Optimization for const closures: access it via GETSTATIC

This commit is contained in:
Mikhael Bogdanov
2014-03-27 14:03:12 +04:00
parent c7c1e33655
commit 7dc662f613
5 changed files with 55 additions and 6 deletions
@@ -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);
@@ -333,7 +333,7 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
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<T extends DeclarationDescriptor> {
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<T extends DeclarationDescriptor> {
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;
}
}
@@ -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);
@@ -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\$
@@ -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");