From fb370a4538c0892c09957f2c84af45de009433ce Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 4 Dec 2013 21:05:56 +0400 Subject: [PATCH] Make anonymous class inner --- .../jet/codegen/ExpressionCodegen.java | 292 +++++++++--------- 1 file changed, 151 insertions(+), 141 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index dc9a9a31f93..36e104a324c 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -2450,10 +2450,10 @@ public class ExpressionCodegen extends JetVisitor implem @Override public StackValue visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression, StackValue data) { // TODO: properties - final FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression); + FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression); assert functionDescriptor != null : "Callable reference is not resolved to descriptor: " + expression.getText(); - final ResolvedCall resolvedCall = bindingContext.get(RESOLVED_CALL, expression.getCallableReference()); + ResolvedCall resolvedCall = bindingContext.get(RESOLVED_CALL, expression.getCallableReference()); assert resolvedCall != null : "Callable reference is not resolved: " + functionDescriptor + " " + expression.getText(); JetType kFunctionType = bindingContext.get(EXPRESSION_TYPE, expression); @@ -2463,152 +2463,162 @@ public class ExpressionCodegen extends JetVisitor implem Type closureSuperClass = typeMapper.mapType(kFunctionImpl); + CallableReferenceGenerationStrategy strategy = new CallableReferenceGenerationStrategy(state, functionDescriptor, resolvedCall); ClosureCodegen closureCodegen = new ClosureCodegen(state, expression, functionDescriptor, null, closureSuperClass, context, this, - new FunctionGenerationStrategy.CodegenBased(state, functionDescriptor) { - - @NotNull - @Override - public ExpressionCodegen initializeExpressionCodegen( - JvmMethodSignature signature, MethodContext context, MethodVisitor mv, - Type returnType, - MemberCodegen parentCodegen - ) { - FunctionDescriptor referencedFunction = (FunctionDescriptor) resolvedCall.getResultingDescriptor(); - JetType returnJetType = referencedFunction.getReturnType(); - assert returnJetType != null : "Return type can't be null: " + referencedFunction; - - return super.initializeExpressionCodegen(signature, context, - mv, typeMapper.mapReturnType(returnJetType), parentCodegen); - } - - @Override - public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { - /* - Here we need to put the arguments from our locals to the stack and invoke the referenced method. Since invocation - of methods is highly dependent on expressions, we create a fake call expression. Then we create a new instance of - ExpressionCodegen and, in order for it to generate code correctly, we save to its 'tempVariables' field every - argument of our fake expression, pointing it to the corresponding index in our locals. This way generation of - every argument boils down to calling LOAD with the corresponding index - */ - - FunctionDescriptor referencedFunction = (FunctionDescriptor) resolvedCall.getResultingDescriptor(); - - JetCallExpression fakeExpression = constructFakeFunctionCall(referencedFunction); - final List fakeArguments = fakeExpression.getValueArguments(); - - final ReceiverValue receiverValue = computeAndSaveReceiver(signature, codegen); - computeAndSaveArguments(codegen.myFrameMap, fakeArguments, codegen); - - ResolvedCall fakeResolvedCall = new DelegatingResolvedCall(resolvedCall) { - @NotNull - @Override - public ReceiverValue getReceiverArgument() { - return resolvedCall.getExplicitReceiverKind() == RECEIVER_ARGUMENT ? receiverValue : NO_RECEIVER; - } - - @NotNull - @Override - public ReceiverValue getThisObject() { - return resolvedCall.getExplicitReceiverKind() == THIS_OBJECT ? receiverValue : NO_RECEIVER; - } - - @NotNull - @Override - public List getValueArgumentsByIndex() { - List result = new ArrayList(fakeArguments.size()); - for (ValueArgument argument : fakeArguments) { - result.add(new ExpressionValueArgument(argument)); - } - return result; - } - }; - - StackValue result; - Type returnType = codegen.returnType; - if (referencedFunction instanceof ConstructorDescriptor) { - if (returnType.getSort() == Type.ARRAY) { - JetType returnJetType = referencedFunction.getReturnType(); - assert returnJetType != null; - codegen.generateNewArray(fakeExpression, returnJetType); - result = StackValue.onStack(returnType); - } - else { - result = codegen.generateConstructorCall(fakeResolvedCall, StackValue.none(), returnType); - } - } - else { - Call call = CallMaker.makeCall(fakeExpression, NO_RECEIVER, null, fakeExpression, fakeArguments); - result = codegen.invokeFunction(call, StackValue.none(), fakeResolvedCall); - } - - InstructionAdapter v = codegen.v; - result.put(returnType, v); - v.areturn(returnType); - } - - @NotNull - private JetCallExpression constructFakeFunctionCall(@NotNull CallableDescriptor referencedFunction) { - StringBuilder fakeFunctionCall = new StringBuilder("callableReferenceFakeCall("); - for (Iterator iterator = referencedFunction.getValueParameters().iterator(); - iterator.hasNext(); ) { - ValueParameterDescriptor descriptor = iterator.next(); - fakeFunctionCall.append("p").append(descriptor.getIndex()); - if (iterator.hasNext()) { - fakeFunctionCall.append(", "); - } - } - fakeFunctionCall.append(")"); - return (JetCallExpression) JetPsiFactory.createExpression(state.getProject(), fakeFunctionCall.toString()); - } - - private void computeAndSaveArguments( - @NotNull FrameMap frameMap, - @NotNull List fakeArguments, - @NotNull ExpressionCodegen codegen - ) { - for (ValueParameterDescriptor parameter : functionDescriptor.getValueParameters()) { - ValueArgument fakeArgument = fakeArguments.get(parameter.getIndex()); - Type type = typeMapper.mapType(parameter); - int localIndex = frameMap.getIndex(parameter); - codegen.tempVariables.put(fakeArgument.getArgumentExpression(), StackValue.local(localIndex, type)); - } - } - - @NotNull - private ReceiverValue computeAndSaveReceiver( - @NotNull JvmMethodSignature signature, - @NotNull ExpressionCodegen codegen - ) { - CallableDescriptor referencedFunction = resolvedCall.getCandidateDescriptor(); - - ReceiverParameterDescriptor receiverParameter = referencedFunction.getReceiverParameter(); - ReceiverParameterDescriptor expectedThisObject = referencedFunction.getExpectedThisObject(); - assert receiverParameter == null || expectedThisObject == null : - "Extensions in classes can't be referenced via callable reference expressions: " + referencedFunction; - - ReceiverParameterDescriptor receiver = receiverParameter != null ? receiverParameter : expectedThisObject; - - if (receiver == null) { - return NO_RECEIVER; - } - - JetExpression receiverExpression = JetPsiFactory.createExpression(state.getProject(), - "callableReferenceFakeReceiver"); - - Type firstParameterType = signature.getAsmMethod().getArgumentTypes()[0]; - // 0 is this (the closure class), 1 is the method's first parameter - codegen.tempVariables.put(receiverExpression, StackValue.local(1, firstParameterType)); - - return new ExpressionReceiver(receiverExpression, receiver.getType()); - } - }, - getParentCodegen()); + strategy, getParentCodegen()); closureCodegen.gen(); return closureCodegen.putInstanceOnStack(v, this); } + private static class CallableReferenceGenerationStrategy extends FunctionGenerationStrategy.CodegenBased { + private final FunctionDescriptor functionDescriptor; + private final ResolvedCall resolvedCall; + + public CallableReferenceGenerationStrategy( + @NotNull GenerationState state, + @NotNull FunctionDescriptor functionDescriptor, + @NotNull ResolvedCall resolvedCall + ) { + super(state, functionDescriptor); + this.functionDescriptor = functionDescriptor; + this.resolvedCall = resolvedCall; + } + + @NotNull + @Override + public ExpressionCodegen initializeExpressionCodegen( + JvmMethodSignature signature, + MethodContext context, + MethodVisitor mv, + Type returnType, + MemberCodegen parentCodegen + ) { + FunctionDescriptor referencedFunction = (FunctionDescriptor) resolvedCall.getResultingDescriptor(); + JetType returnJetType = referencedFunction.getReturnType(); + assert returnJetType != null : "Return type can't be null: " + referencedFunction; + + return super.initializeExpressionCodegen(signature, context, mv, state.getTypeMapper().mapReturnType(returnJetType), parentCodegen); + } + + @Override + public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { + /* + Here we need to put the arguments from our locals to the stack and invoke the referenced method. Since invocation + of methods is highly dependent on expressions, we create a fake call expression. Then we create a new instance of + ExpressionCodegen and, in order for it to generate code correctly, we save to its 'tempVariables' field every + argument of our fake expression, pointing it to the corresponding index in our locals. This way generation of + every argument boils down to calling LOAD with the corresponding index + */ + + FunctionDescriptor referencedFunction = (FunctionDescriptor) resolvedCall.getResultingDescriptor(); + + JetCallExpression fakeExpression = constructFakeFunctionCall(referencedFunction); + final List fakeArguments = fakeExpression.getValueArguments(); + + final ReceiverValue receiverValue = computeAndSaveReceiver(signature, codegen); + computeAndSaveArguments(codegen.myFrameMap, fakeArguments, codegen); + + ResolvedCall fakeResolvedCall = new DelegatingResolvedCall(resolvedCall) { + @NotNull + @Override + public ReceiverValue getReceiverArgument() { + return resolvedCall.getExplicitReceiverKind() == RECEIVER_ARGUMENT ? receiverValue : NO_RECEIVER; + } + + @NotNull + @Override + public ReceiverValue getThisObject() { + return resolvedCall.getExplicitReceiverKind() == THIS_OBJECT ? receiverValue : NO_RECEIVER; + } + + @NotNull + @Override + public List getValueArgumentsByIndex() { + List result = new ArrayList(fakeArguments.size()); + for (ValueArgument argument : fakeArguments) { + result.add(new ExpressionValueArgument(argument)); + } + return result; + } + }; + + StackValue result; + Type returnType = codegen.returnType; + if (referencedFunction instanceof ConstructorDescriptor) { + if (returnType.getSort() == Type.ARRAY) { + JetType returnJetType = referencedFunction.getReturnType(); + assert returnJetType != null; + codegen.generateNewArray(fakeExpression, returnJetType); + result = StackValue.onStack(returnType); + } + else { + result = codegen.generateConstructorCall(fakeResolvedCall, StackValue.none(), returnType); + } + } + else { + Call call = CallMaker.makeCall(fakeExpression, NO_RECEIVER, null, fakeExpression, fakeArguments); + result = codegen.invokeFunction(call, StackValue.none(), fakeResolvedCall); + } + + InstructionAdapter v = codegen.v; + result.put(returnType, v); + v.areturn(returnType); + } + + @NotNull + private JetCallExpression constructFakeFunctionCall(@NotNull CallableDescriptor referencedFunction) { + StringBuilder fakeFunctionCall = new StringBuilder("callableReferenceFakeCall("); + for (Iterator iterator = referencedFunction.getValueParameters().iterator(); iterator.hasNext(); ) { + ValueParameterDescriptor descriptor = iterator.next(); + fakeFunctionCall.append("p").append(descriptor.getIndex()); + if (iterator.hasNext()) { + fakeFunctionCall.append(", "); + } + } + fakeFunctionCall.append(")"); + return (JetCallExpression) JetPsiFactory.createExpression(state.getProject(), fakeFunctionCall.toString()); + } + + private void computeAndSaveArguments( + @NotNull FrameMap frameMap, + @NotNull List fakeArguments, + @NotNull ExpressionCodegen codegen + ) { + for (ValueParameterDescriptor parameter : functionDescriptor.getValueParameters()) { + ValueArgument fakeArgument = fakeArguments.get(parameter.getIndex()); + Type type = state.getTypeMapper().mapType(parameter); + int localIndex = frameMap.getIndex(parameter); + codegen.tempVariables.put(fakeArgument.getArgumentExpression(), StackValue.local(localIndex, type)); + } + } + + @NotNull + private ReceiverValue computeAndSaveReceiver(@NotNull JvmMethodSignature signature, @NotNull ExpressionCodegen codegen) { + CallableDescriptor referencedFunction = resolvedCall.getCandidateDescriptor(); + + ReceiverParameterDescriptor receiverParameter = referencedFunction.getReceiverParameter(); + ReceiverParameterDescriptor expectedThisObject = referencedFunction.getExpectedThisObject(); + assert receiverParameter == null || expectedThisObject == null : + "Extensions in classes can't be referenced via callable reference expressions: " + referencedFunction; + + ReceiverParameterDescriptor receiver = receiverParameter != null ? receiverParameter : expectedThisObject; + + if (receiver == null) { + return NO_RECEIVER; + } + + JetExpression receiverExpression = JetPsiFactory.createExpression(state.getProject(), "callableReferenceFakeReceiver"); + + Type firstParameterType = signature.getAsmMethod().getArgumentTypes()[0]; + // 0 is this (the closure class), 1 is the method's first parameter + codegen.tempVariables.put(receiverExpression, StackValue.local(1, firstParameterType)); + + return new ExpressionReceiver(receiverExpression, receiver.getType()); + } + } + @Override public StackValue visitDotQualifiedExpression(@NotNull JetDotQualifiedExpression expression, StackValue receiver) { StackValue receiverValue = StackValue.none();