예제 #1
0
  @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);
  }