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 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()); }
void generateDefaultIfNeeded( @NotNull MethodContext owner, @NotNull FunctionDescriptor functionDescriptor, @NotNull OwnerKind kind, @NotNull DefaultParameterValueLoader loadStrategy, @Nullable KtNamedFunction function) { DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration(); if (kind != OwnerKind.DEFAULT_IMPLS && isInterface(contextClass)) { return; } if (!isDefaultNeeded(functionDescriptor)) { return; } int flags = getVisibilityAccessFlag(functionDescriptor) | getDeprecatedAccessFlag(functionDescriptor) | ACC_SYNTHETIC; if (!(functionDescriptor instanceof ConstructorDescriptor)) { flags |= ACC_STATIC | ACC_BRIDGE; } // $default methods are never private to be accessible from other class files (e.g. inner) // without the need of synthetic accessors flags &= ~ACC_PRIVATE; Method defaultMethod = typeMapper.mapDefaultMethod(functionDescriptor, kind); MethodVisitor mv = v.newMethod( JvmDeclarationOriginKt.Synthetic(function, functionDescriptor), flags, defaultMethod.getName(), defaultMethod.getDescriptor(), null, getThrownExceptions(functionDescriptor, typeMapper)); // Only method annotations are copied to the $default method. Parameter annotations are not // copied until there are valid use cases; // enum constructors have two additional synthetic parameters which somewhat complicate this // task AnnotationCodegen.forMethod(mv, typeMapper) .genAnnotations(functionDescriptor, defaultMethod.getReturnType()); if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { if (this.owner instanceof MultifileClassFacadeContext) { mv.visitCode(); generateFacadeDelegateMethodBody( mv, defaultMethod, (MultifileClassFacadeContext) this.owner); endVisit(mv, "default method delegation", getSourceFromDescriptor(functionDescriptor)); } else { mv.visitCode(); generateDefaultImplBody( owner, functionDescriptor, mv, loadStrategy, function, memberCodegen, defaultMethod); endVisit(mv, "default method", getSourceFromDescriptor(functionDescriptor)); } } }
public static void generateMethodBody( @NotNull MethodVisitor mv, @NotNull FunctionDescriptor functionDescriptor, @NotNull MethodContext context, @NotNull JvmMethodSignature signature, @NotNull FunctionGenerationStrategy strategy, @NotNull MemberCodegen<?> parentCodegen) { mv.visitCode(); Label methodBegin = new Label(); mv.visitLabel(methodBegin); JetTypeMapper typeMapper = parentCodegen.typeMapper; Label methodEnd; if (context.getParentContext() instanceof DelegatingFacadeContext) { generateFacadeDelegateMethodBody( mv, signature.getAsmMethod(), (DelegatingFacadeContext) context.getParentContext()); methodEnd = new Label(); } else { FrameMap frameMap = createFrameMap( parentCodegen.state, functionDescriptor, signature, isStaticMethod(context.getContextKind(), functionDescriptor)); Label methodEntry = new Label(); mv.visitLabel(methodEntry); context.setMethodStartLabel(methodEntry); if (!JetTypeMapper.isAccessor(functionDescriptor)) { genNotNullAssertionsForParameters( new InstructionAdapter(mv), parentCodegen.state, functionDescriptor, frameMap); } methodEnd = new Label(); context.setMethodEndLabel(methodEnd); strategy.generateBody(mv, frameMap, signature, context, parentCodegen); } mv.visitLabel(methodEnd); Type thisType = getThisTypeForFunction(functionDescriptor, context, typeMapper); generateLocalVariableTable( mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind()); }
@Nullable private static Type getThisTypeForFunction( @NotNull FunctionDescriptor functionDescriptor, @NotNull MethodContext context, @NotNull JetTypeMapper typeMapper) { ReceiverParameterDescriptor dispatchReceiver = functionDescriptor.getDispatchReceiverParameter(); if (functionDescriptor instanceof ConstructorDescriptor) { return typeMapper.mapType(functionDescriptor); } else if (dispatchReceiver != null) { return typeMapper.mapType(dispatchReceiver.getType()); } else if (isFunctionLiteral(functionDescriptor) || isLocalFunction(functionDescriptor) || isFunctionExpression(functionDescriptor)) { return typeMapper.mapType(context.getThisDescriptor()); } else { return null; } }
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 boolean isStaticMethod( FunctionDescriptor functionDescriptor, MethodContext context) { return (getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) != 0; }
@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()); }
public static void generateMethodBody( @NotNull MethodVisitor mv, @NotNull FunctionDescriptor functionDescriptor, @NotNull MethodContext context, @NotNull JvmMethodSignature signature, @NotNull FunctionGenerationStrategy strategy, @NotNull MemberCodegen<?> parentCodegen) { mv.visitCode(); Label methodBegin = new Label(); mv.visitLabel(methodBegin); JetTypeMapper typeMapper = parentCodegen.typeMapper; if (BuiltinSpecialBridgesUtil.shouldHaveTypeSafeBarrier( functionDescriptor, getSignatureMapper(typeMapper))) { generateTypeCheckBarrierIfNeeded( new InstructionAdapter(mv), functionDescriptor, signature.getReturnType(), /* delegateParameterType = */ null); } Label methodEnd; int functionFakeIndex = -1; int lambdaFakeIndex = -1; if (context.getParentContext() instanceof MultifileClassFacadeContext) { generateFacadeDelegateMethodBody( mv, signature.getAsmMethod(), (MultifileClassFacadeContext) context.getParentContext()); methodEnd = new Label(); } else { FrameMap frameMap = createFrameMap( parentCodegen.state, functionDescriptor, signature, isStaticMethod(context.getContextKind(), functionDescriptor)); if (context.isInlineMethodContext()) { functionFakeIndex = frameMap.enterTemp(Type.INT_TYPE); } if (context instanceof InlineLambdaContext) { lambdaFakeIndex = frameMap.enterTemp(Type.INT_TYPE); } Label methodEntry = new Label(); mv.visitLabel(methodEntry); context.setMethodStartLabel(methodEntry); if (!JetTypeMapper.isAccessor(functionDescriptor)) { genNotNullAssertionsForParameters( new InstructionAdapter(mv), parentCodegen.state, functionDescriptor, frameMap); } methodEnd = new Label(); context.setMethodEndLabel(methodEnd); strategy.generateBody(mv, frameMap, signature, context, parentCodegen); } mv.visitLabel(methodEnd); Type thisType = getThisTypeForFunction(functionDescriptor, context, typeMapper); generateLocalVariableTable( mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind()); if (context.isInlineMethodContext() && functionFakeIndex != -1) { mv.visitLocalVariable( JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION + functionDescriptor.getName().asString(), Type.INT_TYPE.getDescriptor(), null, methodBegin, methodEnd, functionFakeIndex); } if (context instanceof InlineLambdaContext && thisType != null && lambdaFakeIndex != -1) { String name = thisType.getClassName(); int indexOfLambdaOrdinal = name.lastIndexOf("$"); if (indexOfLambdaOrdinal > 0) { int lambdaOrdinal = Integer.parseInt(name.substring(indexOfLambdaOrdinal + 1)); mv.visitLocalVariable( JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT + lambdaOrdinal, Type.INT_TYPE.getDescriptor(), null, methodBegin, methodEnd, lambdaFakeIndex); } } }
public void generateMethod( @NotNull JvmDeclarationOrigin origin, @NotNull FunctionDescriptor functionDescriptor, @NotNull MethodContext methodContext, @NotNull FunctionGenerationStrategy strategy) { OwnerKind contextKind = methodContext.getContextKind(); if (isInterface(functionDescriptor.getContainingDeclaration()) && functionDescriptor.getVisibility() == Visibilities.PRIVATE && contextKind != OwnerKind.DEFAULT_IMPLS) { return; } JvmMethodSignature jvmSignature = typeMapper.mapSignature(functionDescriptor, contextKind); Method asmMethod = jvmSignature.getAsmMethod(); int flags = getMethodAsmFlags(functionDescriptor, contextKind); boolean isNative = NativeKt.hasNativeAnnotation(functionDescriptor); if (isNative && owner instanceof MultifileClassFacadeContext) { // Native methods are only defined in facades and do not need package part implementations return; } MethodVisitor mv = v.newMethod( origin, flags, asmMethod.getName(), asmMethod.getDescriptor(), jvmSignature.getGenericsSignature(), getThrownExceptions(functionDescriptor, typeMapper)); if (CodegenContextUtil.isImplClassOwner(owner)) { v.getSerializationBindings().put(METHOD_FOR_FUNCTION, functionDescriptor, asmMethod); } generateMethodAnnotations(functionDescriptor, asmMethod, mv); generateParameterAnnotations( functionDescriptor, mv, typeMapper.mapSignature(functionDescriptor)); generateBridges(functionDescriptor); boolean staticInCompanionObject = AnnotationUtilKt.isPlatformStaticInCompanionObject(functionDescriptor); if (staticInCompanionObject) { ImplementationBodyCodegen parentBodyCodegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen(); parentBodyCodegen.addAdditionalTask( new JvmStaticGenerator(functionDescriptor, origin, state)); } if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES || isAbstractMethod(functionDescriptor, contextKind)) { generateLocalVariableTable( mv, jvmSignature, functionDescriptor, getThisTypeForFunction(functionDescriptor, methodContext, typeMapper), new Label(), new Label(), contextKind); mv.visitEnd(); return; } if (!isNative) { generateMethodBody( mv, functionDescriptor, methodContext, jvmSignature, strategy, memberCodegen); } else if (staticInCompanionObject) { // native @JvmStatic foo() in companion object should delegate to the static native function // moved to the outer class mv.visitCode(); FunctionDescriptor staticFunctionDescriptor = JvmStaticGenerator.createStaticFunctionDescriptor(functionDescriptor); JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature( memberCodegen.getContext().accessibleDescriptor(staticFunctionDescriptor, null)); Type owningType = typeMapper.mapClass( (ClassifierDescriptor) staticFunctionDescriptor.getContainingDeclaration()); generateDelegateToMethodBody( false, mv, jvmMethodSignature.getAsmMethod(), owningType.getInternalName()); } endVisit(mv, null, origin.getElement()); }
public static boolean isFinallyMarkerRequired(@NotNull MethodContext context) { return context.isInlineFunction() || context.isInliningLambda(); }