/**
   * Creates the print
   *
   * @return The print as an ArrayList
   */
  public ArrayList<String> createPrint() {
    ArrayList<String> info = new ArrayList<String>();
    ListIterator<?> it = mNode.instructions.iterator();
    boolean firstLabel = false;
    while (it.hasNext()) {
      AbstractInsnNode ain = (AbstractInsnNode) it.next();
      String line = "";
      if (ain instanceof VarInsnNode) {
        line = printVarInsnNode((VarInsnNode) ain, it);
      } else if (ain instanceof IntInsnNode) {
        line = printIntInsnNode((IntInsnNode) ain, it);
      } else if (ain instanceof FieldInsnNode) {
        line = printFieldInsnNode((FieldInsnNode) ain, it);
      } else if (ain instanceof MethodInsnNode) {
        line = printMethodInsnNode((MethodInsnNode) ain, it);
      } else if (ain instanceof LdcInsnNode) {
        line = printLdcInsnNode((LdcInsnNode) ain, it);
      } else if (ain instanceof InsnNode) {
        line = printInsnNode((InsnNode) ain, it);
      } else if (ain instanceof JumpInsnNode) {
        line = printJumpInsnNode((JumpInsnNode) ain, it);
      } else if (ain instanceof LineNumberNode) {
        line = printLineNumberNode((LineNumberNode) ain, it);
      } else if (ain instanceof LabelNode) {
        if (firstLabel
            && Decompiler.BYTECODE
                .getSettings()
                .isSelected(ClassNodeDecompiler.Settings.APPEND_BRACKETS_TO_LABELS)) info.add("}");

        line = printLabelnode((LabelNode) ain);

        if (Decompiler.BYTECODE
            .getSettings()
            .isSelected(ClassNodeDecompiler.Settings.APPEND_BRACKETS_TO_LABELS)) {
          if (!firstLabel) firstLabel = true;
          line += " {";
        }
      } else if (ain instanceof TypeInsnNode) {
        line = printTypeInsnNode((TypeInsnNode) ain);
      } else if (ain instanceof FrameNode) {
        line = "";
      } else if (ain instanceof IincInsnNode) {
        line = printIincInsnNode((IincInsnNode) ain);
      } else if (ain instanceof TableSwitchInsnNode) {
        line = printTableSwitchInsnNode((TableSwitchInsnNode) ain);
      } else if (ain instanceof LookupSwitchInsnNode) {
        line = printLookupSwitchInsnNode((LookupSwitchInsnNode) ain);
      } else if (ain instanceof InvokeDynamicInsnNode) {
        line = printInvokeDynamicInsNode((InvokeDynamicInsnNode) ain);
      } else {
        line += "UNADDED OPCODE: " + nameOpcode(ain.opcode()) + " " + ain.toString();
      }
      if (!line.equals("")) {
        if (match) if (matchedInsns.contains(ain)) line = "   -> " + line;

        info.add(line);
      }
    }
    if (firstLabel
        && Decompiler.BYTECODE
            .getSettings()
            .isSelected(ClassNodeDecompiler.Settings.APPEND_BRACKETS_TO_LABELS)) info.add("}");
    return info;
  }
Exemplo n.º 2
0
  private static void removeClosureAssertions(MethodNode node) {
    AbstractInsnNode cur = node.instructions.getFirst();
    while (cur != null && cur.getNext() != null) {
      AbstractInsnNode next = cur.getNext();
      if (next.getType() == AbstractInsnNode.METHOD_INSN) {
        MethodInsnNode methodInsnNode = (MethodInsnNode) next;
        if (methodInsnNode.name.equals("checkParameterIsNotNull")
            && methodInsnNode.owner.equals(IntrinsicMethods.INTRINSICS_CLASS_NAME)) {
          AbstractInsnNode prev = cur.getPrevious();

          assert cur.getOpcode() == Opcodes.LDC
              : "checkParameterIsNotNull should go after LDC but " + cur;
          assert prev.getOpcode() == Opcodes.ALOAD
              : "checkParameterIsNotNull should be invoked on local var but " + prev;

          node.instructions.remove(prev);
          node.instructions.remove(cur);
          cur = next.getNext();
          node.instructions.remove(next);
          next = cur;
        }
      }
      cur = next;
    }
  }
  private boolean scanDecrypter(MethodNode decryptermethodnode, int newHashCode) {
    InsnList iList = decryptermethodnode.instructions;

    AbstractInsnNode insn = null, removeInsn = null;
    for (AbstractInsnNode i : iList.toArray()) {
      if (i instanceof MethodInsnNode) {
        MethodInsnNode methodi = ((MethodInsnNode) i);
        if ("currentThread".equals(methodi.name)) { // find code form this instruction
          insn = i;
          break;
        }
      }
    }
    if (insn == null) {
      return false;
    }

    while (insn != null) {
      if (insn instanceof MethodInsnNode) {
        MethodInsnNode methodi = ((MethodInsnNode) insn);
        if ("hashCode".equals(methodi.name)) { // to this instruction
          break;
        }
      }
      removeInsn = insn;
      insn = insn.getNext();
      iList.remove(removeInsn); // and remove it
    }
    if (insn == null) return false;
    iList.set(insn, new LdcInsnNode(newHashCode)); // then replace it with pre-computed key LDC
    return true;
  }
Exemplo n.º 4
0
 // marked return could be either non-local or local in case of labeled lambda self-returns
 public static boolean isMarkedReturn(@NotNull AbstractInsnNode returnIns) {
   if (!isReturnOpcode(returnIns.getOpcode())) {
     return false;
   }
   AbstractInsnNode globalFlag = returnIns.getPrevious();
   return globalFlag instanceof MethodInsnNode
       && NON_LOCAL_RETURN.equals(((MethodInsnNode) globalFlag).owner);
 }
Exemplo n.º 5
0
 private static boolean isEmptyTryInterval(@NotNull TryCatchBlockNode tryCatchBlockNode) {
   LabelNode start = tryCatchBlockNode.start;
   AbstractInsnNode end = tryCatchBlockNode.end;
   while (end != start && end instanceof LabelNode) {
     end = end.getPrevious();
   }
   return start == end;
 }
Exemplo n.º 6
0
  @NotNull
  public static List<AbstractInsnNode> getCapturedFieldAccessChain(@NotNull VarInsnNode aload0) {
    List<AbstractInsnNode> fieldAccessChain = new ArrayList<AbstractInsnNode>();
    fieldAccessChain.add(aload0);
    AbstractInsnNode next = aload0.getNext();
    while (next != null && next instanceof FieldInsnNode || next instanceof LabelNode) {
      if (next instanceof LabelNode) {
        next = next.getNext();
        continue; // it will be delete on transformation
      }
      fieldAccessChain.add(next);
      if ("this$0".equals(((FieldInsnNode) next).name)) {
        next = next.getNext();
      } else {
        break;
      }
    }

    return fieldAccessChain;
  }
 @Override
 public BasicValue naryOperation(AbstractInsnNode insn, List<? extends BasicValue> values)
     throws AnalyzerException {
   int opcode = insn.getOpcode();
   if (opcode == MULTIANEWARRAY) {
     return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc));
   } else if (opcode == INVOKEDYNAMIC) {
     return newValue(Type.getReturnType(((InvokeDynamicInsnNode) insn).desc));
   } else {
     return newValue(Type.getReturnType(((MethodInsnNode) insn).desc));
   }
 }
Exemplo n.º 8
0
 public static boolean isInlineMarker(AbstractInsnNode insn, String name) {
   if (insn instanceof MethodInsnNode) {
     MethodInsnNode methodInsnNode = (MethodInsnNode) insn;
     return insn.getOpcode() == Opcodes.INVOKESTATIC
         && methodInsnNode.owner.equals(INLINE_MARKER_CLASS_NAME)
         && (name != null
             ? methodInsnNode.name.equals(name)
             : methodInsnNode.name.equals(INLINE_MARKER_BEFORE_METHOD_NAME)
                 || methodInsnNode.name.equals(INLINE_MARKER_AFTER_METHOD_NAME));
   } else {
     return false;
   }
 }
Exemplo n.º 9
0
  private void transformCaptured(@NotNull MethodNode node) {
    if (nodeRemapper.isRoot()) {
      return;
    }

    // Fold all captured variable chain - ALOAD 0 ALOAD this$0 GETFIELD $captured - to GETFIELD
    // $$$$captured
    // On future decoding this field could be inline or unfolded in another field access chain (it
    // can differ in some missed this$0)
    AbstractInsnNode cur = node.instructions.getFirst();
    while (cur != null) {
      if (cur instanceof VarInsnNode && cur.getOpcode() == Opcodes.ALOAD) {
        if (((VarInsnNode) cur).var == 0) {
          List<AbstractInsnNode> accessChain = getCapturedFieldAccessChain((VarInsnNode) cur);
          AbstractInsnNode insnNode = nodeRemapper.foldFieldAccessChainIfNeeded(accessChain, node);
          if (insnNode != null) {
            cur = insnNode;
          }
        }
      }
      cur = cur.getNext();
    }
  }
Exemplo n.º 10
0
 public static int getConstant(AbstractInsnNode ins) {
   int opcode = ins.getOpcode();
   Integer value;
   if (opcode >= Opcodes.ICONST_0 && opcode <= Opcodes.ICONST_5) {
     value = opcode - Opcodes.ICONST_0;
   } else if (opcode == Opcodes.BIPUSH || opcode == Opcodes.SIPUSH) {
     IntInsnNode index = (IntInsnNode) ins;
     value = index.operand;
   } else {
     LdcInsnNode index = (LdcInsnNode) ins;
     value = (Integer) index.cst;
   }
   return value;
 }
Exemplo n.º 11
0
  public LambdaInfo getLambdaIfExists(AbstractInsnNode insnNode) {
    if (insnNode.getOpcode() == Opcodes.ALOAD) {
      int varIndex = ((VarInsnNode) insnNode).var;
      if (varIndex < parameters.totalSize()) {
        return parameters.get(varIndex).getLambda();
      }
    } else if (insnNode instanceof FieldInsnNode) {
      FieldInsnNode fieldInsnNode = (FieldInsnNode) insnNode;
      if (fieldInsnNode.name.startsWith("$$$")) {
        return findCapturedField(fieldInsnNode, nodeRemapper).getLambda();
      }
    }

    return null;
  }
Exemplo n.º 12
0
 @Override
 public AnnotationVisitor visitInsnAnnotation(
     int typeRef, TypePath typePath, String desc, boolean visible) {
   // Finds the last real instruction, i.e. the instruction targeted by
   // this annotation.
   AbstractInsnNode insn = instructions.getLast();
   while (insn.getOpcode() == -1) {
     insn = insn.getPrevious();
   }
   // Adds the annotation to this instruction.
   TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
   if (visible) {
     if (insn.visibleTypeAnnotations == null) {
       insn.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
     }
     insn.visibleTypeAnnotations.add(an);
   } else {
     if (insn.invisibleTypeAnnotations == null) {
       insn.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
     }
     insn.invisibleTypeAnnotations.add(an);
   }
   return an;
 }
Exemplo n.º 13
0
  @NotNull
  // process local and global returns (local substituted with goto end-label global kept unchanged)
  public static List<PointForExternalFinallyBlocks> processReturns(
      @NotNull MethodNode node,
      @NotNull LabelOwner labelOwner,
      boolean remapReturn,
      Label endLabel) {
    if (!remapReturn) {
      return Collections.emptyList();
    }
    List<PointForExternalFinallyBlocks> result = new ArrayList<PointForExternalFinallyBlocks>();
    InsnList instructions = node.instructions;
    AbstractInsnNode insnNode = instructions.getFirst();
    while (insnNode != null) {
      if (InlineCodegenUtil.isReturnOpcode(insnNode.getOpcode())) {
        AbstractInsnNode previous = insnNode.getPrevious();
        MethodInsnNode flagNode;
        boolean isLocalReturn = true;
        String labelName = null;
        if (previous != null
            && previous instanceof MethodInsnNode
            && InlineCodegenUtil.NON_LOCAL_RETURN.equals(((MethodInsnNode) previous).owner)) {
          flagNode = (MethodInsnNode) previous;
          labelName = flagNode.name;
        }

        if (labelName != null) {
          isLocalReturn = labelOwner.isMyLabel(labelName);
          // remove global return flag
          if (isLocalReturn) {
            instructions.remove(previous);
          }
        }

        if (isLocalReturn && endLabel != null) {
          LabelNode labelNode = (LabelNode) endLabel.info;
          JumpInsnNode jumpInsnNode = new JumpInsnNode(Opcodes.GOTO, labelNode);
          instructions.insert(insnNode, jumpInsnNode);
          instructions.remove(insnNode);
          insnNode = jumpInsnNode;
        }

        // genetate finally block before nonLocalReturn flag/return/goto
        result.add(
            new PointForExternalFinallyBlocks(
                isLocalReturn ? insnNode : insnNode.getPrevious(),
                getReturnType(insnNode.getOpcode())));
      }
      insnNode = insnNode.getNext();
    }
    return result;
  }
Exemplo n.º 14
0
  @NotNull
  protected MethodNode markPlacesForInlineAndRemoveInlinable(@NotNull MethodNode node) {
    node = prepareNode(node);

    Analyzer<SourceValue> analyzer =
        new Analyzer<SourceValue>(new SourceInterpreter()) {
          @NotNull
          @Override
          protected Frame<SourceValue> newFrame(int nLocals, int nStack) {
            return new Frame<SourceValue>(nLocals, nStack) {
              @Override
              public void execute(
                  @NotNull AbstractInsnNode insn, Interpreter<SourceValue> interpreter)
                  throws AnalyzerException {
                if (insn.getOpcode() == Opcodes.RETURN) {
                  // there is exception on void non local return in frame
                  return;
                }
                super.execute(insn, interpreter);
              }
            };
          }
        };

    Frame<SourceValue>[] sources;
    try {
      sources = analyzer.analyze("fake", node);
    } catch (AnalyzerException e) {
      throw wrapException(e, node, "couldn't inline method call");
    }

    AbstractInsnNode cur = node.instructions.getFirst();
    int index = 0;

    boolean awaitClassReification = false;
    Set<LabelNode> possibleDeadLabels = new HashSet<LabelNode>();

    while (cur != null) {
      Frame<SourceValue> frame = sources[index];

      if (frame != null) {
        if (ReifiedTypeInliner.isNeedClassReificationMarker(cur)) {
          awaitClassReification = true;
        } else if (cur.getType() == AbstractInsnNode.METHOD_INSN) {
          MethodInsnNode methodInsnNode = (MethodInsnNode) cur;
          String owner = methodInsnNode.owner;
          String desc = methodInsnNode.desc;
          String name = methodInsnNode.name;
          // TODO check closure
          int paramLength = Type.getArgumentTypes(desc).length + 1; // non static
          if (isInvokeOnLambda(owner, name) /*&& methodInsnNode.owner.equals(INLINE_RUNTIME)*/) {
            SourceValue sourceValue = frame.getStack(frame.getStackSize() - paramLength);

            LambdaInfo lambdaInfo = null;
            int varIndex = -1;

            if (sourceValue.insns.size() == 1) {
              AbstractInsnNode insnNode = sourceValue.insns.iterator().next();

              lambdaInfo = getLambdaIfExists(insnNode);
              if (lambdaInfo != null) {
                // remove inlinable access
                node.instructions.remove(insnNode);
              }
            }

            invokeCalls.add(new InvokeCall(varIndex, lambdaInfo));
          } else if (isAnonymousConstructorCall(owner, name)) {
            Map<Integer, LambdaInfo> lambdaMapping = new HashMap<Integer, LambdaInfo>();
            int paramStart = frame.getStackSize() - paramLength;

            for (int i = 0; i < paramLength; i++) {
              SourceValue sourceValue = frame.getStack(paramStart + i);
              if (sourceValue.insns.size() == 1) {
                AbstractInsnNode insnNode = sourceValue.insns.iterator().next();
                LambdaInfo lambdaInfo = getLambdaIfExists(insnNode);
                if (lambdaInfo != null) {
                  lambdaMapping.put(i, lambdaInfo);
                  node.instructions.remove(insnNode);
                }
              }
            }

            anonymousObjectGenerations.add(
                buildConstructorInvocation(owner, desc, lambdaMapping, awaitClassReification));
            awaitClassReification = false;
          }
        } else if (cur.getOpcode() == Opcodes.GETSTATIC) {
          FieldInsnNode fieldInsnNode = (FieldInsnNode) cur;
          String owner = fieldInsnNode.owner;
          if (isAnonymousSingletonLoad(owner, fieldInsnNode.name)) {
            anonymousObjectGenerations.add(
                new AnonymousObjectGeneration(
                    owner, isSameModule, awaitClassReification, isAlreadyRegenerated(owner), true));
            awaitClassReification = false;
          }
        }
      }
      AbstractInsnNode prevNode = cur;
      cur = cur.getNext();
      index++;

      // given frame is <tt>null</tt> if and only if the corresponding instruction cannot be reached
      // (dead code).
      if (frame == null) {
        // clean dead code otherwise there is problems in unreachable finally block, don't touch
        // label it cause try/catch/finally problems
        if (prevNode.getType() == AbstractInsnNode.LABEL) {
          // NB: Cause we generate exception table for default handler using gaps (see
          // ExpressionCodegen.visitTryExpression)
          // it may occurs that interval for default handler starts before catch start label, so
          // this label seems as dead,
          // but as result all this labels will be merged into one (see KT-5863)
        } else {
          node.instructions.remove(prevNode);
        }
      }
    }

    // clean dead try/catch blocks
    List<TryCatchBlockNode> blocks = node.tryCatchBlocks;
    for (Iterator<TryCatchBlockNode> iterator = blocks.iterator(); iterator.hasNext(); ) {
      TryCatchBlockNode block = iterator.next();
      if (isEmptyTryInterval(block)) {
        iterator.remove();
      }
    }

    return node;
  }
  @Override
  public BasicValue binaryOperation(
      @NotNull AbstractInsnNode insn, @NotNull BasicValue value1, @NotNull BasicValue value2)
      throws AnalyzerException {
    if (insn.getOpcode() == Opcodes.AALOAD) {
      Type arrayType = value1.getType();
      if (arrayType != null && arrayType.getSort() == Type.ARRAY) {
        return new StrictBasicValue(arrayType.getElementType());
      }
    }

    switch (insn.getOpcode()) {
      case IALOAD:
      case BALOAD:
      case CALOAD:
      case SALOAD:
      case IADD:
      case ISUB:
      case IMUL:
      case IDIV:
      case IREM:
      case ISHL:
      case ISHR:
      case IUSHR:
      case IAND:
      case IOR:
      case IXOR:
        return StrictBasicValue.INT_VALUE;
      case FALOAD:
      case FADD:
      case FSUB:
      case FMUL:
      case FDIV:
      case FREM:
        return StrictBasicValue.FLOAT_VALUE;
      case LALOAD:
      case LADD:
      case LSUB:
      case LMUL:
      case LDIV:
      case LREM:
      case LSHL:
      case LSHR:
      case LUSHR:
      case LAND:
      case LOR:
      case LXOR:
        return StrictBasicValue.LONG_VALUE;
      case DALOAD:
      case DADD:
      case DSUB:
      case DMUL:
      case DDIV:
      case DREM:
        return StrictBasicValue.DOUBLE_VALUE;
      case AALOAD:
        return StrictBasicValue.REFERENCE_VALUE;
      case LCMP:
      case FCMPL:
      case FCMPG:
      case DCMPL:
      case DCMPG:
        return StrictBasicValue.INT_VALUE;
      case IF_ICMPEQ:
      case IF_ICMPNE:
      case IF_ICMPLT:
      case IF_ICMPGE:
      case IF_ICMPGT:
      case IF_ICMPLE:
      case IF_ACMPEQ:
      case IF_ACMPNE:
      case PUTFIELD:
        return null;
      default:
        throw new Error("Internal error.");
    }
  }
  @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.");
    }
  }
 @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.");
   }
 }
  private InsnList fixInstructions(MethodNode originalMethod, CloneMap cloneMap) {
    InsnList instructions = new InsnList();

    for (int k = 0; k < originalMethod.instructions.size(); k++) {
      AbstractInsnNode originalInsn = originalMethod.instructions.get(k);
      switch (originalInsn.getOpcode()) {
          // the put on the field granular field is transformed to a fieldref.set
        case PUTFIELD:
          {
            FieldInsnNode fieldInsn = (FieldInsnNode) originalInsn;
            ClassMetadata ownerMetadata =
                metadataRepository.loadClassMetadata(classLoader, fieldInsn.owner);
            FieldMetadata fieldMetadata = ownerMetadata.getFieldMetadata(fieldInsn.name);
            Type originalFieldType = Type.getType(fieldMetadata.getDesc());

            if (fieldMetadata.hasFieldGranularity()) {

              boolean fieldIsCategory2 = isCategory2(fieldMetadata.getDesc());

              if (fieldIsCategory2) {
                // value(category2), owner,..

                instructions.add(new InsnNode(DUP2_X1));
                // [value(category2), owner, value(category2),...]

                instructions.add(new InsnNode(POP2));
                // [owner, value(category2), ...]
              } else {
                // [value(category1), owner,
                instructions.add(new InsnNode(SWAP));
                // [owner, value(category1),..
              }

              String referenceDesc = findReferenceDesc(fieldMetadata.getDesc());
              String referenceName = Type.getType(referenceDesc).getInternalName();

              instructions.add(
                  new FieldInsnNode(GETFIELD, fieldInsn.owner, fieldInsn.name, referenceDesc));

              if (fieldIsCategory2) {
                // [owner, value(category2),..

                instructions.add(new InsnNode(DUP_X2));
                // [owner, value(category2), owner

                instructions.add(new InsnNode(POP));
                // [value(category2), owner
              } else {
                // [owner, value(category1)
                instructions.add(new InsnNode(SWAP));
                // [value(category1), owner..
              }

              // call the set
              if (originalFieldType.getSort() == Type.ARRAY
                  || originalFieldType.getSort() == Type.OBJECT) {
                String objectDesc = Type.getDescriptor(Object.class);
                MethodInsnNode methodInsn =
                    new MethodInsnNode(
                        INVOKEVIRTUAL,
                        referenceName,
                        "set",
                        format("(%s)%s", objectDesc, objectDesc));
                instructions.add(methodInsn);
              } else {
                MethodInsnNode methodInsn =
                    new MethodInsnNode(
                        INVOKEVIRTUAL,
                        referenceName,
                        "set",
                        format("(%s)%s", fieldMetadata.getDesc(), fieldMetadata.getDesc()));
                instructions.add(methodInsn);
              }

              // pop the unused return value of the set.
              if (fieldIsCategory2) {
                instructions.add(new InsnNode(POP2));
              } else {
                instructions.add(new InsnNode(POP));
              }
            } else {
              instructions.add(originalInsn.clone(cloneMap));
            }
          }
          break;
          // the get on the field granular field is transformed to a fieldref.get
        case GETFIELD:
          {
            FieldInsnNode fieldInsn = (FieldInsnNode) originalInsn;
            FieldMetadata fieldMetadata =
                metadataRepository
                    .loadClassMetadata(classLoader, fieldInsn.owner)
                    .getFieldMetadata(fieldInsn.name);
            if (!fieldMetadata.hasFieldGranularity()) {
              // if it is not getter on a field granular field
              instructions.add(originalInsn.clone(cloneMap));
            } else {
              // it is a getter on a field granular field.
              String referenceDesc = findReferenceDesc(fieldMetadata.getDesc());
              String referenceName = Type.getType(referenceDesc).getInternalName();

              // place the fieldref on the stack.
              instructions.add(
                  new FieldInsnNode(GETFIELD, fieldInsn.owner, fieldInsn.name, referenceDesc));

              Type originalFieldType = Type.getType(fieldMetadata.getDesc());
              if (originalFieldType.getSort() == Type.ARRAY
                  || originalFieldType.getSort() == Type.OBJECT) {
                instructions.add(
                    new MethodInsnNode(
                        INVOKEVIRTUAL,
                        referenceName,
                        "get",
                        format("()%s", getDescriptor(Object.class))));

                if (!originalFieldType.equals(Type.getType(Object.class))) {
                  instructions.add(
                      new TypeInsnNode(CHECKCAST, originalFieldType.getInternalName()));
                }
              } else {
                instructions.add(
                    new MethodInsnNode(
                        INVOKEVIRTUAL,
                        referenceName,
                        "get",
                        format("()%s", fieldMetadata.getDesc())));
              }
            }
          }
          break;
        default:
          instructions.add(originalInsn.clone(cloneMap));
          break;
      }
    }

    return instructions;
  }
Exemplo n.º 19
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;
  }