diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index a638ce51f40..760ff762e05 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -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 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 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 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); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index 94e66bde8ed..7187a78d16a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -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()); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java index e3a45b2ac5e..12eaf3b659e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java @@ -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(); diff --git a/compiler/testData/codegen/bytecodeText/constProperty/accessorsForPrivateConstants.kt b/compiler/testData/codegen/bytecodeText/constProperty/accessorsForPrivateConstants.kt new file mode 100644 index 00000000000..806890f1ecc --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/constProperty/accessorsForPrivateConstants.kt @@ -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 \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/constProperty/noAccessorsForPrivateConstants.kt b/compiler/testData/codegen/bytecodeText/constProperty/noAccessorsForPrivateConstants.kt new file mode 100644 index 00000000000..f36069abcd7 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/constProperty/noAccessorsForPrivateConstants.kt @@ -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 \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/inlineProtectedJavaConstantFromOtherPackage.kt b/compiler/testData/codegen/bytecodeText/inlineProtectedJavaConstantFromOtherPackage.kt new file mode 100644 index 00000000000..e81e9b6375a --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/inlineProtectedJavaConstantFromOtherPackage.kt @@ -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 \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/noInlineJavaProtectedConstants.kt b/compiler/testData/codegen/bytecodeText/noInlineJavaProtectedConstants.kt new file mode 100644 index 00000000000..3fd47c381e1 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/noInlineJavaProtectedConstants.kt @@ -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 \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 36db4118ec5..55dc3917cd8 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -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"); diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index 1a9a02f8697..4d00928cacc 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.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), diff --git a/idea/src/org/jetbrains/kotlin/idea/internal/KotlinBytecodeToolWindow.java b/idea/src/org/jetbrains/kotlin/idea/internal/KotlinBytecodeToolWindow.java index 363444335d3..96ae29f0b81 100644 --- a/idea/src/org/jetbrains/kotlin/idea/internal/KotlinBytecodeToolWindow.java +++ b/idea/src/org/jetbrains/kotlin/idea/internal/KotlinBytecodeToolWindow.java @@ -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); } diff --git a/idea/src/org/jetbrains/kotlin/idea/internal/KotlinDecompilerServiceImpl.kt b/idea/src/org/jetbrains/kotlin/idea/internal/KotlinDecompilerServiceImpl.kt index d4122f69d7a..feeb9f6b972 100644 --- a/idea/src/org/jetbrains/kotlin/idea/internal/KotlinDecompilerServiceImpl.kt +++ b/idea/src/org/jetbrains/kotlin/idea/internal/KotlinDecompilerServiceImpl.kt @@ -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 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 ByteArray>() generationState.factory.asList().filter { FileUtilRt.extensionEquals(it.relativePath, "class") }.forEach { diff --git a/idea/tests/org/jetbrains/kotlin/idea/internal/AbstractBytecodeToolWindowTest.kt b/idea/tests/org/jetbrains/kotlin/idea/internal/AbstractBytecodeToolWindowTest.kt index d0dd589ea30..87751947cf1 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/internal/AbstractBytecodeToolWindowTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/internal/AbstractBytecodeToolWindowTest.kt @@ -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"