Skip property accessors for constants
- Inline protected constants from Java at use sites - Do not create accessors for private constants in Kotlin #KT-11734 In Progress
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -50,6 +50,10 @@ import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.codegen.when.SwitchCodegen;
|
||||
import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil;
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys;
|
||||
import org.jetbrains.kotlin.config.LanguageFeature;
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings;
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl;
|
||||
import org.jetbrains.kotlin.coroutines.CoroutineUtilKt;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||
@@ -2603,9 +2607,16 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
boolean skipPropertyAccessors;
|
||||
|
||||
PropertyDescriptor originalPropertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor);
|
||||
LanguageVersionSettings languageVersionSettings = state.getConfiguration().get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS);
|
||||
if (languageVersionSettings == null) {
|
||||
languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT;
|
||||
}
|
||||
|
||||
if (fieldAccessorKind != FieldAccessorKind.NORMAL) {
|
||||
int flags = AsmUtil.getVisibilityForBackingField(propertyDescriptor, isDelegatedProperty);
|
||||
skipPropertyAccessors = (flags & ACC_PRIVATE) == 0 || skipAccessorsForPrivateFieldInOuterClass;
|
||||
boolean isInlinedConst = propertyDescriptor.isConst() && languageVersionSettings.supportsFeature(LanguageFeature.InlineConstVals);
|
||||
skipPropertyAccessors = isInlinedConst || (flags & ACC_PRIVATE) == 0 || skipAccessorsForPrivateFieldInOuterClass;
|
||||
|
||||
if (!skipPropertyAccessors) {
|
||||
//noinspection ConstantConditions
|
||||
propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(
|
||||
@@ -2624,7 +2635,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
if (!skipPropertyAccessors) {
|
||||
if (!couldUseDirectAccessToProperty(propertyDescriptor, true, isDelegatedProperty, context)) {
|
||||
if (!couldUseDirectAccessToProperty(propertyDescriptor, true, isDelegatedProperty, context, languageVersionSettings)) {
|
||||
propertyDescriptor = context.getAccessorForSuperCallIfNeeded(propertyDescriptor, superCallTarget);
|
||||
|
||||
propertyDescriptor = context.accessibleDescriptor(propertyDescriptor, superCallTarget);
|
||||
@@ -2638,7 +2649,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
if (propertyDescriptor.isVar()) {
|
||||
PropertySetterDescriptor setter = propertyDescriptor.getSetter();
|
||||
if (setter != null &&
|
||||
!couldUseDirectAccessToProperty(propertyDescriptor, false, isDelegatedProperty, context) &&
|
||||
!couldUseDirectAccessToProperty(propertyDescriptor, false, isDelegatedProperty, context, languageVersionSettings) &&
|
||||
!isConstOrHasJvmFieldAnnotation(propertyDescriptor)) {
|
||||
callableSetter = typeMapper.mapToCallableMethod(setter, isSuper);
|
||||
}
|
||||
|
||||
@@ -37,6 +37,9 @@ import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
|
||||
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys;
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings;
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
@@ -646,7 +649,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
private Type genPropertyOnStack(InstructionAdapter iv, MethodContext context, @NotNull PropertyDescriptor propertyDescriptor, int index) {
|
||||
iv.load(index, classAsmType);
|
||||
if (couldUseDirectAccessToProperty(propertyDescriptor, /* forGetter = */ true, /* isDelegated = */ false, context)) {
|
||||
LanguageVersionSettings settings = state.getConfiguration().get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS);
|
||||
if (settings == null) {
|
||||
settings = LanguageVersionSettingsImpl.DEFAULT;
|
||||
}
|
||||
if (couldUseDirectAccessToProperty(propertyDescriptor, /* forGetter = */ true,
|
||||
/* isDelegated = */ false, context, settings)) {
|
||||
Type type = typeMapper.mapType(propertyDescriptor.getType());
|
||||
String fieldName = ((FieldOwnerContext) context.getParentContext()).getFieldName(propertyDescriptor, false);
|
||||
iv.getfield(classAsmType.getInternalName(), fieldName, type.getDescriptor());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,6 +30,8 @@ import org.jetbrains.kotlin.codegen.context.MethodContext;
|
||||
import org.jetbrains.kotlin.codegen.context.RootContext;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.config.LanguageFeature;
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor;
|
||||
@@ -182,8 +184,11 @@ public class JvmCodegenUtil {
|
||||
@NotNull PropertyDescriptor property,
|
||||
boolean forGetter,
|
||||
boolean isDelegated,
|
||||
@NotNull MethodContext contextBeforeInline
|
||||
@NotNull MethodContext contextBeforeInline,
|
||||
@NotNull LanguageVersionSettings languageVersionSettings
|
||||
) {
|
||||
if (languageVersionSettings.supportsFeature(LanguageFeature.InlineConstVals) && property.isConst()) return true;
|
||||
|
||||
if (KotlinTypeMapper.isAccessor(property)) return false;
|
||||
|
||||
CodegenContext context = contextBeforeInline.getFirstCrossInlineOrNonInlineContext();
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// LANGUAGE_VERSION: 1.0
|
||||
// FILE: Foo.kt
|
||||
|
||||
private const val OUTER_PRIVATE = 20
|
||||
|
||||
class Foo {
|
||||
companion object {
|
||||
private const val LOCAL_PRIVATE = 20
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
LOCAL_PRIVATE
|
||||
OUTER_PRIVATE
|
||||
}
|
||||
}
|
||||
|
||||
// 2 INVOKESTATIC
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// FILE: Foo.kt
|
||||
|
||||
private const val OUTER_PRIVATE = 20
|
||||
|
||||
class Foo {
|
||||
companion object {
|
||||
private const val LOCAL_PRIVATE = 20
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
LOCAL_PRIVATE
|
||||
OUTER_PRIVATE
|
||||
}
|
||||
}
|
||||
|
||||
// 0 INVOKESTATIC
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// FILE: first/Foo.java
|
||||
|
||||
package first;
|
||||
|
||||
public class Foo {
|
||||
protected static final int FOO = 42;
|
||||
}
|
||||
|
||||
// FILE: bar.kt
|
||||
|
||||
package second
|
||||
|
||||
import first.Foo
|
||||
|
||||
class Bar : Foo() {
|
||||
fun bar() = FOO
|
||||
}
|
||||
|
||||
// @second/BarKt.class
|
||||
// 0 INVOKESTATIC
|
||||
// 0 GETSTATIC
|
||||
// 1 BIPUSH 42
|
||||
@@ -0,0 +1,23 @@
|
||||
// LANGUAGE_VERSION: 1.0
|
||||
// FILE: first/Foo.java
|
||||
|
||||
package first;
|
||||
|
||||
public class Foo {
|
||||
protected static final int FOO = 42;
|
||||
}
|
||||
|
||||
// FILE: bar.kt
|
||||
|
||||
package second
|
||||
|
||||
import first.Foo
|
||||
|
||||
class Bar : Foo() {
|
||||
fun bar() = FOO
|
||||
}
|
||||
|
||||
// @second/BarKt.class
|
||||
// 1 INVOKESTATIC
|
||||
// 0 GETSTATIC
|
||||
// 1 BIPUSH 42
|
||||
@@ -138,6 +138,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inlineProtectedJavaConstantFromOtherPackage.kt")
|
||||
public void testInlineProtectedJavaConstantFromOtherPackage() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineProtectedJavaConstantFromOtherPackage.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("intConstantNotNull.kt")
|
||||
public void testIntConstantNotNull() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/intConstantNotNull.kt");
|
||||
@@ -270,6 +276,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noInlineJavaProtectedConstants.kt")
|
||||
public void testNoInlineJavaProtectedConstants() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/noInlineJavaProtectedConstants.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noNumberCheckCast.kt")
|
||||
public void testNoNumberCheckCast() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/noNumberCheckCast.kt");
|
||||
@@ -712,10 +724,22 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class ConstProperty extends AbstractBytecodeTextTest {
|
||||
@TestMetadata("accessorsForPrivateConstants.kt")
|
||||
public void testAccessorsForPrivateConstants() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/constProperty/accessorsForPrivateConstants.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInConstProperty() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/constProperty"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("noAccessorsForPrivateConstants.kt")
|
||||
public void testNoAccessorsForPrivateConstants() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/constProperty/noAccessorsForPrivateConstants.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noInline.kt")
|
||||
public void testNoInline() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/constProperty/noInline.kt");
|
||||
|
||||
@@ -34,6 +34,7 @@ enum class LanguageFeature(val sinceVersion: LanguageVersion?) {
|
||||
DslMarkersSupport(KOTLIN_1_1),
|
||||
UnderscoresInNumericLiterals(KOTLIN_1_1),
|
||||
DivisionByZeroInConstantExpressions(KOTLIN_1_1),
|
||||
InlineConstVals(KOTLIN_1_1),
|
||||
|
||||
// Experimental features
|
||||
MultiPlatformProjects(null),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -41,14 +41,12 @@ import org.jetbrains.kotlin.codegen.ClassBuilderFactories;
|
||||
import org.jetbrains.kotlin.codegen.CompilationErrorHandler;
|
||||
import org.jetbrains.kotlin.codegen.KotlinCodegenFacade;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys;
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration;
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys;
|
||||
import org.jetbrains.kotlin.config.JvmTarget;
|
||||
import org.jetbrains.kotlin.config.*;
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic;
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages;
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils;
|
||||
import org.jetbrains.kotlin.idea.debugger.DebuggerUtils;
|
||||
import org.jetbrains.kotlin.idea.project.PlatformKt;
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade;
|
||||
import org.jetbrains.kotlin.idea.util.InfinitePeriodicalTask;
|
||||
import org.jetbrains.kotlin.idea.util.LongRunningReadTask;
|
||||
@@ -136,6 +134,9 @@ public class KotlinBytecodeToolWindow extends JPanel implements Disposable {
|
||||
configuration.put(JVMConfigurationKeys.IR, true);
|
||||
}
|
||||
|
||||
LanguageVersionSettings languageVersionSettings = PlatformKt.getLanguageVersionSettings(ktFile);
|
||||
configuration.put(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, languageVersionSettings);
|
||||
|
||||
return getBytecodeForFile(ktFile, configuration);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,10 @@ import org.jetbrains.java.decompiler.main.decompiler.BaseDecompiler
|
||||
import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider
|
||||
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences
|
||||
import org.jetbrains.java.decompiler.main.extern.IResultSaver
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.idea.actions.canBeDecompiledToJava
|
||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import java.io.File
|
||||
import java.util.jar.Manifest
|
||||
@@ -72,7 +74,10 @@ class KotlinDecompilerServiceImpl : KotlinDecompilerService {
|
||||
}
|
||||
|
||||
fun bytecodeMapForSourceFile(file: KtFile): Map<File, () -> ByteArray> {
|
||||
val generationState = KotlinBytecodeToolWindow.compileSingleFile(file, CompilerConfiguration.EMPTY)
|
||||
val configuration = CompilerConfiguration().apply {
|
||||
put(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, file.languageVersionSettings)
|
||||
}
|
||||
val generationState = KotlinBytecodeToolWindow.compileSingleFile(file, configuration)
|
||||
|
||||
val bytecodeMap = hashMapOf<File, () -> ByteArray>()
|
||||
generationState.factory.asList().filter { FileUtilRt.extensionEquals(it.relativePath, "class") }.forEach {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.internal
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
@@ -44,6 +45,9 @@ abstract class AbstractBytecodeToolWindowTest: KotlinLightCodeInsightFixtureTest
|
||||
if (InTextDirectivesUtils.getPrefixedBoolean(mainFileText, "// INLINE:") == false) {
|
||||
configuration.put(CommonConfigurationKeys.DISABLE_INLINE, true)
|
||||
}
|
||||
|
||||
configuration.put(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, file.languageVersionSettings)
|
||||
|
||||
val bytecodes = KotlinBytecodeToolWindow.getBytecodeForFile(file, configuration)
|
||||
assert(bytecodes.contains("// ================")) {
|
||||
"The header \"// ================\" is missing.\n This means that there is an exception failed during compilation:\n$bytecodes"
|
||||
|
||||
Reference in New Issue
Block a user