Move local fun callee generation to pushArgumentsWithCallReceiver.

Local fun callee generation via resolvedCall.resultingDescriptor not call
This commit is contained in:
Mikhael Bogdanov
2014-03-26 11:21:13 +04:00
parent 94e4c2f0c1
commit c7c1e33655
3 changed files with 67 additions and 77 deletions
@@ -1657,11 +1657,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
}
int index = lookupLocalIndex(descriptor);
if (index >= 0) {
return stackValueForLocal(descriptor, index);
}
if (descriptor instanceof PropertyDescriptor) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
@@ -1708,26 +1703,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
return StackValue.onStack(OBJECT_TYPE);
}
StackValue value = context.lookupInContext(descriptor, StackValue.local(0, OBJECT_TYPE), state, false);
if (value != null) {
if (context.isSpecialStackValue(value)) {
return value;
}
if (value instanceof StackValue.Composed) {
StackValue.Composed composed = (StackValue.Composed) value;
composed.prefix.put(OBJECT_TYPE, v);
value = composed.suffix;
}
if (value instanceof StackValue.FieldForSharedVar) {
StackValue.FieldForSharedVar fieldForSharedVar = (StackValue.FieldForSharedVar) value;
Type sharedType = StackValue.sharedTypeForType(value.type);
v.visitFieldInsn(GETFIELD, fieldForSharedVar.owner.getInternalName(), fieldForSharedVar.name,
sharedType.getDescriptor());
}
return value;
StackValue localOrCaptured = findLocalOrCapturedValue(descriptor);
if (localOrCaptured != null) {
return localOrCaptured;
}
if (descriptor instanceof ValueParameterDescriptor && descriptor.getContainingDeclaration() instanceof ScriptDescriptor) {
@@ -1744,6 +1722,37 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
throw new UnsupportedOperationException("don't know how to generate reference " + descriptor);
}
@Nullable
public StackValue findLocalOrCapturedValue(@NotNull DeclarationDescriptor descriptor) {
int index = lookupLocalIndex(descriptor);
if (index >= 0) {
return stackValueForLocal(descriptor, index);
}
StackValue value = context.lookupInContext(descriptor, StackValue.local(0, OBJECT_TYPE), state, false);
if (value == null) return null;
if (context.isSpecialStackValue(value)) {
return value;
}
if (value instanceof StackValue.Composed) {
StackValue.Composed composed = (StackValue.Composed) value;
composed.prefix.put(OBJECT_TYPE, v);
value = composed.suffix;
}
if (value instanceof StackValue.FieldForSharedVar) {
StackValue.FieldForSharedVar fieldForSharedVar = (StackValue.FieldForSharedVar) value;
Type sharedType = StackValue.sharedTypeForType(value.type);
v.visitFieldInsn(GETFIELD, fieldForSharedVar.owner.getInternalName(), fieldForSharedVar.name,
sharedType.getDescriptor());
}
return value;
}
private StackValue stackValueForLocal(DeclarationDescriptor descriptor, int index) {
if (descriptor instanceof VariableDescriptor) {
Type sharedVarType = typeMapper.getSharedVarType(descriptor);
@@ -2010,25 +2019,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
Callable callable = resolveToCallable(accessibleFunctionDescriptor(fd), superCall);
if (callable instanceof CallableMethod) {
CallableMethod callableMethod = (CallableMethod) callable;
Type calleeType = callableMethod.getGenerateCalleeType();
if (calleeType != null) {
assert !callableMethod.isNeedsThis() : "Method should have a receiver: " + resolvedCall.getResultingDescriptor();
gen(call.getCalleeExpression(), calleeType);
}
}
return invokeFunctionWithCalleeOnStack(call, receiver, resolvedCall, callable);
}
@NotNull
private StackValue invokeFunctionWithCalleeOnStack(
@NotNull Call call,
@NotNull StackValue receiver,
@NotNull ResolvedCall<?> resolvedCall,
@NotNull Callable callable
) {
if (callable instanceof CallableMethod) {
CallableMethod callableMethod = (CallableMethod) callable;
invokeMethodWithArguments(call, callableMethod, resolvedCall, receiver);
@@ -2287,6 +2277,15 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
) {
CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
//generate callee for local function
Type calleeType = callableMethod.getGenerateCalleeType();
if (calleeType != null) {
StackValue value = findLocalOrCapturedValue(descriptor.getOriginal());
assert value != null : "Local fun should be found in locals or in captured params: " + resolvedCall;
value.put(calleeType, v);
}
//generate this (absent for local fun) and receiver
if (!(descriptor instanceof ConstructorDescriptor)) { // otherwise already
receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod);
receiver.put(receiver.type, v);
@@ -2530,12 +2529,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
else {
Call call = CallMaker.makeCall(fakeExpression, NO_RECEIVER, null, fakeExpression, fakeArguments);
Callable callable = codegen.resolveToCallable(codegen.accessibleFunctionDescriptor(referencedFunction), false);
StackValue receiver = generateCallee(codegen, callable);
if (extensionReceiver.exists()) {
receiver = StackValue.composed(receiver, receiverParameterStackValue(signature));
}
result = codegen.invokeFunctionWithCalleeOnStack(call, receiver, fakeResolvedCall, callable);
result = codegen.invokeFunction(call, StackValue.none(), fakeResolvedCall);
}
InstructionAdapter v = codegen.v;
@@ -2543,33 +2537,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
v.areturn(returnType);
}
@NotNull
private StackValue generateCallee(@NotNull ExpressionCodegen codegen, @NotNull Callable callable) {
if (!(callable instanceof CallableMethod) || ((CallableMethod) callable).getGenerateCalleeType() == null) {
return StackValue.none();
}
// If referenced method is a CallableMethod with generateCalleeType != null, this means it's some kind of a closure
// (e.g. a local named function) and a non-trivial callee should be generated before calling invoke()
BindingContext bindingContext = codegen.bindingContext;
ClassDescriptor closureClassOfReferenced = bindingContext.get(CLASS_FOR_FUNCTION, referencedFunction);
MutableClosure closureOfReferenced = bindingContext.get(CLOSURE, closureClassOfReferenced);
assert closureOfReferenced != null :
"Function mapped to CallableMethod with generateCalleeType != null must be a closure: " + referencedFunction;
if (isConst(closureOfReferenced)) {
// 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)
Type asmType = asmTypeForAnonymousClass(bindingContext, referencedFunction);
codegen.v.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor());
return StackValue.onStack(asmType);
}
else {
Type asmCallRefType = asmTypeForAnonymousClass(bindingContext, callableDescriptor);
return codegen.context.lookupInContext(referencedFunction, StackValue.local(0, asmCallRefType), state, false);
}
}
@NotNull
private JetCallExpression constructFakeFunctionCall() {
StringBuilder fakeFunctionCall = new StringBuilder("callableReferenceFakeCall(");
@@ -0,0 +1,18 @@
class T(val value: Int) {
}
fun local() : Int {
fun T.get(s: Int): Int {
return s * this.value
}
var t = T(11)
return t[2]
}
fun box() : String {
if (local() != 22) return "fail1 ${local()} "
return "OK"
}
@@ -2966,6 +2966,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest("compiler/testData/codegen/box/functions/localFunctions/kt4777.kt");
}
@TestMetadata("kt4783.kt")
public void testKt4783() throws Exception {
doTest("compiler/testData/codegen/box/functions/localFunctions/kt4783.kt");
}
@TestMetadata("localFunctionInConstructor.kt")
public void testLocalFunctionInConstructor() throws Exception {
doTest("compiler/testData/codegen/box/functions/localFunctions/localFunctionInConstructor.kt");