Ejemplo n.º 1
0
  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();
  }
Ejemplo n.º 2
0
  private List<CapturedParamInfo> extractParametersMappingAndPatchConstructor(
      @NotNull MethodNode constructor,
      @NotNull ParametersBuilder capturedParamBuilder,
      @NotNull ParametersBuilder constructorParamBuilder,
      @NotNull final AnonymousObjectGeneration anonymousObjectGen,
      @NotNull FieldRemapper parentFieldRemapper) {

    CapturedParamOwner owner =
        new CapturedParamOwner() {
          @Override
          public Type getType() {
            return Type.getObjectType(anonymousObjectGen.getOwnerInternalName());
          }
        };

    Set<LambdaInfo> capturedLambdas =
        new LinkedHashSet<LambdaInfo>(); // captured var of inlined parameter
    List<CapturedParamInfo> constructorAdditionalFakeParams = new ArrayList<CapturedParamInfo>();
    Map<Integer, LambdaInfo> indexToLambda = anonymousObjectGen.getLambdasToInline();
    Set<Integer> capturedParams = new HashSet<Integer>();

    // load captured parameters and patch instruction list (NB: there is also could be object
    // fields)
    AbstractInsnNode cur = constructor.instructions.getFirst();
    while (cur != null) {
      if (cur instanceof FieldInsnNode) {
        FieldInsnNode fieldNode = (FieldInsnNode) cur;
        String fieldName = fieldNode.name;
        if (fieldNode.getOpcode() == Opcodes.PUTFIELD
            && InlineCodegenUtil.isCapturedFieldName(fieldName)) {

          boolean isPrevVarNode = fieldNode.getPrevious() instanceof VarInsnNode;
          boolean isPrevPrevVarNode =
              isPrevVarNode && fieldNode.getPrevious().getPrevious() instanceof VarInsnNode;

          if (isPrevPrevVarNode) {
            VarInsnNode node = (VarInsnNode) fieldNode.getPrevious().getPrevious();
            if (node.var == 0) {
              VarInsnNode previous = (VarInsnNode) fieldNode.getPrevious();
              int varIndex = previous.var;
              LambdaInfo lambdaInfo = indexToLambda.get(varIndex);
              String newFieldName =
                  isThis0(fieldName)
                          && shouldRenameThis0(parentFieldRemapper, indexToLambda.values())
                      ? getNewFieldName(fieldName, true)
                      : fieldName;
              CapturedParamInfo info =
                  capturedParamBuilder.addCapturedParam(
                      owner,
                      fieldName,
                      newFieldName,
                      Type.getType(fieldNode.desc),
                      lambdaInfo != null,
                      null);
              if (lambdaInfo != null) {
                info.setLambda(lambdaInfo);
                capturedLambdas.add(lambdaInfo);
              }
              constructorAdditionalFakeParams.add(info);
              capturedParams.add(varIndex);

              constructor.instructions.remove(previous.getPrevious());
              constructor.instructions.remove(previous);
              AbstractInsnNode temp = cur;
              cur = cur.getNext();
              constructor.instructions.remove(temp);
              continue;
            }
          }
        }
      }
      cur = cur.getNext();
    }

    constructorParamBuilder.addThis(oldObjectType, false);
    String constructorDesc = anonymousObjectGen.getConstructorDesc();

    if (constructorDesc == null) {
      // in case of anonymous object with empty closure
      constructorDesc = Type.getMethodDescriptor(Type.VOID_TYPE);
    }

    Type[] types = Type.getArgumentTypes(constructorDesc);
    for (Type type : types) {
      LambdaInfo info = indexToLambda.get(constructorParamBuilder.getNextValueParameterIndex());
      ParameterInfo parameterInfo =
          constructorParamBuilder.addNextParameter(type, info != null, null);
      parameterInfo.setLambda(info);
      if (capturedParams.contains(parameterInfo.getIndex())) {
        parameterInfo.setCaptured(true);
      } else {
        // otherwise it's super constructor parameter
      }
    }

    // For all inlined lambdas add their captured parameters
    // TODO: some of such parameters could be skipped - we should perform additional analysis
    Map<String, LambdaInfo> capturedLambdasToInline =
        new HashMap<String, LambdaInfo>(); // captured var of inlined parameter
    List<CapturedParamDesc> allRecapturedParameters = new ArrayList<CapturedParamDesc>();
    boolean addCapturedNotAddOuter =
        parentFieldRemapper.isRoot()
            || (parentFieldRemapper instanceof InlinedLambdaRemapper
                && parentFieldRemapper.getParent().isRoot());
    Map<String, CapturedParamInfo> alreadyAdded = new HashMap<String, CapturedParamInfo>();
    for (LambdaInfo info : capturedLambdas) {
      if (addCapturedNotAddOuter) {
        for (CapturedParamDesc desc : info.getCapturedVars()) {
          String key = desc.getFieldName() + "$$$" + desc.getType().getClassName();
          CapturedParamInfo alreadyAddedParam = alreadyAdded.get(key);

          CapturedParamInfo recapturedParamInfo =
              capturedParamBuilder.addCapturedParam(
                  desc,
                  alreadyAddedParam != null
                      ? alreadyAddedParam.getNewFieldName()
                      : getNewFieldName(desc.getFieldName(), false));
          StackValue composed =
              StackValue.field(
                  desc.getType(),
                  oldObjectType, /*TODO owner type*/
                  recapturedParamInfo.getNewFieldName(),
                  false,
                  StackValue.LOCAL_0);
          recapturedParamInfo.setRemapValue(composed);
          allRecapturedParameters.add(desc);

          constructorParamBuilder
              .addCapturedParam(recapturedParamInfo, recapturedParamInfo.getNewFieldName())
              .setRemapValue(composed);
          if (alreadyAddedParam != null) {
            recapturedParamInfo.setSkipInConstructor(true);
          }

          if (isThis0(desc.getFieldName())) {
            alreadyAdded.put(key, recapturedParamInfo);
          }
        }
      }
      capturedLambdasToInline.put(info.getLambdaClassType().getInternalName(), info);
    }

    if (parentFieldRemapper instanceof InlinedLambdaRemapper
        && !capturedLambdas.isEmpty()
        && !addCapturedNotAddOuter) {
      // lambda with non InlinedLambdaRemapper already have outer
      FieldRemapper parent = parentFieldRemapper.getParent();
      assert parent instanceof RegeneratedLambdaFieldRemapper;
      final Type ownerType = Type.getObjectType(parent.getLambdaInternalName());

      CapturedParamDesc desc =
          new CapturedParamDesc(
              new CapturedParamOwner() {
                @Override
                public Type getType() {
                  return ownerType;
                }
              },
              InlineCodegenUtil.THIS,
              ownerType);
      CapturedParamInfo recapturedParamInfo =
          capturedParamBuilder.addCapturedParam(
              desc, InlineCodegenUtil.THIS$0 /*outer lambda/object*/);
      StackValue composed = StackValue.LOCAL_0;
      recapturedParamInfo.setRemapValue(composed);
      allRecapturedParameters.add(desc);

      constructorParamBuilder
          .addCapturedParam(recapturedParamInfo, recapturedParamInfo.getNewFieldName())
          .setRemapValue(composed);
    }

    anonymousObjectGen.setAllRecapturedParameters(allRecapturedParameters);
    anonymousObjectGen.setCapturedLambdasToInline(capturedLambdasToInline);

    return constructorAdditionalFakeParams;
  }
  @Override
  public BasicValue newOperation(@NotNull AbstractInsnNode insn) throws AnalyzerException {
    if (insn.getOpcode() == Opcodes.ACONST_NULL) {
      return newValue(Type.getObjectType("java/lang/Object"));
    }

    switch (insn.getOpcode()) {
      case ACONST_NULL:
        return newValue(Type.getObjectType("null"));
      case ICONST_M1:
      case ICONST_0:
      case ICONST_1:
      case ICONST_2:
      case ICONST_3:
      case ICONST_4:
      case ICONST_5:
        return StrictBasicValue.INT_VALUE;
      case LCONST_0:
      case LCONST_1:
        return StrictBasicValue.LONG_VALUE;
      case FCONST_0:
      case FCONST_1:
      case FCONST_2:
        return StrictBasicValue.FLOAT_VALUE;
      case DCONST_0:
      case DCONST_1:
        return StrictBasicValue.DOUBLE_VALUE;
      case BIPUSH:
      case SIPUSH:
        return StrictBasicValue.INT_VALUE;
      case LDC:
        Object cst = ((LdcInsnNode) insn).cst;
        if (cst instanceof Integer) {
          return StrictBasicValue.INT_VALUE;
        } else if (cst instanceof Float) {
          return StrictBasicValue.FLOAT_VALUE;
        } else if (cst instanceof Long) {
          return StrictBasicValue.LONG_VALUE;
        } else if (cst instanceof Double) {
          return StrictBasicValue.DOUBLE_VALUE;
        } else if (cst instanceof String) {
          return newValue(Type.getObjectType("java/lang/String"));
        } else if (cst instanceof Type) {
          int sort = ((Type) cst).getSort();
          if (sort == Type.OBJECT || sort == Type.ARRAY) {
            return newValue(Type.getObjectType("java/lang/Class"));
          } else if (sort == Type.METHOD) {
            return newValue(Type.getObjectType("java/lang/invoke/MethodType"));
          } else {
            throw new IllegalArgumentException("Illegal LDC constant " + cst);
          }
        } else if (cst instanceof Handle) {
          return newValue(Type.getObjectType("java/lang/invoke/MethodHandle"));
        } else {
          throw new IllegalArgumentException("Illegal LDC constant " + cst);
        }
      case GETSTATIC:
        return newValue(Type.getType(((FieldInsnNode) insn).desc));
      case NEW:
        return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
      default:
        throw new Error("Internal error.");
    }
  }
 private static String getClassName(final String name) {
   return getTypeText(Type.getObjectType(name));
 }
 @Override
 public BasicValue unaryOperation(AbstractInsnNode insn, BasicValue value)
     throws AnalyzerException {
   switch (insn.getOpcode()) {
     case INEG:
     case IINC:
     case L2I:
     case F2I:
     case D2I:
     case I2B:
     case I2C:
     case I2S:
       return StrictBasicValue.INT_VALUE;
     case FNEG:
     case I2F:
     case L2F:
     case D2F:
       return StrictBasicValue.FLOAT_VALUE;
     case LNEG:
     case I2L:
     case F2L:
     case D2L:
       return StrictBasicValue.LONG_VALUE;
     case DNEG:
     case I2D:
     case L2D:
     case F2D:
       return StrictBasicValue.DOUBLE_VALUE;
     case IFEQ:
     case IFNE:
     case IFLT:
     case IFGE:
     case IFGT:
     case IFLE:
     case TABLESWITCH:
     case LOOKUPSWITCH:
     case IRETURN:
     case LRETURN:
     case FRETURN:
     case DRETURN:
     case ARETURN:
     case PUTSTATIC:
       return null;
     case GETFIELD:
       return newValue(Type.getType(((FieldInsnNode) insn).desc));
     case NEWARRAY:
       switch (((IntInsnNode) insn).operand) {
         case T_BOOLEAN:
           return newValue(Type.getType("[Z"));
         case T_CHAR:
           return newValue(Type.getType("[C"));
         case T_BYTE:
           return newValue(Type.getType("[B"));
         case T_SHORT:
           return newValue(Type.getType("[S"));
         case T_INT:
           return newValue(Type.getType("[I"));
         case T_FLOAT:
           return newValue(Type.getType("[F"));
         case T_DOUBLE:
           return newValue(Type.getType("[D"));
         case T_LONG:
           return newValue(Type.getType("[J"));
         default:
           throw new AnalyzerException(insn, "Invalid array type");
       }
     case ANEWARRAY:
       String desc = ((TypeInsnNode) insn).desc;
       return newValue(Type.getType("[" + Type.getObjectType(desc)));
     case ARRAYLENGTH:
       return StrictBasicValue.INT_VALUE;
     case ATHROW:
       return null;
     case CHECKCAST:
       desc = ((TypeInsnNode) insn).desc;
       return newValue(Type.getObjectType(desc));
     case INSTANCEOF:
       return StrictBasicValue.INT_VALUE;
     case MONITORENTER:
     case MONITOREXIT:
     case IFNULL:
     case IFNONNULL:
       return null;
     default:
       throw new Error("Internal error.");
   }
 }