private void putCapturedInLocal( @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 boolean couldBeRemapped = !shouldPutValue(type, stackValue, valueParameterDescriptor); StackValue remappedIndex = couldBeRemapped ? stackValue : null; ParameterInfo info; if (capturedParamIndex >= 0) { CapturedParamDesc capturedParamInfoInLambda = activeLambda.getCapturedVars().get(capturedParamIndex); info = invocationParamBuilder.addCapturedParam( capturedParamInfoInLambda, capturedParamInfoInLambda.getFieldName()); info.setRemapValue(remappedIndex); } else { info = invocationParamBuilder.addNextParameter(type, false, remappedIndex); } putParameterOnStack(info); } }
@Override public void putHiddenParams() { List<JvmMethodParameterSignature> valueParameters = jvmSignature.getValueParameters(); if (!isStaticMethod(functionDescriptor, context)) { invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false, null); } for (JvmMethodParameterSignature param : valueParameters) { if (param.getKind() == JvmMethodParameterKind.VALUE) { break; } invocationParamBuilder.addNextParameter(param.getAsmType(), false, null); } List<ParameterInfo> infos = invocationParamBuilder.listNotCaptured(); putParameterOnStack(infos.toArray(new ParameterInfo[infos.size()])); }
public void rememberClosure(JetExpression expression, Type type) { JetExpression lambda = JetPsiUtil.deparenthesize(expression); assert isInlinableParameterExpression(lambda) : "Couldn't find inline expression in " + expression.getText(); LambdaInfo info = new LambdaInfo(lambda, typeMapper); ParameterInfo closureInfo = invocationParamBuilder.addNextParameter(type, true, null); closureInfo.setLambda(info); expressionMap.put(closureInfo.getIndex(), info); }
public void leaveTemps() { FrameMap frameMap = codegen.getFrameMap(); List<ParameterInfo> infos = invocationParamBuilder.listAllParams(); for (ListIterator<? extends ParameterInfo> iterator = infos.listIterator(infos.size()); iterator.hasPrevious(); ) { ParameterInfo param = iterator.previous(); if (!param.isSkippedOrRemapped()) { frameMap.leaveTemp(param.type); } } }
@NotNull public Parameters addAllParameters(@NotNull FieldRemapper remapper) { Method asmMethod = typeMapper.mapAsmMethod(getFunctionDescriptor()); ParametersBuilder builder = ParametersBuilder.initializeBuilderFrom( AsmTypes.OBJECT_TYPE, asmMethod.getDescriptor(), this); for (CapturedParamDesc info : getCapturedVars()) { CapturedParamInfo field = remapper.findField( new FieldInsnNode(0, info.getContainingLambdaName(), info.getFieldName(), "")); assert field != null : "Captured field not found: " + info.getContainingLambdaName() + "." + info.getFieldName(); builder.addCapturedParam(field, info.getFieldName()); } return builder.buildParameters(); }
public class InlineCodegen extends CallGenerator { private final GenerationState state; private final JetTypeMapper typeMapper; private final SimpleFunctionDescriptor functionDescriptor; private final JvmMethodSignature jvmSignature; private final JetElement callElement; private final MethodContext context; private final ExpressionCodegen codegen; private final boolean asFunctionInline; private final int initialFrameSize; private final boolean isSameModule; protected final ParametersBuilder invocationParamBuilder = ParametersBuilder.newBuilder(); protected final Map<Integer, LambdaInfo> expressionMap = new HashMap<Integer, LambdaInfo>(); private final ReifiedTypeInliner reifiedTypeInliner; private LambdaInfo activeLambda; private final SourceMapper sourceMapper; public InlineCodegen( @NotNull ExpressionCodegen codegen, @NotNull GenerationState state, @NotNull SimpleFunctionDescriptor functionDescriptor, @NotNull JetElement callElement, @Nullable ReifiedTypeParameterMappings typeParameterMappings) { assert InlineUtil.isInline(functionDescriptor) : "InlineCodegen could inline only inline function: " + functionDescriptor; this.state = state; this.typeMapper = state.getTypeMapper(); this.codegen = codegen; this.callElement = callElement; this.functionDescriptor = functionDescriptor.getOriginal(); reifiedTypeInliner = new ReifiedTypeInliner(typeParameterMappings); initialFrameSize = codegen.getFrameMap().getCurrentSize(); context = (MethodContext) getContext(functionDescriptor, state); jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind()); // TODO: implement AS_FUNCTION inline strategy InlineStrategy inlineStrategy = InlineUtil.getInlineStrategy(functionDescriptor); this.asFunctionInline = false; isSameModule = JvmCodegenUtil.isCallInsideSameModuleAsDeclared( functionDescriptor, codegen.getContext(), state.getOutDirectory()); sourceMapper = codegen.getParentCodegen().getOrCreateSourceMapper(); reportIncrementalInfo( functionDescriptor, codegen.getContext().getFunctionDescriptor().getOriginal()); } @Override public void genCallWithoutAssertions( @NotNull CallableMethod callableMethod, @NotNull ExpressionCodegen codegen) { genCall(callableMethod, null, false, codegen); } @Override public void genCallInner( @NotNull Callable callableMethod, @Nullable ResolvedCall<?> resolvedCall, boolean callDefault, @NotNull ExpressionCodegen codegen) { SMAPAndMethodNode nodeAndSmap = null; if (!state.getInlineCycleReporter().enterIntoInlining(resolvedCall)) { generateStub(resolvedCall, codegen); return; } try { nodeAndSmap = createMethodNode(callDefault); endCall(inlineCall(nodeAndSmap)); } catch (CompilationException e) { throw e; } catch (Exception e) { boolean generateNodeText = !(e instanceof InlineException); PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration( this.codegen.getContext().getContextDescriptor()); throw new CompilationException( "Couldn't inline method call '" + functionDescriptor.getName() + "' into \n" + (element != null ? element.getText() : "null psi element " + this.codegen.getContext().getContextDescriptor()) + (generateNodeText ? ("\ncause: " + InlineCodegenUtil.getNodeText( nodeAndSmap != null ? nodeAndSmap.getNode() : null)) : ""), e, callElement); } finally { state.getInlineCycleReporter().exitFromInliningOf(resolvedCall); } } protected void generateStub( @Nullable ResolvedCall<?> resolvedCall, @NotNull ExpressionCodegen codegen) { leaveTemps(); assert resolvedCall != null; String message = "Call is part of inline cycle: " + resolvedCall.getCall().getCallElement().getText(); AsmUtil.genThrow(codegen.v, "java/lang/UnsupportedOperationException", message); } private void endCall(@NotNull InlineResult result) { leaveTemps(); codegen.propagateChildReifiedTypeParametersUsages(result.getReifiedTypeParametersUsages()); state.getFactory().removeInlinedClasses(result.getClassesToRemove()); codegen.markLineNumberAfterInlineIfNeeded(); } @NotNull private SMAPAndMethodNode createMethodNode(boolean callDefault) throws ClassNotFoundException, IOException { JvmMethodSignature jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind()); Method asmMethod; if (callDefault) { asmMethod = typeMapper.mapDefaultMethod(functionDescriptor, context.getContextKind()); } else { asmMethod = jvmSignature.getAsmMethod(); } SMAPAndMethodNode nodeAndSMAP; if (functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) { JetTypeMapper.ContainingClassesInfo containingClasses = typeMapper.getContainingClassesForDeserializedCallable( (DeserializedSimpleFunctionDescriptor) functionDescriptor); VirtualFile file = InlineCodegenUtil.getVirtualFileForCallable(containingClasses.getImplClassId(), state); nodeAndSMAP = InlineCodegenUtil.getMethodNode( file.contentsToByteArray(), asmMethod.getName(), asmMethod.getDescriptor(), containingClasses.getFacadeClassId()); if (nodeAndSMAP == null) { throw new RuntimeException( "Couldn't obtain compiled function body for " + descriptorName(functionDescriptor)); } } else { PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor); if (element == null || !(element instanceof JetNamedFunction)) { throw new RuntimeException( "Couldn't find declaration for function " + descriptorName(functionDescriptor)); } JetNamedFunction inliningFunction = (JetNamedFunction) element; MethodNode node = new MethodNode( InlineCodegenUtil.API, getMethodAsmFlags(functionDescriptor, context.getContextKind()) | (callDefault ? Opcodes.ACC_STATIC : 0), asmMethod.getName(), asmMethod.getDescriptor(), jvmSignature.getGenericsSignature(), null); // for maxLocals calculation MethodVisitor maxCalcAdapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node); MethodContext methodContext = context.getParentContext().intoFunction(functionDescriptor); SMAP smap; if (callDefault) { Type implementationOwner = typeMapper.mapOwner(functionDescriptor); FakeMemberCodegen parentCodegen = new FakeMemberCodegen( codegen.getParentCodegen(), inliningFunction, (FieldOwnerContext) methodContext.getParentContext(), implementationOwner.getInternalName()); FunctionCodegen.generateDefaultImplBody( methodContext, functionDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT, inliningFunction, parentCodegen); smap = createSMAPWithDefaultMapping( inliningFunction, parentCodegen.getOrCreateSourceMapper().getResultMappings()); } else { smap = generateMethodBody( maxCalcAdapter, functionDescriptor, methodContext, inliningFunction, jvmSignature, false); } nodeAndSMAP = new SMAPAndMethodNode(node, smap); maxCalcAdapter.visitMaxs(-1, -1); maxCalcAdapter.visitEnd(); } return nodeAndSMAP; } private InlineResult inlineCall(SMAPAndMethodNode nodeAndSmap) { MethodNode node = nodeAndSmap.getNode(); ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node.instructions); generateClosuresBodies(); // through generation captured parameters will be added to invocationParamBuilder putClosureParametersOnStack(); addInlineMarker(codegen.v, true); Parameters parameters = invocationParamBuilder.buildParameters(); InliningContext info = new RootInliningContext( expressionMap, state, codegen.getInlineNameGenerator().subGenerator(functionDescriptor.getName().asString()), codegen.getContext(), callElement, codegen.getParentCodegen().getClassName(), reifiedTypeInliner); MethodInliner inliner = new MethodInliner( node, parameters, info, new FieldRemapper(null, null, parameters), isSameModule, "Method inlining " + callElement.getText(), createNestedSourceMapper(nodeAndSmap)); // with captured LocalVarRemapper remapper = new LocalVarRemapper(parameters, initialFrameSize); MethodNode adapter = InlineCodegenUtil.createEmptyMethodNode(); // hack to keep linenumber info, otherwise jdi will skip begin of linenumber chain adapter.visitInsn(Opcodes.NOP); InlineResult result = inliner.doInline(adapter, remapper, true, LabelOwner.SKIP_ALL); result.getReifiedTypeParametersUsages().mergeAll(reificationResult); CallableMemberDescriptor descriptor = codegen.getContext().getContextDescriptor(); final Set<String> labels = getDeclarationLabels( DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor); LabelOwner labelOwner = new LabelOwner() { @Override public boolean isMyLabel(@NotNull String name) { return labels.contains(name); } }; List<MethodInliner.PointForExternalFinallyBlocks> infos = MethodInliner.processReturns(adapter, labelOwner, true, null); generateAndInsertFinallyBlocks( adapter, infos, ((StackValue.Local) remapper.remap(parameters.totalSize() + 1).value).index); removeFinallyMarkers(adapter); adapter.accept(new InliningInstructionAdapter(codegen.v)); addInlineMarker(codegen.v, false); return result; } private void generateClosuresBodies() { for (LambdaInfo info : expressionMap.values()) { info.setNode(generateLambdaBody(info)); } } private SMAPAndMethodNode generateLambdaBody(LambdaInfo info) { JetExpression declaration = info.getFunctionWithBodyOrCallableReference(); FunctionDescriptor descriptor = info.getFunctionDescriptor(); MethodContext parentContext = codegen.getContext(); MethodContext context = parentContext.intoClosure(descriptor, codegen, typeMapper).intoInlinedLambda(descriptor); JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature(descriptor); Method asmMethod = jvmMethodSignature.getAsmMethod(); MethodNode methodNode = new MethodNode( InlineCodegenUtil.API, getMethodAsmFlags(descriptor, context.getContextKind()), asmMethod.getName(), asmMethod.getDescriptor(), jvmMethodSignature.getGenericsSignature(), null); MethodVisitor adapter = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode); SMAP smap = generateMethodBody(adapter, descriptor, context, declaration, jvmMethodSignature, true); adapter.visitMaxs(-1, -1); return new SMAPAndMethodNode(methodNode, smap); } private SMAP generateMethodBody( @NotNull MethodVisitor adapter, @NotNull FunctionDescriptor descriptor, @NotNull MethodContext context, @NotNull JetExpression expression, @NotNull JvmMethodSignature jvmMethodSignature, boolean isLambda) { FakeMemberCodegen parentCodegen = new FakeMemberCodegen( codegen.getParentCodegen(), expression, (FieldOwnerContext) context.getParentContext(), isLambda ? codegen.getParentCodegen().getClassName() : typeMapper.mapOwner(descriptor).getInternalName()); FunctionGenerationStrategy strategy = expression instanceof JetCallableReferenceExpression ? new FunctionReferenceGenerationStrategy( state, descriptor, CallUtilKt.getResolvedCallWithAssert( ((JetCallableReferenceExpression) expression).getCallableReference(), codegen.getBindingContext())) : new FunctionGenerationStrategy.FunctionDefault( state, descriptor, (JetDeclarationWithBody) expression); FunctionCodegen.generateMethodBody( adapter, descriptor, context, jvmMethodSignature, strategy, // Wrapping for preventing marking actual parent codegen as containing reifier markers parentCodegen); return createSMAPWithDefaultMapping( expression, parentCodegen.getOrCreateSourceMapper().getResultMappings()); } private static SMAP createSMAPWithDefaultMapping( @NotNull JetExpression declaration, @NotNull List<FileMapping> mappings) { PsiFile containingFile = declaration.getContainingFile(); Integer lineNumbers = CodegenUtil.getLineNumberForElement(containingFile, true); assert lineNumbers != null : "Couldn't extract line count in " + containingFile; return new SMAP(mappings); } private static class FakeMemberCodegen extends MemberCodegen { private final MemberCodegen delegate; @NotNull private final String className; public FakeMemberCodegen( @NotNull MemberCodegen wrapped, @NotNull JetElement declaration, @NotNull FieldOwnerContext codegenContext, @NotNull String className) { super(wrapped, declaration, codegenContext); delegate = wrapped; this.className = className; } @Override protected void generateDeclaration() { throw new IllegalStateException(); } @Override protected void generateBody() { throw new IllegalStateException(); } @Override protected void generateKotlinAnnotation() { throw new IllegalStateException(); } @NotNull @Override public NameGenerator getInlineNameGenerator() { return delegate.getInlineNameGenerator(); } @NotNull @Override // TODO: obtain name from context public String getClassName() { return className; } } @Override public void afterParameterPut( @NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor valueParameterDescriptor) { putCapturedInLocal(type, stackValue, valueParameterDescriptor, -1); } private void putCapturedInLocal( @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 boolean couldBeRemapped = !shouldPutValue(type, stackValue, valueParameterDescriptor); StackValue remappedIndex = couldBeRemapped ? stackValue : null; ParameterInfo info; if (capturedParamIndex >= 0) { CapturedParamDesc capturedParamInfoInLambda = activeLambda.getCapturedVars().get(capturedParamIndex); info = invocationParamBuilder.addCapturedParam( capturedParamInfoInLambda, capturedParamInfoInLambda.getFieldName()); info.setRemapValue(remappedIndex); } else { info = invocationParamBuilder.addNextParameter(type, false, remappedIndex); } putParameterOnStack(info); } } /*descriptor is null for captured vars*/ public boolean shouldPutValue( @NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor descriptor) { if (stackValue == null) { // default or vararg return true; } // remap only inline functions (and maybe non primitives) // TODO - clean asserion and remapping logic if (isPrimitive(type) != isPrimitive(stackValue.type)) { // don't remap boxing/unboxing primitives - lost identity and perfomance return true; } if (stackValue instanceof StackValue.Local) { return false; } StackValue field = stackValue; if (stackValue instanceof StackValue.FieldForSharedVar) { field = ((StackValue.FieldForSharedVar) stackValue).receiver; } // check that value corresponds to captured inlining parameter if (field instanceof StackValue.Field) { DeclarationDescriptor varDescriptor = ((StackValue.Field) field).descriptor; // check that variable is inline function parameter return !(varDescriptor instanceof ParameterDescriptor && InlineUtil.isInlineLambdaParameter((ParameterDescriptor) varDescriptor) && InlineUtil.isInline(varDescriptor.getContainingDeclaration())); } return true; } private void putParameterOnStack(ParameterInfo... infos) { int[] index = new int[infos.length]; for (int i = 0; i < infos.length; i++) { ParameterInfo info = infos[i]; if (!info.isSkippedOrRemapped()) { index[i] = codegen.getFrameMap().enterTemp(info.getType()); } else { index[i] = -1; } } for (int i = infos.length - 1; i >= 0; i--) { ParameterInfo info = infos[i]; if (!info.isSkippedOrRemapped()) { Type type = info.type; StackValue.local(index[i], type).store(StackValue.onStack(type), codegen.v); } } } @Override public void putHiddenParams() { List<JvmMethodParameterSignature> valueParameters = jvmSignature.getValueParameters(); if (!isStaticMethod(functionDescriptor, context)) { invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false, null); } for (JvmMethodParameterSignature param : valueParameters) { if (param.getKind() == JvmMethodParameterKind.VALUE) { break; } invocationParamBuilder.addNextParameter(param.getAsmType(), false, null); } List<ParameterInfo> infos = invocationParamBuilder.listNotCaptured(); putParameterOnStack(infos.toArray(new ParameterInfo[infos.size()])); } public void leaveTemps() { FrameMap frameMap = codegen.getFrameMap(); List<ParameterInfo> infos = invocationParamBuilder.listAllParams(); for (ListIterator<? extends ParameterInfo> iterator = infos.listIterator(infos.size()); iterator.hasPrevious(); ) { ParameterInfo param = iterator.previous(); if (!param.isSkippedOrRemapped()) { frameMap.leaveTemp(param.type); } } } /*lambda or callable reference*/ public static boolean isInliningParameter( JetExpression expression, ValueParameterDescriptor valueParameterDescriptor) { // TODO deparenthisise typed JetExpression deparenthesized = JetPsiUtil.deparenthesize(expression); return InlineUtil.isInlineLambdaParameter(valueParameterDescriptor) && isInlinableParameterExpression(deparenthesized); } protected static boolean isInlinableParameterExpression(JetExpression deparenthesized) { return deparenthesized instanceof JetFunctionLiteralExpression || deparenthesized instanceof JetNamedFunction || deparenthesized instanceof JetCallableReferenceExpression; } public void rememberClosure(JetExpression expression, Type type) { JetExpression lambda = JetPsiUtil.deparenthesize(expression); assert isInlinableParameterExpression(lambda) : "Couldn't find inline expression in " + expression.getText(); LambdaInfo info = new LambdaInfo(lambda, typeMapper); ParameterInfo closureInfo = invocationParamBuilder.addNextParameter(type, true, null); closureInfo.setLambda(info); expressionMap.put(closureInfo.getIndex(), info); } @NotNull protected static Set<String> getDeclarationLabels( @Nullable PsiElement lambdaOrFun, @NotNull DeclarationDescriptor descriptor) { Set<String> result = new HashSet<String>(); if (lambdaOrFun != null) { Name label = LabelResolver.INSTANCE.getLabelNameIfAny(lambdaOrFun); if (label != null) { result.add(label.asString()); } } if (!isFunctionLiteral(descriptor)) { if (!descriptor.getName().isSpecial()) { result.add(descriptor.getName().asString()); } result.add(InlineCodegenUtil.FIRST_FUN_LABEL); } return result; } private void putClosureParametersOnStack() { for (LambdaInfo next : expressionMap.values()) { activeLambda = next; codegen.pushClosureOnStack(next.getClassDescriptor(), true, this); } activeLambda = null; } public static CodegenContext getContext(DeclarationDescriptor descriptor, GenerationState state) { if (descriptor instanceof PackageFragmentDescriptor) { return new PackageContext( (PackageFragmentDescriptor) descriptor, state.getRootContext(), null); } CodegenContext parent = getContext(descriptor.getContainingDeclaration(), state); if (descriptor instanceof ClassDescriptor) { OwnerKind kind = DescriptorUtils.isInterface(descriptor) ? OwnerKind.DEFAULT_IMPLS : OwnerKind.IMPLEMENTATION; return parent.intoClass((ClassDescriptor) descriptor, kind, state); } else if (descriptor instanceof ScriptDescriptor) { ClassDescriptor classDescriptorForScript = state.getBindingContext().get(CLASS_FOR_SCRIPT, (ScriptDescriptor) descriptor); assert classDescriptorForScript != null : "Can't find class for script: " + descriptor; List<ScriptDescriptor> earlierScripts = state.getEarlierScriptsForReplInterpreter(); return parent.intoScript( (ScriptDescriptor) descriptor, earlierScripts == null ? Collections.emptyList() : earlierScripts, classDescriptorForScript); } else if (descriptor instanceof FunctionDescriptor) { return parent.intoFunction((FunctionDescriptor) descriptor); } throw new IllegalStateException("Couldn't build context for " + descriptorName(descriptor)); } private static boolean isStaticMethod( FunctionDescriptor functionDescriptor, MethodContext context) { return (getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) != 0; } 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) { if (isInliningParameter(argumentExpression, valueParameterDescriptor)) { rememberClosure(argumentExpression, parameterType); } else { StackValue value = codegen.gen(argumentExpression); putValueIfNeeded(valueParameterDescriptor, parameterType, value); } } @Override public void putValueIfNeeded( @Nullable ValueParameterDescriptor valueParameterDescriptor, @NotNull Type parameterType, @NotNull StackValue value) { 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); } public void generateAndInsertFinallyBlocks( @NotNull MethodNode intoNode, @NotNull List<MethodInliner.PointForExternalFinallyBlocks> insertPoints, int offsetForFinallyLocalVar) { if (!codegen.hasFinallyBlocks()) return; Map<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks> extensionPoints = new HashMap<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks>(); for (MethodInliner.PointForExternalFinallyBlocks insertPoint : insertPoints) { extensionPoints.put(insertPoint.beforeIns, insertPoint); } DefaultProcessor processor = new DefaultProcessor(intoNode, offsetForFinallyLocalVar); int curFinallyDepth = 0; AbstractInsnNode curInstr = intoNode.instructions.getFirst(); while (curInstr != null) { processor.processInstruction(curInstr, true); if (InlineCodegenUtil.isFinallyStart(curInstr)) { // TODO depth index calc could be more precise curFinallyDepth = getConstant(curInstr.getPrevious()); } MethodInliner.PointForExternalFinallyBlocks extension = extensionPoints.get(curInstr); if (extension != null) { Label start = new Label(); MethodNode finallyNode = InlineCodegenUtil.createEmptyMethodNode(); finallyNode.visitLabel(start); ExpressionCodegen finallyCodegen = new ExpressionCodegen( finallyNode, codegen.getFrameMap(), codegen.getReturnType(), codegen.getContext(), codegen.getState(), codegen.getParentCodegen()); finallyCodegen.addBlockStackElementsForNonLocalReturns( codegen.getBlockStackElements(), curFinallyDepth); FrameMap frameMap = finallyCodegen.getFrameMap(); FrameMap.Mark mark = frameMap.mark(); while (frameMap.getCurrentSize() < processor.getNextFreeLocalIndex()) { frameMap.enterTemp(Type.INT_TYPE); } finallyCodegen.generateFinallyBlocksIfNeeded( extension.returnType, extension.finallyIntervalEnd.getLabel()); // Exception table for external try/catch/finally blocks will be generated in original // codegen after exiting this method InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr); SimpleInterval splitBy = new SimpleInterval((LabelNode) start.info, extension.finallyIntervalEnd); processor.getTryBlocksMetaInfo().splitCurrentIntervals(splitBy, true); // processor.getLocalVarsMetaInfo().splitAndRemoveIntervalsFromCurrents(splitBy); mark.dropTo(); } curInstr = curInstr.getNext(); } processor.substituteTryBlockNodes(intoNode); // processor.substituteLocalVarTable(intoNode); } public void removeFinallyMarkers(@NotNull MethodNode intoNode) { if (InlineCodegenUtil.isFinallyMarkerRequired(codegen.getContext())) return; InsnList instructions = intoNode.instructions; AbstractInsnNode curInstr = instructions.getFirst(); while (curInstr != null) { if (InlineCodegenUtil.isFinallyMarker(curInstr)) { AbstractInsnNode marker = curInstr; // just to assert getConstant(marker.getPrevious()); curInstr = curInstr.getNext(); instructions.remove(marker.getPrevious()); instructions.remove(marker); continue; } curInstr = curInstr.getNext(); } } private SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap) { return new NestedSourceMapper( sourceMapper, nodeAndSmap.getRanges(), nodeAndSmap.getClassSMAP().getSourceInfo()); } private void reportIncrementalInfo( @NotNull FunctionDescriptor sourceDescriptor, @NotNull FunctionDescriptor targetDescriptor) { IncrementalCompilationComponents incrementalCompilationComponents = state.getIncrementalCompilationComponents(); TargetId targetId = state.getTargetId(); if (incrementalCompilationComponents == null || targetId == null) return; IncrementalCache incrementalCache = incrementalCompilationComponents.getIncrementalCache(targetId); String sourceFile = getClassFilePath(sourceDescriptor, incrementalCache); String targetFile = getSourceFilePath(targetDescriptor); incrementalCache.registerInline(sourceFile, jvmSignature.toString(), targetFile); } }
private InlineResult inlineCall(SMAPAndMethodNode nodeAndSmap) { MethodNode node = nodeAndSmap.getNode(); ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node.instructions); generateClosuresBodies(); // through generation captured parameters will be added to invocationParamBuilder putClosureParametersOnStack(); addInlineMarker(codegen.v, true); Parameters parameters = invocationParamBuilder.buildParameters(); InliningContext info = new RootInliningContext( expressionMap, state, codegen.getInlineNameGenerator().subGenerator(functionDescriptor.getName().asString()), codegen.getContext(), callElement, codegen.getParentCodegen().getClassName(), reifiedTypeInliner); MethodInliner inliner = new MethodInliner( node, parameters, info, new FieldRemapper(null, null, parameters), isSameModule, "Method inlining " + callElement.getText(), createNestedSourceMapper(nodeAndSmap)); // with captured LocalVarRemapper remapper = new LocalVarRemapper(parameters, initialFrameSize); MethodNode adapter = InlineCodegenUtil.createEmptyMethodNode(); // hack to keep linenumber info, otherwise jdi will skip begin of linenumber chain adapter.visitInsn(Opcodes.NOP); InlineResult result = inliner.doInline(adapter, remapper, true, LabelOwner.SKIP_ALL); result.getReifiedTypeParametersUsages().mergeAll(reificationResult); CallableMemberDescriptor descriptor = codegen.getContext().getContextDescriptor(); final Set<String> labels = getDeclarationLabels( DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor); LabelOwner labelOwner = new LabelOwner() { @Override public boolean isMyLabel(@NotNull String name) { return labels.contains(name); } }; List<MethodInliner.PointForExternalFinallyBlocks> infos = MethodInliner.processReturns(adapter, labelOwner, true, null); generateAndInsertFinallyBlocks( adapter, infos, ((StackValue.Local) remapper.remap(parameters.totalSize() + 1).value).index); removeFinallyMarkers(adapter); adapter.accept(new InliningInstructionAdapter(codegen.v)); addInlineMarker(codegen.v, false); return result; }