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); }
@NotNull protected ExpressionCodegen createOrGetClInitCodegen() { DeclarationDescriptor descriptor = context.getContextDescriptor(); assert state.getClassBuilderMode() == ClassBuilderMode.FULL : "<clinit> should not be generated for light classes. Descriptor: " + descriptor; if (clInit == null) { MethodVisitor mv = v.newMethod(null, ACC_STATIC, "<clinit>", "()V", null, null); mv.visitCode(); SimpleFunctionDescriptorImpl clInit = SimpleFunctionDescriptorImpl.create( descriptor, Annotations.EMPTY, Name.special("<clinit>"), SYNTHESIZED); clInit.initialize( null, null, Collections.<TypeParameterDescriptor>emptyList(), Collections.<ValueParameterDescriptor>emptyList(), null, null, Visibilities.PRIVATE); this.clInit = new ExpressionCodegen( mv, new FrameMap(), Type.VOID_TYPE, context.intoFunction(clInit), state, this); } return clInit; }
private void generateBridge( @Nullable PsiElement origin, @NotNull FunctionDescriptor descriptor, @NotNull Method bridge, @NotNull Method delegateTo, boolean isSpecialBridge, boolean isStubDeclarationWithDelegationToSuper) { boolean isSpecialOrDelegationToSuper = isSpecialBridge || isStubDeclarationWithDelegationToSuper; int flags = ACC_PUBLIC | ACC_BRIDGE | (!isSpecialOrDelegationToSuper ? ACC_SYNTHETIC : 0) | (isSpecialBridge ? ACC_FINAL : 0); // TODO. MethodVisitor mv = v.newMethod( JvmDeclarationOriginKt.Bridge(descriptor, origin), flags, bridge.getName(), bridge.getDescriptor(), null, null); if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; mv.visitCode(); Type[] argTypes = bridge.getArgumentTypes(); Type[] originalArgTypes = delegateTo.getArgumentTypes(); InstructionAdapter iv = new InstructionAdapter(mv); MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv); if (delegateTo.getArgumentTypes().length == 1 && isSpecialBridge) { generateTypeCheckBarrierIfNeeded( iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes()[0]); } iv.load(0, OBJECT_TYPE); for (int i = 0, reg = 1; i < argTypes.length; i++) { StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv); //noinspection AssignmentToForLoopParameter reg += argTypes[i].getSize(); } if (isStubDeclarationWithDelegationToSuper) { ClassDescriptor parentClass = getSuperClassDescriptor((ClassDescriptor) descriptor.getContainingDeclaration()); assert parentClass != null; String parentInternalName = typeMapper.mapClass(parentClass).getInternalName(); iv.invokespecial(parentInternalName, delegateTo.getName(), delegateTo.getDescriptor()); } else { iv.invokevirtual(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor()); } StackValue.coerce(delegateTo.getReturnType(), bridge.getReturnType(), iv); iv.areturn(bridge.getReturnType()); endVisit(mv, "bridge method", origin); }
private void generateConstInstance() { MethodVisitor mv = v.newMethod( OtherOrigin(element, funDescriptor), ACC_STATIC | ACC_SYNTHETIC, "<clinit>", "()V", null, ArrayUtil.EMPTY_STRING_ARRAY); InstructionAdapter iv = new InstructionAdapter(mv); v.newField( OtherOrigin(element, funDescriptor), ACC_STATIC | ACC_FINAL | ACC_PUBLIC, JvmAbi.INSTANCE_FIELD, asmType.getDescriptor(), null, null); if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { mv.visitCode(); iv.anew(asmType); iv.dup(); iv.invokespecial(asmType.getInternalName(), "<init>", "()V", false); iv.putstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor()); mv.visitInsn(RETURN); FunctionCodegen.endVisit(mv, "<clinit>", element); } }
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)); } } }
private void createStaticInitializer() { final MethodVisitor mv = cv.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null); mv.visitCode(); patchStaticInitializer(mv); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); }
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()); }
// verify pattern and add compiled pattern to static cache private void initPatterns(MethodVisitor mv) { mv.visitIntInsn(BIPUSH, myPatterns.size()); mv.visitTypeInsn(ANEWARRAY, "java/util/regex/Pattern"); mv.visitFieldInsn(PUTSTATIC, myClassName, PATTERN_CACHE_NAME, JAVA_UTIL_REGEX_PATTERN); int i = 0; for (String pattern : myPatterns) { // check the pattern so we can rely on the pattern being valid at runtime try { Pattern.compile(pattern); } catch (Exception e) { throw new InstrumentationException("Illegal Pattern: " + pattern, e); } mv.visitFieldInsn(GETSTATIC, myClassName, PATTERN_CACHE_NAME, JAVA_UTIL_REGEX_PATTERN); mv.visitIntInsn(BIPUSH, i++); mv.visitLdcInsn(pattern); mv.visitMethodInsn( INVOKESTATIC, "java/util/regex/Pattern", "compile", "(Ljava/lang/String;)Ljava/util/regex/Pattern;", false); mv.visitInsn(AASTORE); } }
// add assert startup code private void initAssertions(MethodVisitor mv) { mv.visitLdcInsn(Type.getType("L" + myClassName + ";")); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "desiredAssertionStatus", "()Z", false); Label l0 = new Label(); mv.visitJumpInsn(IFNE, l0); mv.visitInsn(ICONST_1); Label l1 = new Label(); mv.visitJumpInsn(GOTO, l1); mv.visitLabel(l0); mv.visitInsn(ICONST_0); mv.visitLabel(l1); mv.visitFieldInsn(PUTSTATIC, myClassName, ASSERTIONS_DISABLED_NAME, "Z"); }
private void generateBridge(@NotNull Method bridge, @NotNull Method delegate) { if (bridge.equals(delegate)) return; MethodVisitor mv = v.newMethod( OtherOrigin(element, funDescriptor), ACC_PUBLIC | ACC_BRIDGE, bridge.getName(), bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY); if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; mv.visitCode(); InstructionAdapter iv = new InstructionAdapter(mv); ImplementationBodyCodegen.markLineNumberForSyntheticFunction( DescriptorUtils.getParentOfType(funDescriptor, ClassDescriptor.class), iv); iv.load(0, asmType); ReceiverParameterDescriptor receiver = funDescriptor.getExtensionReceiverParameter(); int count = 1; if (receiver != null) { StackValue.local(count, bridge.getArgumentTypes()[count - 1]) .put(typeMapper.mapType(receiver.getType()), iv); count++; } List<ValueParameterDescriptor> params = funDescriptor.getValueParameters(); for (ValueParameterDescriptor param : params) { StackValue.local(count, bridge.getArgumentTypes()[count - 1]) .put(typeMapper.mapType(param.getType()), iv); count++; } iv.invokevirtual( asmType.getInternalName(), delegate.getName(), delegate.getDescriptor(), false); StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), iv); iv.areturn(bridge.getReturnType()); FunctionCodegen.endVisit(mv, "bridge", element); }
private static void generateLocalVariableTable( @NotNull MethodVisitor mv, @NotNull JvmMethodSignature jvmMethodSignature, @NotNull FunctionDescriptor functionDescriptor, @Nullable Type thisType, @NotNull Label methodBegin, @NotNull Label methodEnd, @NotNull OwnerKind ownerKind) { Iterator<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters().iterator(); List<JvmMethodParameterSignature> params = jvmMethodSignature.getValueParameters(); int shift = 0; boolean isStatic = AsmUtil.isStaticMethod(ownerKind, functionDescriptor); if (!isStatic) { // add this if (thisType != null) { mv.visitLocalVariable( "this", thisType.getDescriptor(), null, methodBegin, methodEnd, shift); } else { // TODO: provide thisType for callable reference } shift++; } for (int i = 0; i < params.size(); i++) { JvmMethodParameterSignature param = params.get(i); JvmMethodParameterKind kind = param.getKind(); String parameterName; if (kind == JvmMethodParameterKind.VALUE) { ValueParameterDescriptor parameter = valueParameters.next(); parameterName = parameter.getName().asString(); } else { String lowercaseKind = kind.name().toLowerCase(); parameterName = needIndexForVar(kind) ? "$" + lowercaseKind + "$" + i : "$" + lowercaseKind; } Type type = param.getAsmType(); mv.visitLocalVariable( parameterName, type.getDescriptor(), null, methodBegin, methodEnd, shift); shift += type.getSize(); } }
@NotNull private Method generateConstructor(@NotNull Type superClassAsmType) { List<FieldInfo> args = calculateConstructorParameters(typeMapper, closure, asmType); Type[] argTypes = fieldListToTypeArray(args); Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes); MethodVisitor mv = v.newMethod( OtherOrigin(element, funDescriptor), visibilityFlag, "<init>", constructor.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY); if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { mv.visitCode(); InstructionAdapter iv = new InstructionAdapter(mv); int k = 1; for (FieldInfo fieldInfo : args) { k = genAssignInstanceFieldFromParam(fieldInfo, k, iv); } iv.load(0, superClassAsmType); if (superClassAsmType.equals(LAMBDA) || superClassAsmType.equals(FUNCTION_REFERENCE)) { int arity = funDescriptor.getValueParameters().size(); if (funDescriptor.getExtensionReceiverParameter() != null) arity++; if (funDescriptor.getDispatchReceiverParameter() != null) arity++; iv.iconst(arity); iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "(I)V", false); } else { iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "()V", false); } iv.visitInsn(RETURN); FunctionCodegen.endVisit(iv, "constructor", element); } return constructor; }
public static void endVisit( MethodVisitor mv, @Nullable String description, @Nullable PsiElement method) { try { mv.visitMaxs(-1, -1); mv.visitEnd(); } catch (ProcessCanceledException e) { throw e; } catch (Throwable t) { String bytecode = renderByteCodeIfAvailable(mv); throw new CompilationException( "wrong code generated" + (description != null ? " for " + description : "") + t.getClass().getName() + " " + t.getMessage() + (bytecode != null ? "\nbytecode:\n" + bytecode : ""), t, method); } }
private void markEnumOrInnerConstructorParameterAsSynthetic(MethodVisitor mv, int i) { // IDEA's ClsPsi builder fails to annotate synthetic parameters if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return; // This is needed to avoid RuntimeInvisibleParameterAnnotations error in javac: // see MethodWriter.visitParameterAnnotation() AnnotationVisitor av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", true); if (av != null) { av.visitEnd(); } }
@NotNull private InlineResult inlineMethod( @NotNull AnonymousObjectGeneration anonymousObjectGen, @NotNull FieldRemapper parentRemapper, @NotNull MethodVisitor deferringVisitor, @NotNull MethodNode sourceNode, @NotNull ParametersBuilder capturedBuilder, boolean isConstructor) { ReifiedTypeParametersUsages typeParametersToReify = inliningContext.reifedTypeInliner.reifyInstructions(sourceNode); Parameters parameters = isConstructor ? capturedBuilder.buildParameters() : getMethodParametersWithCaptured(capturedBuilder, sourceNode); RegeneratedLambdaFieldRemapper remapper = new RegeneratedLambdaFieldRemapper( oldObjectType.getInternalName(), newLambdaType.getInternalName(), parameters, anonymousObjectGen.getCapturedLambdasToInline(), parentRemapper, isConstructor); MethodInliner inliner = new MethodInliner( sourceNode, parameters, inliningContext.subInline(inliningContext.nameGenerator.subGenerator("lambda")), remapper, isSameModule, "Transformer for " + anonymousObjectGen.getOwnerInternalName(), sourceMapper, new InlineCallSiteInfo( anonymousObjectGen.getOwnerInternalName(), sourceNode.name, isConstructor ? anonymousObjectGen.getNewConstructorDescriptor() : sourceNode.desc)); InlineResult result = inliner.doInline( deferringVisitor, new LocalVarRemapper(parameters, 0), false, LabelOwner.NOT_APPLICABLE); result.getReifiedTypeParametersUsages().mergeAll(typeParametersToReify); deferringVisitor.visitMaxs(-1, -1); return result; }
public void visitLocalVariable( String name, String desc, String signature, Label start, Label end, int index, MethodVisitor mv) { RemapInfo info = doRemap(index); // add entries only for shifted vars or remapped to locals if (SHIFT == info.status || REMAPPED == info.status && info.value instanceof StackValue.Local) { int newIndex = ((StackValue.Local) info.value).index; mv.visitLocalVariable(name, desc, signature, start, end, newIndex); } }
private void writePackageFacadeMethodAnnotationsIfNeeded(MethodVisitor mv) { if (owner instanceof PackageFacadeContext) { PackageFacadeContext packageFacadeContext = (PackageFacadeContext) owner; Type delegateToClassType = packageFacadeContext.getPublicFacadeType(); if (delegateToClassType != null) { String className = delegateToClassType.getClassName(); AnnotationVisitor av = mv.visitAnnotation( AsmUtil.asmDescByFqNameWithoutInnerClasses( JvmAnnotationNames.KOTLIN_DELEGATED_METHOD), true); av.visit(JvmAnnotationNames.IMPLEMENTATION_CLASS_NAME_FIELD_NAME, className); av.visitEnd(); } } }
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()); }
@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; }
@NotNull public InlineResult doTransform( @NotNull AnonymousObjectGeneration anonymousObjectGen, @NotNull FieldRemapper parentRemapper) { final List<InnerClassNode> innerClassNodes = new ArrayList<InnerClassNode>(); ClassBuilder classBuilder = createClassBuilder(); final List<MethodNode> methodsToTransform = new ArrayList<MethodNode>(); reader.accept( new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) { @Override public void visit( int version, int access, @NotNull String name, String signature, String superName, String[] interfaces) { InlineCodegenUtil.assertVersionNotGreaterThanJava6(version, name); super.visit(version, access, name, signature, superName, interfaces); } @Override public void visitInnerClass( @NotNull String name, String outerName, String innerName, int access) { innerClassNodes.add(new InnerClassNode(name, outerName, innerName, access)); } @Override public MethodVisitor visitMethod( int access, @NotNull String name, @NotNull String desc, String signature, String[] exceptions) { MethodNode node = new MethodNode(access, name, desc, signature, exceptions); if (name.equals("<init>")) { if (constructor != null) throw new RuntimeException( "Lambda, SAM or anonymous object should have only one constructor"); constructor = node; } else { methodsToTransform.add(node); } return node; } @Override public FieldVisitor visitField( int access, @NotNull String name, @NotNull String desc, String signature, Object value) { addUniqueField(name); if (InlineCodegenUtil.isCapturedFieldName(name)) { return null; } else { return super.visitField(access, name, desc, signature, value); } } @Override public void visitSource(String source, String debug) { sourceInfo = source; debugInfo = debug; } @Override public void visitEnd() {} }, ClassReader.SKIP_FRAMES); if (!inliningContext.isInliningLambda) { if (debugInfo != null && !debugInfo.isEmpty()) { sourceMapper = SourceMapper.Companion.createFromSmap(SMAPParser.parse(debugInfo)); } else { // seems we can't do any clever mapping cause we don't know any about original class name sourceMapper = IdenticalSourceMapper.INSTANCE; } if (sourceInfo != null && !InlineCodegenUtil.GENERATE_SMAP) { classBuilder.visitSource(sourceInfo, debugInfo); } } else { if (sourceInfo != null) { classBuilder.visitSource(sourceInfo, debugInfo); } sourceMapper = IdenticalSourceMapper.INSTANCE; } ParametersBuilder allCapturedParamBuilder = ParametersBuilder.newBuilder(); ParametersBuilder constructorParamBuilder = ParametersBuilder.newBuilder(); List<CapturedParamInfo> additionalFakeParams = extractParametersMappingAndPatchConstructor( constructor, allCapturedParamBuilder, constructorParamBuilder, anonymousObjectGen, parentRemapper); List<MethodVisitor> deferringMethods = new ArrayList<MethodVisitor>(); for (MethodNode next : methodsToTransform) { MethodVisitor deferringVisitor = newMethod(classBuilder, next); InlineResult funResult = inlineMethodAndUpdateGlobalResult( anonymousObjectGen, parentRemapper, deferringVisitor, next, allCapturedParamBuilder, false); Type returnType = Type.getReturnType(next.desc); if (!AsmUtil.isPrimitive(returnType)) { String oldFunReturnType = returnType.getInternalName(); String newFunReturnType = funResult.getChangedTypes().get(oldFunReturnType); if (newFunReturnType != null) { inliningContext.typeRemapper.addAdditionalMappings(oldFunReturnType, newFunReturnType); } } deferringMethods.add(deferringVisitor); } for (MethodVisitor method : deferringMethods) { method.visitEnd(); } generateConstructorAndFields( classBuilder, allCapturedParamBuilder, constructorParamBuilder, anonymousObjectGen, parentRemapper, additionalFakeParams); SourceMapper.Companion.flushToClassBuilder(sourceMapper, classBuilder); ClassVisitor visitor = classBuilder.getVisitor(); for (InnerClassNode node : innerClassNodes) { visitor.visitInnerClass(node.name, node.outerName, node.innerName, node.access); } writeOuterInfo(visitor); classBuilder.done(); anonymousObjectGen.setNewLambdaType(newLambdaType); return transformationResult; }
private void generateConstructorAndFields( @NotNull ClassBuilder classBuilder, @NotNull ParametersBuilder allCapturedBuilder, @NotNull ParametersBuilder constructorInlineBuilder, @NotNull AnonymousObjectGeneration anonymousObjectGen, @NotNull FieldRemapper parentRemapper, @NotNull List<CapturedParamInfo> constructorAdditionalFakeParams) { List<Type> descTypes = new ArrayList<Type>(); Parameters constructorParams = constructorInlineBuilder.buildParameters(); int[] capturedIndexes = new int[constructorParams.getReal().size() + constructorParams.getCaptured().size()]; int index = 0; int size = 0; // complex processing cause it could have super constructor call params for (ParameterInfo info : constructorParams) { if (!info.isSkipped()) { // not inlined if (info.isCaptured() || info instanceof CapturedParamInfo) { capturedIndexes[index] = size; index++; } if (size != 0) { // skip this descTypes.add(info.getType()); } size += info.getType().getSize(); } } String constructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, descTypes.toArray(new Type[descTypes.size()])); // TODO for inline method make public class anonymousObjectGen.setNewConstructorDescriptor(constructorDescriptor); MethodVisitor constructorVisitor = classBuilder.newMethod( NO_ORIGIN, AsmUtil.NO_FLAG_PACKAGE_PRIVATE, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY); // initialize captured fields List<NewJavaField> newFieldsWithSkipped = TransformationUtilsKt.getNewFieldsToGenerate(allCapturedBuilder.listCaptured()); List<FieldInfo> fieldInfoWithSkipped = TransformationUtilsKt.transformToFieldInfo(newLambdaType, newFieldsWithSkipped); int paramIndex = 0; InstructionAdapter capturedFieldInitializer = new InstructionAdapter(constructorVisitor); for (int i = 0; i < fieldInfoWithSkipped.size(); i++) { FieldInfo fieldInfo = fieldInfoWithSkipped.get(i); if (!newFieldsWithSkipped.get(i).getSkip()) { AsmUtil.genAssignInstanceFieldFromParam( fieldInfo, capturedIndexes[paramIndex], capturedFieldInitializer); } paramIndex++; } // then transform constructor // HACK: in inlinining into constructor we access original captured fields with field access not // local var // but this fields added to general params (this assumes local var access) not captured one, // so we need to add them to captured params for (CapturedParamInfo info : constructorAdditionalFakeParams) { CapturedParamInfo fake = constructorInlineBuilder.addCapturedParamCopy(info); if (fake.getLambda() != null) { // set remap value to skip this fake (captured with lambda already skipped) StackValue composed = StackValue.field( fake.getType(), oldObjectType, fake.getNewFieldName(), false, StackValue.LOCAL_0); fake.setRemapValue(composed); } } inlineMethodAndUpdateGlobalResult( anonymousObjectGen, parentRemapper, capturedFieldInitializer, constructor, constructorInlineBuilder, true); constructorVisitor.visitEnd(); AsmUtil.genClosureFields( TransformationUtilsKt.toNameTypePair( TransformationUtilsKt.filterSkipped(newFieldsWithSkipped)), classBuilder); }
public void visitIincInsn(int var, int increment, MethodVisitor mv) { RemapInfo remap = remap(var); assert remap.value instanceof StackValue.Local; mv.visitIincInsn(((StackValue.Local) remap.value).index, increment); }
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); } } }