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()); }
private void endCall(@NotNull InlineResult result) { leaveTemps(); codegen.propagateChildReifiedTypeParametersUsages(result.getReifiedTypeParametersUsages()); state.getFactory().removeInlinedClasses(result.getClassesToRemove()); codegen.markLineNumberAfterInlineIfNeeded(); }
private void putClosureParametersOnStack() { for (LambdaInfo next : expressionMap.values()) { activeLambda = next; codegen.pushClosureOnStack(next.getClassDescriptor(), true, this); } activeLambda = null; }
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); }
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); } } }
@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); } }
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()); }
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 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); } } }
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); }
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; }
@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; }
public static void generateDefaultImplBody( @NotNull MethodContext methodContext, @NotNull FunctionDescriptor functionDescriptor, @NotNull MethodVisitor mv, @NotNull DefaultParameterValueLoader loadStrategy, @Nullable KtNamedFunction function, @NotNull MemberCodegen<?> parentCodegen, @NotNull Method defaultMethod) { GenerationState state = parentCodegen.state; JvmMethodSignature signature = state.getTypeMapper().mapSignature(functionDescriptor, methodContext.getContextKind()); boolean isStatic = isStaticMethod(methodContext.getContextKind(), functionDescriptor); FrameMap frameMap = createFrameMap(state, functionDescriptor, signature, isStatic); ExpressionCodegen codegen = new ExpressionCodegen( mv, frameMap, signature.getReturnType(), methodContext, state, parentCodegen); CallGenerator generator = codegen.getOrCreateCallGeneratorForDefaultImplBody(functionDescriptor, function); InstructionAdapter iv = new InstructionAdapter(mv); genDefaultSuperCallCheckIfNeeded(iv, defaultMethod); loadExplicitArgumentsOnStack(OBJECT_TYPE, isStatic, signature, generator); List<JvmMethodParameterSignature> mappedParameters = signature.getValueParameters(); int capturedArgumentsCount = 0; while (capturedArgumentsCount < mappedParameters.size() && mappedParameters.get(capturedArgumentsCount).getKind() != JvmMethodParameterKind.VALUE) { capturedArgumentsCount++; } int maskIndex = 0; List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters(); for (int index = 0; index < valueParameters.size(); index++) { if (index % Integer.SIZE == 0) { maskIndex = frameMap.enterTemp(Type.INT_TYPE); } ValueParameterDescriptor parameterDescriptor = valueParameters.get(index); Type type = mappedParameters.get(capturedArgumentsCount + index).getAsmType(); int parameterIndex = frameMap.getIndex(parameterDescriptor); if (parameterDescriptor.declaresDefaultValue()) { iv.load(maskIndex, Type.INT_TYPE); iv.iconst(1 << (index % Integer.SIZE)); iv.and(Type.INT_TYPE); Label loadArg = new Label(); iv.ifeq(loadArg); StackValue.local(parameterIndex, type) .store(loadStrategy.genValue(parameterDescriptor, codegen), iv); iv.mark(loadArg); } generator.putValueIfNeeded(type, StackValue.local(parameterIndex, type)); } CallableMethod method = state.getTypeMapper().mapToCallableMethod(functionDescriptor, false); generator.genCallWithoutAssertions(method, codegen); iv.areturn(signature.getReturnType()); }