@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;
  }
 @NotNull
 private InlineResult inlineMethodAndUpdateGlobalResult(
     @NotNull AnonymousObjectGeneration anonymousObjectGen,
     @NotNull FieldRemapper parentRemapper,
     @NotNull MethodVisitor deferringVisitor,
     @NotNull MethodNode next,
     @NotNull ParametersBuilder allCapturedParamBuilder,
     boolean isConstructor) {
   InlineResult funResult =
       inlineMethod(
           anonymousObjectGen,
           parentRemapper,
           deferringVisitor,
           next,
           allCapturedParamBuilder,
           isConstructor);
   transformationResult.addAllClassesToRemove(funResult);
   transformationResult
       .getReifiedTypeParametersUsages()
       .mergeAll(funResult.getReifiedTypeParametersUsages());
   return funResult;
 }
  public AnonymousObjectTransformer(
      @NotNull String objectInternalName,
      @NotNull InliningContext inliningContext,
      boolean isSameModule,
      @NotNull Type newLambdaType) {
    this.isSameModule = isSameModule;
    this.state = inliningContext.state;
    this.typeMapper = state.getTypeMapper();
    this.inliningContext = inliningContext;
    this.oldObjectType = Type.getObjectType(objectInternalName);
    this.newLambdaType = newLambdaType;

    reader = InlineCodegenUtil.buildClassReaderByInternalName(state, objectInternalName);
    transformationResult = InlineResult.create();
  }
예제 #4
0
 /*
  *
  * @param node
  * @param parameters
  * @param inliningContext
  * @param lambdaType - in case on lambda 'invoke' inlining
  */
 public MethodInliner(
     @NotNull MethodNode node,
     @NotNull Parameters parameters,
     @NotNull InliningContext parent,
     @NotNull FieldRemapper nodeRemapper,
     boolean isSameModule,
     @NotNull String errorPrefix) {
   this.node = node;
   this.parameters = parameters;
   this.inliningContext = parent;
   this.nodeRemapper = nodeRemapper;
   this.isSameModule = isSameModule;
   this.errorPrefix = errorPrefix;
   this.typeMapper = parent.state.getTypeMapper();
   this.result = InlineResult.create();
 }
  @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;
  }