diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CallGenerator.java b/compiler/backend/src/org/jetbrains/jet/codegen/CallGenerator.java new file mode 100644 index 00000000000..dd49a5f15e6 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CallGenerator.java @@ -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(); +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 17fe59b164b..744b273d320 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -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(), "", constructor.getDescriptor()); } return StackValue.onStack(asmType); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index e6717cfae09..a44c5212b2c 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -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 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 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 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 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 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 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 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 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 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 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 implem throw new IllegalStateException(); } - callGenerator = callGenerator != null ? callGenerator : CallGenerator.NOT_INLINE; + callGenerator = callGenerator != null ? callGenerator : defaulCallGenerator; int mask = 0; for (Iterator iterator = valueParameters.iterator(); iterator.hasNext(); ) { @@ -2356,25 +2338,16 @@ public class ExpressionCodegen extends JetVisitor 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 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; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/CallGenerator.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/CallGenerator.java deleted file mode 100644 index faf9227daea..00000000000 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/CallGenerator.java +++ /dev/null @@ -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); -} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java index 0556b4f1605..f552fc0ab54 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java @@ -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 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); + } }