Call generator refactoring

This commit is contained in:
Mikhael Bogdanov
2014-02-25 13:54:37 +04:00
parent e7603d2e62
commit ead2f84a29
5 changed files with 154 additions and 161 deletions
@@ -0,0 +1,93 @@
/*
* Copyright 2010-2013 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.Type;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
public interface CallGenerator {
public class DefaultCallGenerator implements CallGenerator {
private ExpressionCodegen codegen;
public DefaultCallGenerator(ExpressionCodegen codegen) {
this.codegen = codegen;
}
@Override
public void genCall(
CallableMethod callableMethod,
ResolvedCall<?> resolvedCall, int mask,
ExpressionCodegen codegen
) {
if (mask == 0) {
callableMethod.invokeWithNotNullAssertion(codegen.v, codegen.getState(), resolvedCall);
}
else {
callableMethod.invokeDefaultWithNotNullAssertion(codegen.v, codegen.getState(), resolvedCall, mask);
}
}
@Override
public void afterParameterPut(Type type, StackValue stackValue, ValueParameterDescriptor valueParameterDescriptor) {
}
@Override
public void putHiddenParams() {
}
@Override
public void genValueAndPut(
@NotNull ValueParameterDescriptor valueParameterDescriptor,
@NotNull JetExpression argumentExpression,
@NotNull Type parameterType
) {
StackValue value = codegen.gen(argumentExpression);
value.put(parameterType, codegen.v);
}
@Override
public void putCapturedValueOnStack(
@NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex
) {
stackValue.put(stackValue.type, codegen.v);
}
};
void genCall(CallableMethod callableMethod, ResolvedCall<?> resolvedCall, int mask, ExpressionCodegen codegen);
void afterParameterPut(Type type, StackValue stackValue, ValueParameterDescriptor valueParameterDescriptor);
void genValueAndPut(
@NotNull ValueParameterDescriptor valueParameterDescriptor,
@NotNull JetExpression argumentExpression,
@NotNull Type parameterType
);
void putCapturedValueOnStack(
@NotNull StackValue stackValue,
@NotNull Type valueType, int paramIndex
);
void putHiddenParams();
}
@@ -25,7 +25,6 @@ import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.asm4.commons.Method;
import org.jetbrains.jet.codegen.inline.CallGenerator;
import org.jetbrains.jet.codegen.binding.CalculatedClosure;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.context.LocalLookup;
@@ -154,7 +153,7 @@ public class ClosureCodegen extends ParentCodegenAwareImpl {
v.anew(asmType);
v.dup();
codegen.pushClosureOnStack(closure, false, CallGenerator.NOT_INLINE);
codegen.pushClosureOnStack(closure, false, codegen.defaulCallGenerator);
v.invokespecial(asmType.getInternalName(), "<init>", constructor.getDescriptor());
}
return StackValue.onStack(asmType);
@@ -33,7 +33,6 @@ import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.asm4.commons.Method;
import org.jetbrains.jet.codegen.inline.InlineCodegen;
import org.jetbrains.jet.codegen.inline.CallGenerator;
import org.jetbrains.jet.codegen.inline.NameGenerator;
import org.jetbrains.jet.codegen.binding.CalculatedClosure;
import org.jetbrains.jet.codegen.binding.CodegenBinding;
@@ -84,7 +83,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
private int myLastLineNumber = -1;
InstructionAdapter v;
public final InstructionAdapter v;
final MethodVisitor methodVisitor;
final FrameMap myFrameMap;
final JetTypeMapper typeMapper;
@@ -109,6 +108,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
@NotNull
private final TailRecursionCodegen tailRecursionCodegen;
public final CallGenerator defaulCallGenerator;
public CalculatedClosure generateObjectLiteral(GenerationState state, JetObjectLiteralExpression literal) {
JetObjectDeclaration objectDeclaration = literal.getObjectDeclaration();
@@ -178,6 +179,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
this.context = context;
this.statementVisitor = new CodegenStatementVisitor(this);
this.tailRecursionCodegen = new TailRecursionCodegen(context, this, this.v, state);
this.defaulCallGenerator = new CallGenerator.DefaultCallGenerator(this);
}
public GenerationState getState() {
@@ -1334,7 +1336,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
v.anew(type);
v.dup();
pushClosureOnStack(closure, false, CallGenerator.NOT_INLINE);
pushClosureOnStack(closure, false, defaulCallGenerator);
JetDelegatorToSuperCall superCall = closure.getSuperCall();
if (superCall != null) {
@@ -1355,7 +1357,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
return StackValue.onStack(type);
}
public void pushClosureOnStack(CalculatedClosure closure, boolean ignoreThisAndReceiver, CallGenerator callGenerator) {
public void pushClosureOnStack(@Nullable CalculatedClosure closure, boolean ignoreThisAndReceiver, @NotNull CallGenerator callGenerator) {
if (closure != null) {
int paramIndex = 0;
if (!ignoreThisAndReceiver) {
@@ -1364,20 +1366,14 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
StackValue thisOrOuter = generateThisOrOuter(captureThis, false);
assert !isPrimitive(thisOrOuter.type) : "This or outer should be non primitive: " + thisOrOuter.type;
if (callGenerator.shouldPutValue(thisOrOuter.type, thisOrOuter, null)) {
thisOrOuter.put(thisOrOuter.type, v);
}
callGenerator.putCapturedInLocal(thisOrOuter.type, thisOrOuter, null, paramIndex++);
callGenerator.putCapturedValueOnStack(thisOrOuter, thisOrOuter.type, paramIndex++);
}
JetType captureReceiver = closure.getCaptureReceiverType();
if (captureReceiver != null) {
Type asmType = typeMapper.mapType(captureReceiver);
StackValue.Local capturedReceiver = StackValue.local(context.isStatic() ? 0 : 1, asmType);
if (callGenerator.shouldPutValue(asmType, capturedReceiver, null)) {
capturedReceiver.put(asmType, v);
}
callGenerator.putCapturedInLocal(asmType, capturedReceiver, null, paramIndex++);
callGenerator.putCapturedValueOnStack(capturedReceiver, capturedReceiver.type, paramIndex++);
}
}
@@ -1387,10 +1383,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
sharedVarType = typeMapper.mapType((VariableDescriptor) entry.getKey());
}
StackValue capturedVar = entry.getValue().getOuterValue(this);
if (callGenerator.shouldPutValue(sharedVarType, capturedVar, null)) {
capturedVar.put(sharedVarType, v);
}
callGenerator.putCapturedInLocal(sharedVarType, capturedVar, null, paramIndex++);
callGenerator.putCapturedValueOnStack(capturedVar, sharedVarType, paramIndex++);
}
}
}
@@ -2123,7 +2116,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
descriptor instanceof SimpleFunctionDescriptor &&
((SimpleFunctionDescriptor) descriptor).getInlineStrategy().isInline();
CallGenerator callGenerator = !isInline ? CallGenerator.NOT_INLINE :
CallGenerator callGenerator = !isInline ? defaulCallGenerator :
new InlineCodegen(this, state, (SimpleFunctionDescriptor) unwrapFakeOverride(
(CallableMemberDescriptor) descriptor.getOriginal()), call);
@@ -2136,7 +2129,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
receiver.put(receiver.type, v);
}
assert callGenerator == CallGenerator.NOT_INLINE || !hasDefaultArguments(resolvedCall) && !tailRecursionCodegen.isTailRecursion(resolvedCall) :
assert callGenerator == defaulCallGenerator || !hasDefaultArguments(resolvedCall) && !tailRecursionCodegen.isTailRecursion(resolvedCall) :
"Method with defaults or tail recursive couldn't be inlined " + descriptor;
pushArgumentsAndInvoke(resolvedCall, callableMethod, callGenerator);
@@ -2152,18 +2145,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
return;
}
if (mask == 0) {
if (callGenerator != CallGenerator.NOT_INLINE) {
callGenerator.inlineCall(callable, getParentCodegen().getBuilder().getVisitor());
} else {
callable.invokeWithNotNullAssertion(v, state, resolvedCall);
}
}
else {
callable.invokeDefaultWithNotNullAssertion(v, state, resolvedCall, mask);
}
callGenerator.leaveTemps();
callGenerator.genCall(callable, resolvedCall, mask, this);
}
private void genThisAndReceiverFromResolvedCall(
@@ -2339,7 +2321,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
throw new IllegalStateException();
}
callGenerator = callGenerator != null ? callGenerator : CallGenerator.NOT_INLINE;
callGenerator = callGenerator != null ? callGenerator : defaulCallGenerator;
int mask = 0;
for (Iterator<ValueParameterDescriptor> iterator = valueParameters.iterator(); iterator.hasNext(); ) {
@@ -2356,25 +2338,16 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
JetExpression argumentExpression = valueArgument.getArgumentExpression();
assert argumentExpression != null : valueArgument.asElement().getText();
//TODO deparenthisise
if (callGenerator.isInliningClosure(argumentExpression, valueParameter)) {
callGenerator.rememberClosure((JetFunctionLiteralExpression) argumentExpression, parameterType);
} else {
StackValue value = gen(argumentExpression);
if (callGenerator.shouldPutValue(parameterType, value, valueParameter)) {
value.put(parameterType, v);
}
callGenerator.putInLocal(parameterType, value, valueParameter);
}
callGenerator.genValueAndPut(valueParameter, argumentExpression, parameterType);
} else if (resolvedValueArgument instanceof DefaultValueArgument) {
pushDefaultValueOnStack(parameterType, v);
mask |= (1 << valueParameter.getIndex());
callGenerator.putInLocal(parameterType, null, valueParameter);
callGenerator.afterParameterPut(parameterType, null, valueParameter);
}
else if (resolvedValueArgument instanceof VarargValueArgument) {
VarargValueArgument valueArgument = (VarargValueArgument) resolvedValueArgument;
genVarargs(valueParameter, valueArgument);
callGenerator.putInLocal(parameterType, null, valueParameter);
callGenerator.afterParameterPut(parameterType, null, valueParameter);
}
else {
throw new UnsupportedOperationException();
@@ -3319,7 +3292,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
//Resolved call to local class constructor doesn't have resolvedCall.getThisObject() and resolvedCall.getReceiverArgument()
//so we need generate closure on stack
//See StackValue.receiver for more info
pushClosureOnStack(closure, resolvedCall.getThisObject().exists() || resolvedCall.getReceiverArgument().exists(), CallGenerator.NOT_INLINE);
pushClosureOnStack(closure, resolvedCall.getThisObject().exists() || resolvedCall.getReceiverArgument().exists(), defaulCallGenerator);
ConstructorDescriptor originalOfSamAdapter = (ConstructorDescriptor) SamCodegenUtil.getOriginalIfSamAdapter(constructorDescriptor);
CallableMethod method = typeMapper.mapToCallableMethod(originalOfSamAdapter == null ? constructorDescriptor : originalOfSamAdapter);
@@ -3874,11 +3847,6 @@ The "returned" value of try expression with no finally is either the last expres
throw new IllegalStateException("Script codegen should be present in codegen tree");
}
@NotNull
public InstructionAdapter getInstructionAdapter() {
return v;
}
@NotNull
public FrameMap getFrameMap() {
return myFrameMap;
@@ -1,93 +0,0 @@
/*
* Copyright 2010-2013 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.codegen.inline;
import org.jetbrains.asm4.ClassVisitor;
import org.jetbrains.asm4.Type;
import org.jetbrains.jet.codegen.CallableMethod;
import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
public interface CallGenerator {
CallGenerator NOT_INLINE = new CallGenerator() {
@Override
public void inlineCall(
CallableMethod callableMethod, ClassVisitor visitor
) {
throw new UnsupportedOperationException();
}
@Override
public void putInLocal(Type type, StackValue stackValue, ValueParameterDescriptor valueParameterDescriptor) {
}
@Override
public void putCapturedInLocal(
Type type, StackValue stackValue, ValueParameterDescriptor valueParameterDescriptor, int index
) {
}
@Override
public void leaveTemps() {
}
@Override
public boolean isInliningClosure(JetExpression expression, ValueParameterDescriptor valueParameterDescriptora) {
return false;
}
@Override
public void rememberClosure(JetFunctionLiteralExpression expression, Type type) {
throw new UnsupportedOperationException();
}
@Override
public void putHiddenParams() {
}
@Override
public boolean shouldPutValue(
Type type, StackValue stackValue,
ValueParameterDescriptor descriptor
) {
return true;
}
};
void inlineCall(CallableMethod callableMethod, ClassVisitor visitor);
void putInLocal(Type type, StackValue stackValue, ValueParameterDescriptor valueParameterDescriptor);
void putCapturedInLocal(Type type, StackValue stackValue, ValueParameterDescriptor valueParameterDescriptor, int index);
boolean shouldPutValue(Type type, StackValue stackValue, ValueParameterDescriptor descriptor);
void putHiddenParams();
void leaveTemps();
boolean isInliningClosure(JetExpression expression, ValueParameterDescriptor valueParameterDescriptora);
void rememberClosure(JetFunctionLiteralExpression expression, Type type);
}
@@ -20,7 +20,6 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.ClassVisitor;
import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Opcodes;
import org.jetbrains.asm4.Type;
@@ -43,6 +42,7 @@ import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
import org.jetbrains.jet.lang.types.lang.InlineStrategy;
import org.jetbrains.jet.lang.types.lang.InlineUtil;
@@ -119,7 +119,9 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
@Override
public void inlineCall(CallableMethod callableMethod, ClassVisitor visitor) {
public void genCall(CallableMethod callableMethod, ResolvedCall<?> resolvedCall, int mask, ExpressionCodegen codegen) {
assert mask == 0 : "Default method invocation couldn't be inlined " + resolvedCall;
MethodNode node = null;
try {
@@ -131,13 +133,15 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
}
catch (Exception e) {
String text = getNodeText(node);
PsiElement element = BindingContextUtils.descriptorToDeclaration(bindingContext, codegen.getContext().getContextDescriptor());
PsiElement element = BindingContextUtils.descriptorToDeclaration(bindingContext, this.codegen.getContext().getContextDescriptor());
throw new CompilationException("Couldn't inline method call '" +
functionDescriptor.getName() +
"' into \n" + (element != null ? element.getText() : "null psi element " + codegen.getContext().getContextDescriptor()) +
"' into \n" + (element != null ? element.getText() : "null psi element " + this.codegen.getContext().getContextDescriptor()) +
"\ncause: " +
text, e, call.getCallElement());
}
leaveTemps();
}
@NotNull
@@ -203,7 +207,7 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
VarRemapper.ParamRemapper remapper = new VarRemapper.ParamRemapper(parameters, initialFrameSize);
inliner.doTransformAndMerge(codegen.getInstructionAdapter(), remapper);
inliner.doTransformAndMerge(codegen.v, remapper);
}
@@ -242,13 +246,12 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
@Override
public void putInLocal(@NotNull Type type, @Nullable StackValue stackValue, ValueParameterDescriptor valueParameterDescriptor) {
public void afterParameterPut(@NotNull Type type, @Nullable StackValue stackValue, ValueParameterDescriptor valueParameterDescriptor) {
putCapturedInLocal(type, stackValue, valueParameterDescriptor, -1);
}
@Override
public void putCapturedInLocal(
@NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor valueParameterDescriptor, int index
@NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor valueParameterDescriptor, int capturedParamIndex
) {
if (!asFunctionInline && Type.VOID_TYPE != type) {
//TODO remap only inlinable closure => otherwise we could get a lot of problem
@@ -257,8 +260,8 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
ParameterInfo info = new ParameterInfo(type, false, couldBeRemapped ? -1 : codegen.getFrameMap().enterTemp(type), remappedIndex);
if (index >= 0 && couldBeRemapped) {
CapturedParamInfo capturedParamInfo = activeLambda.getCapturedVars().get(index);
if (capturedParamIndex >= 0 && couldBeRemapped) {
CapturedParamInfo capturedParamInfo = activeLambda.getCapturedVars().get(capturedParamIndex);
capturedParamInfo.setRemapValue(remappedIndex != null ? remappedIndex : StackValue.local(info.getIndex(), info.getType()));
}
@@ -266,9 +269,7 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
}
}
/*descriptor is null for captured vars*/
@Override
public boolean shouldPutValue(
@NotNull Type type,
@Nullable StackValue stackValue,
@@ -324,7 +325,7 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
if (!info.isSkippedOrRemapped()) {
int index = info.getIndex();
Type type = info.type;
StackValue.local(index, type).store(type, codegen.getInstructionAdapter());
StackValue.local(index, type).store(type, codegen.v);
}
}
@@ -353,7 +354,6 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
}
}
@Override
public void leaveTemps() {
FrameMap frameMap = codegen.getFrameMap();
for (ListIterator<? extends ParameterInfo> iterator = actualParameters.listIterator(actualParameters.size()); iterator.hasPrevious(); ) {
@@ -364,14 +364,12 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
}
}
@Override
public boolean isInliningClosure(JetExpression expression, ValueParameterDescriptor valueParameterDescriptora) {
public static boolean isInliningClosure(JetExpression expression, ValueParameterDescriptor valueParameterDescriptora) {
//TODO deparenthisise
return expression instanceof JetFunctionLiteralExpression &&
!InlineUtil.hasNoinlineAnnotation(valueParameterDescriptora);
}
@Override
public void rememberClosure(JetFunctionLiteralExpression expression, Type type) {
ParameterInfo closureInfo = new ParameterInfo(type, true, -1, -1);
int index = recordParamInfo(closureInfo, true);
@@ -450,4 +448,32 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
private static String descriptorName(DeclarationDescriptor descriptor) {
return DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor);
}
@Override
public void genValueAndPut(
@NotNull ValueParameterDescriptor valueParameterDescriptor,
@NotNull JetExpression argumentExpression,
@NotNull Type parameterType
) {
//TODO deparenthisise
if (isInliningClosure(argumentExpression, valueParameterDescriptor)) {
rememberClosure((JetFunctionLiteralExpression) argumentExpression, parameterType);
} else {
StackValue value = codegen.gen(argumentExpression);
if (shouldPutValue(parameterType, value, valueParameterDescriptor)) {
value.put(parameterType, codegen.v);
}
afterParameterPut(parameterType, value, valueParameterDescriptor);
}
}
@Override
public void putCapturedValueOnStack(
@NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex
) {
if (shouldPutValue(stackValue.type, stackValue, null)) {
stackValue.put(stackValue.type, codegen.v);
}
putCapturedInLocal(stackValue.type, stackValue, null, paramIndex);
}
}