Example #1
0
  public RemapInfo doRemap(int index) {
    int remappedIndex;

    if (index < params.getArgsSizeOnStack()) {
      ParameterInfo info = params.getParameterByDeclarationSlot(index);
      StackValue remapped = remapValues[index];
      if (info.isSkipped || remapped == null) {
        return new RemapInfo(info);
      }
      if (info.isRemapped()) {
        return new RemapInfo(remapped, info, REMAPPED);
      } else {
        remappedIndex = ((StackValue.Local) remapped).index;
      }
    } else {
      remappedIndex =
          actualParamsSize
              - params.getArgsSizeOnStack()
              + index; // captured params not used directly in this inlined method, they used in
                       // closure
    }

    return new RemapInfo(
        StackValue.local(remappedIndex + additionalShift, AsmTypes.OBJECT_TYPE), null, SHIFT);
  }
Example #2
0
 @Override
 public void putCapturedValueOnStack(
     @NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex) {
   if (shouldPutValue(stackValue.type, stackValue, null)) {
     stackValue.put(stackValue.type, codegen.v);
   }
   putCapturedInLocal(stackValue.type, stackValue, null, paramIndex);
 }
Example #3
0
 @Override
 public void putValueIfNeeded(
     @Nullable ValueParameterDescriptor valueParameterDescriptor,
     @NotNull Type parameterType,
     @NotNull StackValue value) {
   if (shouldPutValue(parameterType, value, valueParameterDescriptor)) {
     value.put(parameterType, codegen.v);
   }
   afterParameterPut(parameterType, value, valueParameterDescriptor);
 }
Example #4
0
  private void putParameterOnStack(ParameterInfo... infos) {
    int[] index = new int[infos.length];
    for (int i = 0; i < infos.length; i++) {
      ParameterInfo info = infos[i];
      if (!info.isSkippedOrRemapped()) {
        index[i] = codegen.getFrameMap().enterTemp(info.getType());
      } else {
        index[i] = -1;
      }
    }

    for (int i = infos.length - 1; i >= 0; i--) {
      ParameterInfo info = infos[i];
      if (!info.isSkippedOrRemapped()) {
        Type type = info.type;
        StackValue.local(index[i], type).store(StackValue.onStack(type), codegen.v);
      }
    }
  }
Example #5
0
  @NotNull
  public List<CapturedParamDesc> getCapturedVars() {
    // lazy initialization cause it would be calculated after object creation
    if (capturedVars == null) {
      capturedVars = new ArrayList<CapturedParamDesc>();

      if (closure.getCaptureThis() != null) {
        Type type = typeMapper.mapType(closure.getCaptureThis());
        EnclosedValueDescriptor descriptor =
            new EnclosedValueDescriptor(
                AsmUtil.CAPTURED_THIS_FIELD,
                /* descriptor = */ null,
                StackValue.field(
                    type, closureClassType, AsmUtil.CAPTURED_THIS_FIELD, false, StackValue.LOCAL_0),
                type);
        capturedVars.add(getCapturedParamInfo(descriptor));
      }

      if (closure.getCaptureReceiverType() != null) {
        Type type = typeMapper.mapType(closure.getCaptureReceiverType());
        EnclosedValueDescriptor descriptor =
            new EnclosedValueDescriptor(
                AsmUtil.CAPTURED_RECEIVER_FIELD,
                /* descriptor = */ null,
                StackValue.field(
                    type,
                    closureClassType,
                    AsmUtil.CAPTURED_RECEIVER_FIELD,
                    false,
                    StackValue.LOCAL_0),
                type);
        capturedVars.add(getCapturedParamInfo(descriptor));
      }

      for (EnclosedValueDescriptor descriptor : closure.getCaptureVariables().values()) {
        capturedVars.add(getCapturedParamInfo(descriptor));
      }
    }
    return capturedVars;
  }
Example #6
0
 public void visitVarInsn(int opcode, int var, InstructionAdapter mv) {
   RemapInfo remapInfo = remap(var);
   StackValue value = remapInfo.value;
   if (value instanceof StackValue.Local) {
     if (remapInfo.parameterInfo != null) {
       // All remapped value parameters can't be rewritten except case of default ones.
       // On remapping default parameter to actual value there is only one instruction that writes
       // to it according to mask value
       // but if such parameter remapped then it passed and this mask branch code never executed
       // TODO add assertion about parameter default value: descriptor is required
       opcode =
           value.type.getOpcode(
               InlineCodegenUtil.isStoreInstruction(opcode) ? Opcodes.ISTORE : Opcodes.ILOAD);
     }
     mv.visitVarInsn(opcode, ((StackValue.Local) value).index);
     if (remapInfo.parameterInfo != null) {
       StackValue.coerce(value.type, remapInfo.parameterInfo.type, mv);
     }
   } else {
     assert remapInfo.parameterInfo != null : "Non local value should have parameter info";
     value.put(remapInfo.parameterInfo.type, mv);
   }
 }
Example #7
0
  public LocalVarRemapper(Parameters params, int additionalShift) {
    this.additionalShift = additionalShift;
    this.params = params;

    remapValues = new StackValue[params.getArgsSizeOnStack()];

    int realSize = 0;
    for (ParameterInfo info : params) {
      Integer shift = params.getDeclarationSlot(info);
      if (!info.isSkippedOrRemapped()) {
        remapValues[shift] = StackValue.local(realSize, AsmTypes.OBJECT_TYPE);
        realSize += info.getType().getSize();
      } else {
        remapValues[shift] = info.isRemapped() ? info.getRemapValue() : null;
      }
    }

    actualParamsSize = realSize;
  }
Example #8
0
  public static void putStackValuesIntoLocals(
      List<Type> directOrder, int shift, InstructionAdapter iv, String descriptor) {
    Type[] actualParams = Type.getArgumentTypes(descriptor);
    assert actualParams.length == directOrder.size()
        : "Number of expected and actual params should be equals!";

    int size = 0;
    for (Type next : directOrder) {
      size += next.getSize();
    }

    shift += size;
    int index = directOrder.size();

    for (Type next : Lists.reverse(directOrder)) {
      shift -= next.getSize();
      Type typeOnStack = actualParams[--index];
      if (!typeOnStack.equals(next)) {
        StackValue.onStack(typeOnStack).put(next, iv);
      }
      iv.store(shift, next);
    }
  }
  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;
  }
  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);
  }