diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java index 338b5cf841f..5b40e9823aa 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java @@ -1195,7 +1195,7 @@ public abstract class StackValue { public abstract static class StackValueWithSimpleReceiver extends StackValue { - protected final boolean isStatic; + public final boolean isStatic; public StackValueWithSimpleReceiver(@NotNull Type type, boolean isStatic) { super(type); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java index f041831d35f..54536b2d5b6 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java @@ -333,7 +333,7 @@ public abstract class CodegenContext { break; } else { - return result == null ? innerValue : StackValue.composed(result, innerValue); + return result == null ? innerValue : composedOrStatic(result, innerValue); } } } @@ -349,7 +349,7 @@ public abstract class CodegenContext { resultValue = parentContext != null ? parentContext.lookupInContext(d, result, state, ignoreNoOuter) : null; } - if (myOuter != null && resultValue != null) { + if (myOuter != null && resultValue != null && !isStaticField(resultValue)) { closure.setCaptureThis(); } return resultValue; @@ -464,4 +464,16 @@ public abstract class CodegenContext { public CodegenContext findChildContext(@NotNull DeclarationDescriptor child) { return childContexts == null ? null : childContexts.get(child); } + + @NotNull + private static StackValue composedOrStatic(@NotNull StackValue prefix, @NotNull StackValue suffix) { + if (isStaticField(suffix)) { + return suffix; + } + return StackValue.composed(prefix, suffix); + } + + private static boolean isStaticField(@NotNull StackValue value) { + return value instanceof StackValue.Field && ((StackValue.Field) value).isStatic; + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/context/LocalLookup.java b/compiler/backend/src/org/jetbrains/jet/codegen/context/LocalLookup.java index e6d3d74ce09..65e9ec3920e 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/context/LocalLookup.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/context/LocalLookup.java @@ -17,16 +17,18 @@ package org.jetbrains.jet.codegen.context; import org.jetbrains.asm4.Type; +import org.jetbrains.jet.codegen.CodegenUtil; import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.codegen.binding.MutableClosure; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.types.JetType; import static org.jetbrains.jet.codegen.AsmUtil.CAPTURED_RECEIVER_FIELD; -import static org.jetbrains.jet.codegen.binding.CodegenBinding.asmTypeForAnonymousClass; -import static org.jetbrains.jet.codegen.binding.CodegenBinding.isLocalNamedFun; +import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; public interface LocalLookup { boolean lookupLocal(DeclarationDescriptor descriptor); @@ -86,7 +88,15 @@ public interface LocalLookup { boolean idx = localLookup != null && localLookup.lookupLocal(vd); if (!idx) return null; - Type localType = asmTypeForAnonymousClass(state.getBindingContext(), vd); + BindingContext bindingContext = state.getBindingContext(); + Type localType = asmTypeForAnonymousClass(bindingContext, vd); + + MutableClosure localFunClosure = bindingContext.get(CLOSURE, bindingContext.get(CLASS_FOR_FUNCTION, vd)); + if (localFunClosure != null && CodegenUtil.isConst(localFunClosure)) { + // This is an optimization: we can obtain an instance of a const closure simply by GETSTATIC ...$instance + // (instead of passing this instance to the constructor and storing as a field) + return StackValue.field(localType, localType, JvmAbi.INSTANCE_FIELD, true); + } String fieldName = "$" + vd.getName(); StackValue innerValue = StackValue.field(localType, classType, fieldName, false); diff --git a/compiler/testData/codegen/bytecodeText/constClosureOptimization.kt b/compiler/testData/codegen/bytecodeText/constClosureOptimization.kt new file mode 100644 index 00000000000..424884ab803 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/constClosureOptimization.kt @@ -0,0 +1,22 @@ +fun test() { + + fun local(){ + { + //static instance access + local() + }() + } + + //static instance access + { + //static instance access + local() + }() + + //static instance access + (::local)() +} + +// 3 GETSTATIC _DefaultPackage\$test\$1\.instance\$ +// 1 GETSTATIC _DefaultPackage\$test\$2\.instance\$ +// 1 GETSTATIC _DefaultPackage\$test\$3\.instance\$ \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/BytecodeTextTestGenerated.java index 5233dccb39d..224ee62fbb7 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/BytecodeTextTestGenerated.java @@ -57,6 +57,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { doTest("compiler/testData/codegen/bytecodeText/componentEvaluatesOnlyOnce.kt"); } + @TestMetadata("constClosureOptimization.kt") + public void testConstClosureOptimization() throws Exception { + doTest("compiler/testData/codegen/bytecodeText/constClosureOptimization.kt"); + } + @TestMetadata("intConstantNotNull.kt") public void testIntConstantNotNull() throws Exception { doTest("compiler/testData/codegen/bytecodeText/intConstantNotNull.kt");