@NotNull public MethodNode prepareNode(@NotNull MethodNode node) { final int capturedParamsSize = parameters.getCaptured().size(); final int realParametersSize = parameters.getReal().size(); Type[] types = Type.getArgumentTypes(node.desc); Type returnType = Type.getReturnType(node.desc); ArrayList<Type> capturedTypes = parameters.getCapturedTypes(); Type[] allTypes = ArrayUtil.mergeArrays(types, capturedTypes.toArray(new Type[capturedTypes.size()])); node.instructions.resetLabels(); MethodNode transformedNode = new MethodNode( InlineCodegenUtil.API, node.access, node.name, Type.getMethodDescriptor(returnType, allTypes), node.signature, null) { private final boolean isInliningLambda = nodeRemapper.isInsideInliningLambda(); private int getNewIndex(int var) { return var + (var < realParametersSize ? 0 : capturedParamsSize); } @Override public void visitVarInsn(int opcode, int var) { super.visitVarInsn(opcode, getNewIndex(var)); } @Override public void visitIincInsn(int var, int increment) { super.visitIincInsn(getNewIndex(var), increment); } @Override public void visitMaxs(int maxStack, int maxLocals) { super.visitMaxs(maxStack, maxLocals + capturedParamsSize); } @Override public void visitLineNumber(int line, @NotNull Label start) { if (isInliningLambda) { super.visitLineNumber(line, start); } } @Override public void visitLocalVariable( @NotNull String name, @NotNull String desc, String signature, @NotNull Label start, @NotNull Label end, int index) { if (isInliningLambda) { super.visitLocalVariable(name, desc, signature, start, end, getNewIndex(index)); } } }; node.accept(transformedNode); transformCaptured(transformedNode); return transformedNode; }
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); }