diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 362bde601a8..e6717cfae09 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1711,7 +1711,7 @@ public class ExpressionCodegen extends JetVisitor implem StackValue value = context.lookupInContext(descriptor, StackValue.local(0, OBJECT_TYPE), state, false); if (value != null) { - if (context.isSpecialStackValue(value) != null) { + if (context.isSpecialStackValue(value)) { return value; } @@ -2348,9 +2348,6 @@ public class ExpressionCodegen extends JetVisitor implem continue; } - boolean putInLocal = true; - StackValue valueIfPresent = null; - ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameter.getIndex()); Type parameterType = valueParameterTypes.get(valueParameter.getIndex()); if (resolvedValueArgument instanceof ExpressionValueArgument) { @@ -2362,7 +2359,6 @@ public class ExpressionCodegen extends JetVisitor implem //TODO deparenthisise if (callGenerator.isInliningClosure(argumentExpression, valueParameter)) { callGenerator.rememberClosure((JetFunctionLiteralExpression) argumentExpression, parameterType); - putInLocal = false; } else { StackValue value = gen(argumentExpression); if (callGenerator.shouldPutValue(parameterType, value, valueParameter)) { @@ -2373,18 +2369,16 @@ public class ExpressionCodegen extends JetVisitor implem } else if (resolvedValueArgument instanceof DefaultValueArgument) { pushDefaultValueOnStack(parameterType, v); mask |= (1 << valueParameter.getIndex()); + callGenerator.putInLocal(parameterType, null, valueParameter); } else if (resolvedValueArgument instanceof VarargValueArgument) { VarargValueArgument valueArgument = (VarargValueArgument) resolvedValueArgument; genVarargs(valueParameter, valueArgument); + callGenerator.putInLocal(parameterType, null, valueParameter); } else { throw new UnsupportedOperationException(); } - - if (putInLocal) { - callGenerator.putInLocal(parameterType, valueIfPresent, valueParameter); - } } return mask; } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/context/MethodContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/context/MethodContext.java index 02dbbcdbb92..7af24f65666 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/context/MethodContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/context/MethodContext.java @@ -104,17 +104,14 @@ public class MethodContext extends CodegenContext { return isInlineClosure; } - public StackValue isSpecialStackValue(StackValue stackValue) { + public boolean isSpecialStackValue(StackValue stackValue) { if (isInlineClosure && stackValue instanceof StackValue.Composed) { StackValue prefix = ((StackValue.Composed) stackValue).prefix; StackValue suffix = ((StackValue.Composed) stackValue).suffix; if (prefix instanceof StackValue.Local && ((StackValue.Local) prefix).index == 0) { - if (suffix instanceof StackValue.Field) { - StackValue.Field field = (StackValue.Field) suffix; - return StackValue.field(field.type, field.owner, field.name, true); - } + return suffix instanceof StackValue.Field; } } - return null; + return false; } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/CapturedParamInfo.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/CapturedParamInfo.java index 14c1717e10c..fb36534adb9 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/CapturedParamInfo.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/CapturedParamInfo.java @@ -62,20 +62,8 @@ public class CapturedParamInfo extends ParameterInfo { this.recapturedFrom = recapturedFrom; } - - public CapturedParamInfo newRemapIndex(int newRamapIndex) { - return clone(index, newRamapIndex); - } - public CapturedParamInfo newIndex(int newIndex) { - return clone(newIndex, getRemapIndex()); - } - - public CapturedParamInfo clone(int newIndex, int newRamapIndex) { - CapturedParamInfo capturedParamInfo = new CapturedParamInfo(fieldName, type, isSkipped, newIndex, newRamapIndex); - capturedParamInfo.setLambda(lambda); - capturedParamInfo.setRecapturedFrom(recapturedFrom); - return capturedParamInfo; + return clone(newIndex, getRemapValue()); } public CapturedParamInfo clone(int newIndex, StackValue newRamapIndex) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/ConstructorInvocation.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/ConstructorInvocation.java index 52d688386a0..266c6fe95ef 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/ConstructorInvocation.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/ConstructorInvocation.java @@ -25,9 +25,9 @@ public class ConstructorInvocation { private final String ownerInternalName; - private final Map access; + private final Map access; - private boolean isSameModule; + private final boolean isSameModule; private Type newLambdaType; @@ -37,7 +37,7 @@ public class ConstructorInvocation { private Map recapturedLambdas; - ConstructorInvocation(String ownerInternalName, Map access, boolean isSameModule) { + ConstructorInvocation(String ownerInternalName, Map access, boolean isSameModule) { this.ownerInternalName = ownerInternalName; this.access = access; this.isSameModule = isSameModule; @@ -51,7 +51,7 @@ public class ConstructorInvocation { return !access.isEmpty() || !isSameModule; } - public Map getAccess() { + public Map getAccess() { return access; } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineAdapter.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineAdapter.java index 34afff36a9d..a3331ceedd6 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineAdapter.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineAdapter.java @@ -75,19 +75,17 @@ public class InlineAdapter extends InstructionAdapter { public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { if(!isInlining) { - blocks.add(new CatchBlock(start, end, - handler, type)); - } else { - super.visitTryCatchBlock(start, end, - handler, type); + blocks.add(new CatchBlock(start, end, handler, type)); + } + else { + super.visitTryCatchBlock(start, end, handler, type); } } @Override public void visitMaxs(int stack, int locals) { for (CatchBlock b : blocks) { - super.visitTryCatchBlock(b.start, b.end, - b.handler, b.type); + super.visitTryCatchBlock(b.start, b.end, b.handler, b.type); } super.visitMaxs(stack, locals); } 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 183380150bf..0556b4f1605 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java @@ -89,8 +89,6 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator { protected final Map expressionMap = new HashMap(); - private SimpleFunctionDescriptor inlineFunctionDescriptor; - public InlineCodegen( @NotNull ExpressionCodegen codegen, @NotNull GenerationState state, @@ -98,7 +96,6 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator { @NotNull Call call ) { assert functionDescriptor.getInlineStrategy().isInline() : "InlineCodegen could inline only inline function but " + functionDescriptor; - inlineFunctionDescriptor = functionDescriptor; this.state = state; this.typeMapper = state.getTypeMapper(); @@ -117,7 +114,7 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator { this.asFunctionInline = false; isSameModule = !(functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) /*not compiled library*/ && - CodegenUtil.isCallInsideSameModuleAsDeclared(inlineFunctionDescriptor, codegen.getContext()); + CodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext()); } @@ -262,26 +259,21 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator { if (index >= 0 && couldBeRemapped) { CapturedParamInfo capturedParamInfo = activeLambda.getCapturedVars().get(index); - capturedParamInfo.setRemapIndex(remappedIndex != null ? remappedIndex : StackValue.local(info.getIndex(), info.getType())); + capturedParamInfo.setRemapValue(remappedIndex != null ? remappedIndex : StackValue.local(info.getIndex(), info.getType())); } doWithParameter(info); } } + + /*descriptor is null for captured vars*/ @Override public boolean shouldPutValue( @NotNull Type type, @Nullable StackValue stackValue, - ValueParameterDescriptor descriptor + @Nullable ValueParameterDescriptor descriptor ) { - //boolean isInline = true/*context.isInlineFunction() || context.getParentContext() instanceof ClosureContext*/; - //if (stackValue != null && isInline && stackValue instanceof StackValue.Local) { - // if (isInvokeOnInlinable(type.getClassName(), "invoke") && (descriptor == null || !InlineUtil.hasNoinlineAnnotation(descriptor))) { - // //TODO remap only inlinable closure => otherwise we could get a lot of problem - // return false; - // } - //} if (stackValue == null) { //default or vararg @@ -299,22 +291,13 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator { return false; } - if (codegen.getContext().isInlineClosure() && codegen.getContext().getContextDescriptor() instanceof AnonymousFunctionDescriptor) { - Type internalName = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) codegen.getContext().getContextDescriptor()); - - String owner = null; - if (stackValue instanceof StackValue.Field) { - owner = ((StackValue.Field) stackValue).owner.getInternalName(); - } - - if (stackValue instanceof StackValue.Composed) { - //go through aload 0 - owner = internalName.getInternalName(); - } - - if (descriptor != null && !InlineUtil.hasNoinlineAnnotation(descriptor) && internalName.getInternalName().equals(owner)) { - //check type of context - return false; + if (stackValue instanceof StackValue.Composed) { + //see: Method.isSpecialStackValue: go through aload 0 + if (codegen.getContext().isInlineClosure() && codegen.getContext().getContextDescriptor() instanceof AnonymousFunctionDescriptor) { + if (descriptor != null && !InlineUtil.hasNoinlineAnnotation(descriptor)) { + //TODO: check type of context + return false; + } } } return true; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java index 991704596e5..74d4e5d4043 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java @@ -189,7 +189,7 @@ public class InlineCodegenUtil { } - public static boolean isInvokeOnInlinable(String owner, String name) { + public static boolean isInvokeOnLambda(String owner, String name) { return INVOKE.equals(name) && /*TODO: check type*/owner.contains("Function"); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineFieldRemapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineFieldRemapper.java index 61dd56eef60..e1c33a871d6 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineFieldRemapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineFieldRemapper.java @@ -27,8 +27,6 @@ import java.util.Collection; import java.util.List; import java.util.Map; -import static org.jetbrains.jet.codegen.inline.MethodInliner.getPreviousNoLabelNoLine; - public class InlineFieldRemapper extends LambdaFieldRemapper { private final String oldOwnerType; @@ -50,18 +48,14 @@ public class InlineFieldRemapper extends LambdaFieldRemapper { public AbstractInsnNode doTransform( MethodNode node, FieldInsnNode fieldInsnNode, CapturedParamInfo capturedField ) { - boolean isRecaptured = isRecapruredLambdaType(fieldInsnNode.owner); + boolean isRecaptured = isRecapturedLambdaType(fieldInsnNode.owner); if (!isRecaptured && capturedField.getLambda() != null) { //strict inlining return super.doTransform(node, fieldInsnNode, capturedField); } - AbstractInsnNode prev = getPreviousNoLabelNoLine(fieldInsnNode); - - assert prev.getType() == AbstractInsnNode.VAR_INSN || prev.getType() == AbstractInsnNode.FIELD_INSN; - AbstractInsnNode loadThis = prev; - assert /*loadThis.var == info.getCapturedVarsSize() - 1 && */loadThis.getOpcode() == Opcodes.ALOAD || loadThis.getOpcode() == Opcodes.GETSTATIC; + AbstractInsnNode loadThis = getPreviousThis(fieldInsnNode); int opcode = Opcodes.GETSTATIC; @@ -95,10 +89,10 @@ public class InlineFieldRemapper extends LambdaFieldRemapper { @Override public boolean canProcess(String owner, String currentLambdaType) { - return super.canProcess(owner, currentLambdaType) || isRecapruredLambdaType(owner); + return super.canProcess(owner, currentLambdaType) || isRecapturedLambdaType(owner); } - private boolean isRecapruredLambdaType(String owner) { + private boolean isRecapturedLambdaType(String owner) { return recapturedLambdas.containsKey(owner); } @@ -106,7 +100,7 @@ public class InlineFieldRemapper extends LambdaFieldRemapper { @Nullable @Override public CapturedParamInfo findField(FieldInsnNode fieldInsnNode, Collection captured) { - if (!isRecapruredLambdaType(fieldInsnNode.owner)) { + if (!isRecapturedLambdaType(fieldInsnNode.owner)) { return super.findField(fieldInsnNode, captured); } else { LambdaInfo info = recapturedLambdas.get(fieldInsnNode.owner); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InliningInfo.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InliningInfo.java index b633e901e4d..5eafafac24e 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InliningInfo.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InliningInfo.java @@ -29,7 +29,7 @@ public class InliningInfo { public final Map expresssionMap; - public final List inlinableAccesses; + public final List invokeCalls; public final List constructorInvocation; @@ -47,7 +47,7 @@ public class InliningInfo { public InliningInfo( Map map, - List accesses, + List accesses, List invocation, VarRemapper remapper, GenerationState state, @@ -57,7 +57,7 @@ public class InliningInfo { Map typeMapping ) { expresssionMap = map; - inlinableAccesses = accesses; + invokeCalls = accesses; constructorInvocation = invocation; this.remapper = remapper; this.state = state; @@ -74,7 +74,7 @@ public class InliningInfo { public InliningInfo subInline(NameGenerator generator, Map additionalTypeMappings) { HashMap newTypeMappings = new HashMap(typeMapping); newTypeMappings.putAll(additionalTypeMappings); - return new InliningInfo(expresssionMap, inlinableAccesses, constructorInvocation, remapper, state, generator, startContext, call, + return new InliningInfo(expresssionMap, invokeCalls, constructorInvocation, remapper, state, generator, startContext, call, newTypeMappings); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlinableAccess.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InvokeCall.java similarity index 54% rename from compiler/backend/src/org/jetbrains/jet/codegen/inline/InlinableAccess.java rename to compiler/backend/src/org/jetbrains/jet/codegen/inline/InvokeCall.java index 0d4a4b7cba7..76e0760a8c8 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlinableAccess.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InvokeCall.java @@ -18,38 +18,14 @@ package org.jetbrains.jet.codegen.inline; import org.jetbrains.annotations.Nullable; -import java.util.List; - -class InlinableAccess { +class InvokeCall { public final int index; - public final boolean inlinable; + public final LambdaInfo lambdaInfo; - private final List parameters; - - private LambdaInfo info; - - InlinableAccess(int index, boolean isInlinable, List parameterInfos) { + InvokeCall(int index, @Nullable LambdaInfo lambdaInfo) { this.index = index; - inlinable = isInlinable; - this.parameters = parameterInfos; - } - - public boolean isInlinable() { - return inlinable; - } - - @Nullable - public LambdaInfo getInfo() { - return info; - } - - public void setInfo(LambdaInfo info) { - this.info = info; - } - - public List getParameters() { - return parameters; + this.lambdaInfo = lambdaInfo; } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaFieldRemapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaFieldRemapper.java index c0d326d07ec..1d8dc5480f4 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaFieldRemapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaFieldRemapper.java @@ -31,21 +31,26 @@ import static org.jetbrains.jet.codegen.inline.MethodInliner.getPreviousNoLabelN public class LambdaFieldRemapper { public AbstractInsnNode doTransform(MethodNode node, FieldInsnNode fieldInsnNode, CapturedParamInfo capturedField) { - AbstractInsnNode prev = getPreviousNoLabelNoLine(fieldInsnNode); - - assert prev.getType() == AbstractInsnNode.VAR_INSN || prev.getType() == AbstractInsnNode.FIELD_INSN; - AbstractInsnNode loadThis = prev; - int opcode1 = loadThis.getOpcode(); - assert /*loadThis.var == info.getCapturedVarsSize() - 1 && */opcode1 == Opcodes.ALOAD || opcode1 == Opcodes.GETSTATIC; + AbstractInsnNode loadThis = getPreviousThis(fieldInsnNode); int opcode = fieldInsnNode.getOpcode() == Opcodes.GETFIELD ? capturedField.getType().getOpcode(Opcodes.ILOAD) : capturedField.getType().getOpcode(Opcodes.ISTORE); - VarInsnNode insn = new VarInsnNode(opcode, capturedField.getIndex()); + VarInsnNode newInstruction = new VarInsnNode(opcode, capturedField.getIndex()); - node.instructions.remove(prev); //remove aload this - node.instructions.insertBefore(fieldInsnNode, insn); + node.instructions.remove(loadThis); //remove aload this + node.instructions.insertBefore(fieldInsnNode, newInstruction); node.instructions.remove(fieldInsnNode); //remove aload field - return insn; + return newInstruction; + } + + protected static AbstractInsnNode getPreviousThis(FieldInsnNode fieldInsnNode) { + AbstractInsnNode loadThis = getPreviousNoLabelNoLine(fieldInsnNode); + + assert loadThis.getType() == AbstractInsnNode.VAR_INSN || loadThis.getType() == AbstractInsnNode.FIELD_INSN : + "Field access instruction should go after load this but goes after " + loadThis; + assert loadThis.getOpcode() == Opcodes.ALOAD || loadThis.getOpcode() == Opcodes.GETSTATIC : + "This should be loaded by ALOAD or GETSTATIC but " + loadThis.getOpcode(); + return loadThis; } public List markRecaptured(List originalCaptured, LambdaInfo lambda) { @@ -59,14 +64,11 @@ public class LambdaFieldRemapper { @Nullable public CapturedParamInfo findField(FieldInsnNode fieldInsnNode, Collection captured) { - String name = fieldInsnNode.name; - CapturedParamInfo result = null; for (CapturedParamInfo valueDescriptor : captured) { - if (valueDescriptor.getFieldName().equals(name)) { - result = valueDescriptor; - break; + if (valueDescriptor.getFieldName().equals(fieldInsnNode.name)) { + return valueDescriptor; } } - return result; + return null; } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaInfo.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaInfo.java index 82200514013..5d42649aaa1 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaInfo.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaInfo.java @@ -25,9 +25,11 @@ import org.jetbrains.jet.codegen.context.EnclosedValueDescriptor; import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.psi.JetFunctionLiteral; import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants; import java.util.*; @@ -39,7 +41,8 @@ public class LambdaInfo { public final JetFunctionLiteralExpression expression; - @NotNull private final JetTypeMapper typeMapper; + @NotNull + private final JetTypeMapper typeMapper; public final CalculatedClosure closure; @@ -53,8 +56,6 @@ public class LambdaInfo { private final Type closureClassType; - private int paramOffset; - LambdaInfo(@NotNull JetFunctionLiteralExpression expression, @NotNull JetTypeMapper typeMapper) { this.expression = expression; this.typeMapper = typeMapper; @@ -126,19 +127,10 @@ public class LambdaInfo { return new CapturedParamInfo(descriptor.getFieldName(), descriptor.getType(), false, index, -1); } - private void shiftParams(int shift) { - for (CapturedParamInfo var : getCapturedVars()) { - var.setShift(shift); - } - } - - public int getParamOffset() { - return paramOffset; - } - public void setParamOffset(int paramOffset) { - this.paramOffset = paramOffset; - shiftParams(paramOffset); + for (CapturedParamInfo var : getCapturedVars()) { + var.setShift(paramOffset); + } } public List getParamsWithoutCapturedValOrVar() { @@ -146,6 +138,25 @@ public class LambdaInfo { return Arrays.asList(types); } + public Parameters addAllParameters(@NotNull LambdaFieldRemapper remapper) { + ParametersBuilder builder = ParametersBuilder.newBuilder(); + //add skipped this cause inlined lambda doesn't have it + builder.addThis(AsmTypeConstants.OBJECT_TYPE, true).setLambda(this); + + List valueParameters = getFunctionDescriptor().getValueParameters(); + for (ValueParameterDescriptor parameter : valueParameters) { + Type type = typeMapper.mapType(parameter.getType()); + builder.addNextParameter(type, false, null); + } + + + List infos = remapper.markRecaptured(getCapturedVars(), this); + for (CapturedParamInfo info : infos) { + builder.addCapturedParam(info.getFieldName(), info.getType(), info.isSkipped, info); + } + return builder.buildParameters(); + } + public int getCapturedVarsSize() { int size = 0; for (CapturedParamInfo next : getCapturedVars()) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaTransformer.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaTransformer.java index 1c9d47e1b5f..f519b96cff6 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaTransformer.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaTransformer.java @@ -65,7 +65,7 @@ public class LambdaTransformer { private String signature; private String superName; private String[] interfaces; - private boolean isSameModule; + private final boolean isSameModule; public LambdaTransformer(String lambdaInternalName, InliningInfo info, boolean isSameModule, Type newLambdaType) { this.isSameModule = isSameModule; @@ -189,7 +189,7 @@ public class LambdaTransformer { } private void extractParametersMapping(MethodNode constructor, ParametersBuilder builder, ConstructorInvocation invocation) { - Map indexToLambda = invocation.getAccess(); + Map indexToLambda = invocation.getAccess(); AbstractInsnNode cur = constructor.instructions.getFirst(); cur = cur.getNext(); //skip super call @@ -202,9 +202,9 @@ public class LambdaTransformer { paramMapping.put(fieldNode.name, varIndex); CapturedParamInfo info = builder.addCapturedParam(fieldNode.name, Type.getType(fieldNode.desc), false, null); - InlinableAccess access = indexToLambda.get(varIndex); + InvokeCall access = indexToLambda.get(varIndex); if (access != null) { - LambdaInfo accessInfo = access.getInfo(); + LambdaInfo accessInfo = access.lambdaInfo; if (accessInfo != null) { info.setLambda(accessInfo); additionalCaptured.add(accessInfo); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java index e2bda2a3287..bc7e92afe6d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java @@ -16,8 +16,7 @@ import org.jetbrains.asm4.tree.analysis.*; import org.jetbrains.jet.codegen.ClosureCodegen; import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.codegen.state.JetTypeMapper; -import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; -import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants; +import org.jetbrains.jet.utils.UtilsPackage; import java.util.*; @@ -32,18 +31,18 @@ public class MethodInliner { private final InliningInfo parent; @Nullable - private final Type lambdaInfo; + private final Type lambdaType; private final LambdaFieldRemapper lambdaFieldRemapper; - private boolean isSameModule; + private final boolean isSameModule; private final JetTypeMapper typeMapper; - private final List inlinableInvocation = new ArrayList(); + private final List invokeCalls = new ArrayList(); //keeps order - private final List constructorInvocationList = new ArrayList(); + private final List constructorInvocations = new ArrayList(); //current state private final Map currentTypeMapping = new HashMap(); @@ -52,20 +51,20 @@ public class MethodInliner { * @param node * @param parameters * @param parent - * @param lambdaInfo - in case on lambda 'invoke' inlining + * @param lambdaType - in case on lambda 'invoke' inlining */ public MethodInliner( @NotNull MethodNode node, - Parameters parameters, + @NotNull Parameters parameters, @NotNull InliningInfo parent, - @Nullable Type lambdaInfo, + @Nullable Type lambdaType, LambdaFieldRemapper lambdaFieldRemapper, boolean isSameModule ) { this.node = node; this.parameters = parameters; this.parent = parent; - this.lambdaInfo = lambdaInfo; + this.lambdaType = lambdaType; this.lambdaFieldRemapper = lambdaFieldRemapper; this.isSameModule = isSameModule; this.typeMapper = parent.state.getTypeMapper(); @@ -87,7 +86,7 @@ public class MethodInliner { transformedNode = markPlacesForInlineAndRemoveInlinable(transformedNode); } catch (AnalyzerException e) { - throw new RuntimeException(e); + throw UtilsPackage.rethrow(e); } transformedNode = doInline(transformedNode, capturedRemapper); @@ -103,11 +102,11 @@ public class MethodInliner { private MethodNode doInline(MethodNode node, final LambdaFieldRemapper capturedRemapper) { - final Deque infos = new LinkedList(inlinableInvocation); + final Deque currentInvokes = new LinkedList(invokeCalls); MethodNode resultNode = new MethodNode(node.access, node.name, node.desc, node.signature, null); - final Iterator iterator = constructorInvocationList.iterator(); + final Iterator iterator = constructorInvocations.iterator(); RemappingMethodAdapter remappingMethodAdapter = new RemappingMethodAdapter(resultNode.access, resultNode.desc, resultNode, new TypeRemapper(currentTypeMapping, isSameModule)); @@ -137,35 +136,34 @@ public class MethodInliner { @Override public void visitMethodInsn(int opcode, String owner, String name, String desc) { - if (/*INLINE_RUNTIME.equals(owner) &&*/ isInvokeOnInlinable(owner, name)) { //TODO add method - assert !infos.isEmpty(); - InlinableAccess inlinableAccess = infos.remove(); + if (/*INLINE_RUNTIME.equals(owner) &&*/ isInvokeOnLambda(owner, name)) { //TODO add method + assert !currentInvokes.isEmpty(); + InvokeCall invokeCall = currentInvokes.remove(); + LambdaInfo info = invokeCall.lambdaInfo; - if (!inlinableAccess.isInlinable()) { - //noninlinable closure + if (info == null) { + //noninlinable lambda super.visitMethodInsn(opcode, owner, name, desc); return; } - LambdaInfo info = getLambda(inlinableAccess.index); - - int valueParamShift = getNextLocalIndex(); + int valueParamShift = getNextLocalIndex();//NB: don't inline cause it changes putStackValuesIntoLocals(info.getParamsWithoutCapturedValOrVar(), valueParamShift, this, desc); - List lambdaParameters = inlinableAccess.getParameters(); + Parameters lambdaParameters = info.addAllParameters(capturedRemapper); - Parameters params = new Parameters(lambdaParameters, Parameters.transformList(capturedRemapper.markRecaptured(info.getCapturedVars(), info), lambdaParameters.size())); + setInlining(true); + MethodInliner inliner = new MethodInliner(info.getNode(), lambdaParameters, parent.subInline(parent.nameGenerator.subGenerator("lambda")), info.getLambdaClassType(), + capturedRemapper, true /*cause all calls in same module as lambda*/); - this.setInlining(true); - MethodInliner inliner = new MethodInliner(info.getNode(), params, parent.subInline(parent.nameGenerator.subGenerator("lambda")), info.getLambdaClassType(), - capturedRemapper, true /*cause all call in same module as lambda*/); - - VarRemapper.ParamRemapper remapper = new VarRemapper.ParamRemapper(params, valueParamShift); + VarRemapper.ParamRemapper remapper = new VarRemapper.ParamRemapper(lambdaParameters, valueParamShift); inliner.doTransformAndMerge(this.mv, remapper); //TODO add skipped this and receiver + + //return value boxing/unboxing Method bridge = typeMapper.mapSignature(ClosureCodegen.getInvokeFunction(info.getFunctionDescriptor())).getAsmMethod(); Method delegate = typeMapper.mapSignature(info.getFunctionDescriptor()).getAsmMethod(); StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), this); - this.setInlining(true); + setInlining(false); } else if (isLambdaConstructorCall(owner, name)) { //TODO add method assert invocation != null : " call not corresponds to new call" + owner + " " + name; @@ -248,12 +246,12 @@ public class MethodInliner { node.accept(transformedNode); - if (lambdaInfo != null) { - transformCaptured(transformedNode, parameters, lambdaInfo, lambdaFieldRemapper); - } + transformCaptured(transformedNode); + return transformedNode; } + @NotNull protected MethodNode markPlacesForInlineAndRemoveInlinable(@NotNull MethodNode node) throws AnalyzerException { node = prepareNode(node); @@ -275,10 +273,9 @@ public class MethodInliner { String name = methodInsnNode.name; //TODO check closure int paramLength = Type.getArgumentTypes(desc).length + 1;//non static - if (isInvokeOnInlinable(owner, name) /*&& methodInsnNode.owner.equals(INLINE_RUNTIME)*/) { + if (isInvokeOnLambda(owner, name) /*&& methodInsnNode.owner.equals(INLINE_RUNTIME)*/) { SourceValue sourceValue = frame.getStack(frame.getStackSize() - paramLength); - boolean isInlinable = false; LambdaInfo lambdaInfo = null; int varIndex = -1; @@ -288,19 +285,18 @@ public class MethodInliner { assert insnNode.getOpcode() == Opcodes.ALOAD : insnNode.toString(); varIndex = ((VarInsnNode) insnNode).var; lambdaInfo = getLambda(varIndex); - isInlinable = lambdaInfo != null; - if (isInlinable) { + if (lambdaInfo != null) { //remove inlinable access node.instructions.remove(insnNode); } } } - inlinableInvocation.add(new InlinableAccess(varIndex, isInlinable, getParametersInfo(lambdaInfo, desc))); + invokeCalls.add(new InvokeCall(varIndex, lambdaInfo)); } else if (isLambdaConstructorCall(owner, name)) { - Map infos = new HashMap(); + Map infos = new HashMap(); int paramStart = frame.getStackSize() - paramLength; for (int i = 0; i < paramLength; i++) { @@ -311,19 +307,14 @@ public class MethodInliner { int varIndex = ((VarInsnNode) insnNode).var; LambdaInfo lambdaInfo = getLambda(varIndex); if (lambdaInfo != null) { - InlinableAccess inlinableAccess = new InlinableAccess(varIndex, true, null); - inlinableAccess.setInfo(lambdaInfo); - infos.put(i, inlinableAccess); - - //remove inlinable access + infos.put(i, new InvokeCall(varIndex, lambdaInfo)); node.instructions.remove(insnNode); } } } } - ConstructorInvocation invocation = new ConstructorInvocation(owner, infos, isSameModule); - constructorInvocationList.add(invocation); + constructorInvocations.add(new ConstructorInvocation(owner, infos, isSameModule)); } } } @@ -343,7 +334,7 @@ public class MethodInliner { } } - //clean dead try catch blocks + //clean dead try/catch blocks List blocks = node.tryCatchBlocks; for (Iterator iterator = blocks.iterator(); iterator.hasNext(); ) { TryCatchBlockNode block = iterator.next(); @@ -355,40 +346,7 @@ public class MethodInliner { return node; } - public List getParametersInfo(LambdaInfo info, String desc) { - List result = new ArrayList(); - Type[] types = Type.getArgumentTypes(desc); - - //add skipped this cause closure doesn't have it - //result.add(ParameterInfo.STUB); - ParameterInfo thiz = new ParameterInfo(AsmTypeConstants.OBJECT_TYPE, true, -1, -1); - thiz.setLambda(info); - - result.add(thiz); - int index = 1; - - if (info != null) { - List valueParameters = info.getFunctionDescriptor().getValueParameters(); - for (ValueParameterDescriptor parameter : valueParameters) { - Type type = typeMapper.mapType(parameter.getType()); - int paramIndex = index++; - result.add(new ParameterInfo(type, false, paramIndex, -1)); - if (type.getSize() == 2) { - result.add(ParameterInfo.STUB); - } - } - } else { - for (Type type : types) { - int paramIndex = index++; - result.add(new ParameterInfo(type, false, paramIndex, -1)); - if (type.getSize() == 2) { - result.add(ParameterInfo.STUB); - } - } - } - return result; - } - + @Nullable public LambdaInfo getLambda(int index) { if (index < parameters.totalSize()) { return parameters.get(index).getLambda(); @@ -433,13 +391,10 @@ public class MethodInliner { } } - static List transformCaptured( - @NotNull MethodNode node, - @NotNull Parameters paramsToSearch, - @NotNull Type lambdaClassType, - @NotNull LambdaFieldRemapper lambdaFieldRemapper - ) { - List capturedFields = new ArrayList(); + private void transformCaptured(@NotNull MethodNode node) { + if (lambdaType == null) { + return; + } //remove all this and shift all variables to captured ones size AbstractInsnNode cur = node.instructions.getFirst(); @@ -447,53 +402,28 @@ public class MethodInliner { if (cur.getType() == AbstractInsnNode.FIELD_INSN) { FieldInsnNode fieldInsnNode = (FieldInsnNode) cur; //TODO check closure - String owner = fieldInsnNode.owner; - if (lambdaFieldRemapper.canProcess(fieldInsnNode.owner, lambdaClassType.getInternalName())) { - String name = fieldInsnNode.name; - String desc = fieldInsnNode.desc; - - Collection vars = paramsToSearch.getCaptured(); - CapturedParamInfo result = lambdaFieldRemapper.findField(fieldInsnNode, paramsToSearch.getCaptured()); + if (lambdaFieldRemapper.canProcess(fieldInsnNode.owner, lambdaType.getInternalName())) { + CapturedParamInfo result = this.lambdaFieldRemapper.findField(fieldInsnNode, parameters.getCaptured()); if (result == null) { throw new UnsupportedOperationException("Coudn't find field " + - owner + + fieldInsnNode.owner + "." + - name + + fieldInsnNode.name + " (" + - desc + - ") in captured vars of " + lambdaClassType); + fieldInsnNode.desc + + ") in captured vars of " + lambdaType); } if (result.isSkipped()) { - //lambda class transformation skip this captured + //lambda class transformation: skip captured this } else { - cur = lambdaFieldRemapper.doTransform(node, fieldInsnNode, result); - - //AbstractInsnNode prev = getPreviousNoLableNoLine(cur); - // - //assert prev.getType() == AbstractInsnNode.VAR_INSN; - //VarInsnNode loadThis = (VarInsnNode) prev; - //assert /*loadThis.var == info.getCapturedVarsSize() - 1 && */loadThis.getOpcode() == Opcodes.ALOAD; - // - //int opcode = fieldInsnNode.getOpcode() == Opcodes.GETFIELD ? result.getType().getOpcode(Opcodes.ILOAD) : result.getType().getOpcode(Opcodes.ISTORE); - //VarInsnNode insn = new VarInsnNode(opcode, result.getIndex()); - // - //node.instructions.remove(prev); //remove aload this - //node.instructions.insertBefore(cur, insn); - //node.instructions.remove(cur); //remove aload field - // - //cur = insn; - // - //FieldAccess fieldAccess = new FieldAccess(fieldInsnNode.name, fieldInsnNode.desc, new FieldAccess("" + loadThis.var, lambdaClassType.getInternalName())); - //capturedFields.add(fieldAccess); + cur = this.lambdaFieldRemapper.doTransform(node, fieldInsnNode, result); } } } cur = cur.getNext(); } - - return capturedFields; } public static AbstractInsnNode getPreviousNoLabelNoLine(AbstractInsnNode cur) { @@ -504,8 +434,8 @@ public class MethodInliner { return prev; } - public static void putStackValuesIntoLocals(List directOrder, int shift, InstructionAdapter mv, String descriptor) { - Type[] actualParams = Type.getArgumentTypes(descriptor); //last param is closure itself + public static void putStackValuesIntoLocals(List directOrder, int shift, InstructionAdapter iv, String descriptor) { + Type[] actualParams = Type.getArgumentTypes(descriptor); assert actualParams.length == directOrder.size() : "Number of expected and actual params should be equals!"; int size = 0; @@ -520,9 +450,9 @@ public class MethodInliner { shift -= next.getSize(); Type typeOnStack = actualParams[--index]; if (!typeOnStack.equals(next)) { - StackValue.onStack(typeOnStack).put(next, mv); + StackValue.onStack(typeOnStack).put(next, iv); } - mv.visitVarInsn(next.getOpcode(Opcodes.ISTORE), shift); + iv.store(shift, next); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/ParameterInfo.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/ParameterInfo.java index 46ed74328d1..de1d60102d7 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/ParameterInfo.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/ParameterInfo.java @@ -34,32 +34,32 @@ class ParameterInfo { public final boolean isSkipped; //in case when parameter could be extracted from outer context (e.g. from local var) - private StackValue remapIndex; + private StackValue remapValue; public LambdaInfo lambda; - ParameterInfo(Type type, boolean skipped, int index, int remapIndex) { - this(type, skipped, index, remapIndex == -1 ? null : StackValue.local(remapIndex, type)); + ParameterInfo(Type type, boolean skipped, int index, int remapValue) { + this(type, skipped, index, remapValue == -1 ? null : StackValue.local(remapValue, type)); } ParameterInfo(Type type, boolean skipped, int index, StackValue stackValue) { this.type = type; this.isSkipped = skipped; - this.remapIndex = stackValue; + this.remapValue = stackValue; this.index = index; } public boolean isSkippedOrRemapped() { - return isSkipped || remapIndex != null; + return isSkipped || remapValue != null; } public boolean isRemapped() { - return remapIndex != null; + return remapValue != null; } @Nullable - public StackValue getRemapIndex() { - return remapIndex; + public StackValue getRemapValue() { + return remapValue; } public int getIndex() { @@ -84,7 +84,7 @@ class ParameterInfo { this.lambda = lambda; } - public void setRemapIndex(StackValue remapIndex) { - this.remapIndex = remapIndex; + public void setRemapValue(StackValue remapValue) { + this.remapValue = remapValue; } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/Parameters.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/Parameters.java index d835b088057..3a33b0d97f2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/Parameters.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/Parameters.java @@ -60,20 +60,6 @@ public class Parameters implements Iterable { return Iterables.concat(real, captured).iterator(); } - public static List transformList(List capturedParams, int realSize) { - List result = new ArrayList(); - for (CapturedParamInfo capturedParamInfo : capturedParams) { - CapturedParamInfo newInfo = capturedParamInfo.clone(result.size() + realSize, capturedParamInfo.getIndex()); - - result.add(newInfo); - - if (capturedParamInfo.getType().getSize() == 2) { - result.add(CapturedParamInfo.STUB); - } - } - return result; - } - public static List addStubs(List capturedParams, int realSize) { List result = new ArrayList(); for (CapturedParamInfo capturedParamInfo : capturedParams) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/ParametersBuilder.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/ParametersBuilder.java index a577290a7f8..8f4e58ef59b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/ParametersBuilder.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/ParametersBuilder.java @@ -27,7 +27,6 @@ public class ParametersBuilder { private final List params = new ArrayList(); private final List capturedParams = new ArrayList(); - private final List additionalCapturedParams = new ArrayList(); private int nextIndex = 0; private int nextCaptured = 0; @@ -36,9 +35,10 @@ public class ParametersBuilder { return new ParametersBuilder(); } - public ParametersBuilder addThis(Type type, boolean skipped) { - addParameter(new ParameterInfo(type, skipped, nextIndex, -1)); - return this; + public ParameterInfo addThis(Type type, boolean skipped) { + ParameterInfo info = new ParameterInfo(type, skipped, nextIndex, -1); + addParameter(info); + return info; } public ParametersBuilder addNextParameter(Type type, boolean skipped, @Nullable ParameterInfo original) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/ShiftAdapter.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/ShiftAdapter.java index 235e96ed5d9..d20d43b7324 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/ShiftAdapter.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/ShiftAdapter.java @@ -21,7 +21,7 @@ import org.jetbrains.asm4.commons.InstructionAdapter; public class ShiftAdapter extends InstructionAdapter { - private int shift; + private final int shift; public ShiftAdapter(MethodVisitor mv, int shift) { super(mv); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/VarRemapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/VarRemapper.java index 9c7af627b7a..d18acac60a7 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/VarRemapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/VarRemapper.java @@ -32,9 +32,9 @@ public abstract class VarRemapper { private final Parameters params; private final int actualParamsSize; - private final StackValue [] remapIndex; + private final StackValue [] remapValues; - private int additionalShift; + private final int additionalShift; public ParamRemapper(Parameters params, int additionalShift) { this.additionalShift = additionalShift; @@ -42,15 +42,15 @@ public abstract class VarRemapper { this.params = params; int realSize = 0; - remapIndex = new StackValue [params.totalSize()]; + remapValues = new StackValue [params.totalSize()]; int index = 0; for (ParameterInfo info : params) { if (!info.isSkippedOrRemapped()) { - remapIndex[index] = StackValue.local(realSize, AsmTypeConstants.OBJECT_TYPE); + remapValues[index] = StackValue.local(realSize, AsmTypeConstants.OBJECT_TYPE); realSize += info.getType().getSize(); } else { - remapIndex[index] = info.isRemapped() ? info.getRemapIndex() : null; + remapValues[index] = info.isRemapped() ? info.getRemapValue() : null; } index++; } @@ -64,7 +64,7 @@ public abstract class VarRemapper { if (index < allParamsSize) { ParameterInfo info = params.get(index); - StackValue remapped = remapIndex[index]; + StackValue remapped = remapValues[index]; if (info.isSkipped || remapped == null) { throw new RuntimeException("Trying to access skipped parameter: " + info.type + " at " +index); } @@ -100,9 +100,10 @@ public abstract class VarRemapper { } mv.visitVarInsn(opcode, ((StackValue.Local) value).index); if (remapInfo.parameterInfo != null) { - value.coerce(value.type, remapInfo.parameterInfo.type, mv); + StackValue.coerce(value.type, remapInfo.parameterInfo.type, mv); } } else { + assert remapInfo.parameterInfo != null : "Non local value should have parameter info"; value.put(remapInfo.parameterInfo.type, mv); } }