diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineCodegen.java index 9c4b08b3f62..5a602e9bf1f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineCodegen.java @@ -21,6 +21,7 @@ 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; import org.jetbrains.asm4.commons.Method; @@ -163,15 +164,16 @@ public class InlineCodegen implements ParentCodegenAware, Inliner { jvmSignature.getGenericsSignature(), null); - FunctionCodegen.generateMethodBody(node, functionDescriptor, context.getParentContext().intoFunction(functionDescriptor), + //for maxLocals calculation + MethodVisitor adapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node); + FunctionCodegen.generateMethodBody(adapter, functionDescriptor, context.getParentContext().intoFunction(functionDescriptor), jvmSignature, new FunctionGenerationStrategy.FunctionDefault(state, functionDescriptor, (JetDeclarationWithBody) element), getParentCodegen()); - //TODO - node.visitMaxs(30, 30); - node.visitEnd(); + adapter.visitMaxs(-1, -1); + adapter.visitEnd(); } return node; } @@ -196,7 +198,6 @@ public class InlineCodegen implements ParentCodegenAware, Inliner { VarRemapper.ParamRemapper remapper = new VarRemapper.ParamRemapper(parameters, initialFrameSize); inliner.doTransformAndMerge(codegen.getInstructionAdapter(), remapper); - generateClosuresBodies(); } @@ -219,9 +220,7 @@ public class InlineCodegen implements ParentCodegenAware, Inliner { Method asmMethod = jvmMethodSignature.getAsmMethod(); MethodNode methodNode = new MethodNode(Opcodes.ASM4, getMethodAsmFlags(descriptor, context.getContextKind()), asmMethod.getName(), asmMethod.getDescriptor(), jvmMethodSignature.getGenericsSignature(), null); - - //AnalyzerAdapter adapter = new AnalyzerAdapter("fake", methodNode.access, methodNode.name, methodNode.desc, methodNode); - MethodNode adapter = methodNode; + MethodVisitor adapter = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode); FunctionCodegen.generateMethodBody(adapter, descriptor, context, jvmMethodSignature, new FunctionGenerationStrategy.FunctionDefault(state, descriptor, declaration) { @Override @@ -229,7 +228,7 @@ public class InlineCodegen implements ParentCodegenAware, Inliner { return false; } }, codegen.getParentCodegen()); - adapter.visitMaxs(30, 30); + adapter.visitMaxs(-1, -1); return methodNode; } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineCodegenUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineCodegenUtil.java index b1155193fe5..124b386e04b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineCodegenUtil.java @@ -240,4 +240,9 @@ public class InlineCodegenUtil { } return null; } + + @NotNull + public static MaxCalcNode wrapWithMaxLocalCalc(@NotNull MethodNode methodNode) { + return new MaxCalcNode(methodNode); + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/MaxCalcNode.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/MaxCalcNode.java new file mode 100644 index 00000000000..7efd00d44e7 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/MaxCalcNode.java @@ -0,0 +1,78 @@ +/* + * Copyright 2010-2014 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.asm; + +import org.jetbrains.asm4.MethodVisitor; +import org.jetbrains.asm4.Opcodes; +import org.jetbrains.asm4.Type; +import org.jetbrains.asm4.tree.AbstractInsnNode; +import org.jetbrains.asm4.tree.MethodNode; + +import java.util.ListIterator; + +public class MaxCalcNode extends MethodVisitor { + + private int maxLocal; + + private final MethodNode node; + + public MaxCalcNode(MethodNode node) + { + super(Opcodes.ASM4, node); + this.node = node; + int paramsSize = (node.access & Opcodes.ACC_STATIC) == 0 ? 1 : 0; + + Type[] types = Type.getArgumentTypes(node.desc); + for (Type type : types) { + paramsSize += type.getSize(); + } + maxLocal = paramsSize; + } + + @Override + public void visitVarInsn(int opcode, int var) { + super.visitVarInsn(opcode, var); + int size = opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE ? 2 : 1; + updateMaxLocal(var, size); + } + + @Override + public void visitIincInsn(int var, int increment) { + super.visitIincInsn(var, increment); + updateMaxLocal(var, 1); + } + + private void updateMaxLocal(int index, int size) { + maxLocal = Math.max(maxLocal, index + size); + } + + @Override + public void visitMaxs(int maxStack, int maxLocals) { + //NB: it's hack for fast maxStack calculation cause it performed only in MethodWriter + //temporary solution: maxStack = instruction size (without labels and line numbers) * 2 (cause 1 instruction could put value of size 2) + int size = 0; + ListIterator iterator = node.instructions.iterator(); + while (iterator.hasNext()) { + AbstractInsnNode next = iterator.next(); + int type = next.getType(); + if (type != AbstractInsnNode.LINE && type != AbstractInsnNode.LABEL) { + size++; + } + } + super.visitMaxs(Math.max(size * 2, maxStack), Math.max(maxLocals, this.maxLocal)); + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/MethodInliner.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/MethodInliner.java index b1db37e15be..589b0fd8328 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/asm/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/MethodInliner.java @@ -20,9 +20,7 @@ import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants; import java.util.*; -import static org.jetbrains.jet.codegen.asm.InlineCodegenUtil.isLambdaClass; -import static org.jetbrains.jet.codegen.asm.InlineCodegenUtil.isLambdaConstructorCall; -import static org.jetbrains.jet.codegen.asm.InlineCodegenUtil.isInvokeOnInlinable; +import static org.jetbrains.jet.codegen.asm.InlineCodegenUtil.*; public class MethodInliner { @@ -213,6 +211,7 @@ public class MethodInliner { ArrayList capturedTypes = parameters.getCapturedTypes(); Type[] allTypes = ArrayUtil.mergeArrays(types, capturedTypes.toArray(new Type[capturedTypes.size()])); + node.instructions.resetLabels(); MethodNode transformedNode = new MethodNode(node.access, node.name, Type.getMethodDescriptor(returnType, allTypes), node.signature, null) { @Override @@ -236,9 +235,14 @@ public class MethodInliner { } super.visitIincInsn(newIndex, increment); } + + @Override + public void visitMaxs(int maxStack, int maxLocals) { + super.visitMaxs(maxStack, maxLocals + capturedParamsSize); + } }; + node.accept(transformedNode); - transformedNode.visitMaxs(30, 30); if (lambdaInfo != null) { transformCaptured(transformedNode, parameters, lambdaInfo, lambdaFieldRemapper);