private void emitInstantiation()

in asm-commons/src/main/java/org/objectweb/asm/commons/JSRInlinerAdapter.java [334:425]


  private void emitInstantiation(
      final Instantiation instantiation,
      final List<Instantiation> worklist,
      final InsnList newInstructions,
      final List<TryCatchBlockNode> newTryCatchBlocks,
      final List<LocalVariableNode> newLocalVariables) {
    LabelNode previousLabelNode = null;
    for (int i = 0; i < instructions.size(); ++i) {
      AbstractInsnNode insnNode = instructions.get(i);
      if (insnNode.getType() == AbstractInsnNode.LABEL) {
        // Always clone all labels, while avoiding to add the same label more than once.
        LabelNode labelNode = (LabelNode) insnNode;
        LabelNode clonedLabelNode = instantiation.getClonedLabel(labelNode);
        if (clonedLabelNode != previousLabelNode) {
          newInstructions.add(clonedLabelNode);
          previousLabelNode = clonedLabelNode;
        }
      } else if (instantiation.findOwner(i) == instantiation) {
        // Don't emit instructions that were already emitted by an ancestor subroutine. Note that it
        // is still possible for a given instruction to be emitted twice because it may belong to
        // two subroutines that do not invoke each other.

        if (insnNode.getOpcode() == RET) {
          // Translate RET instruction(s) to a jump to the return label for the appropriate
          // instantiation. The problem is that the subroutine may "fall through" to the ret of a
          // parent subroutine; therefore, to find the appropriate ret label we find the oldest
          // instantiation that claims to own this instruction.
          LabelNode retLabel = null;
          for (Instantiation retLabelOwner = instantiation;
              retLabelOwner != null;
              retLabelOwner = retLabelOwner.parent) {
            if (retLabelOwner.subroutineInsns.get(i)) {
              retLabel = retLabelOwner.returnLabel;
            }
          }
          if (retLabel == null) {
            // This is only possible if the mainSubroutine owns a RET instruction, which should
            // never happen for verifiable code.
            throw new IllegalArgumentException(
                "Instruction #" + i + " is a RET not owned by any subroutine");
          }
          newInstructions.add(new JumpInsnNode(GOTO, retLabel));
        } else if (insnNode.getOpcode() == JSR) {
          LabelNode jsrLabelNode = ((JumpInsnNode) insnNode).label;
          BitSet subroutineInsns = subroutinesInsns.get(jsrLabelNode);
          Instantiation newInstantiation = new Instantiation(instantiation, subroutineInsns);
          LabelNode clonedJsrLabelNode = newInstantiation.getClonedLabelForJumpInsn(jsrLabelNode);
          // Replace the JSR instruction with a GOTO to the instantiated subroutine, and push NULL
          // for what was once the return address value. This hack allows us to avoid doing any sort
          // of data flow analysis to figure out which instructions manipulate the old return
          // address value pointer which is now known to be unneeded.
          newInstructions.add(new InsnNode(ACONST_NULL));
          newInstructions.add(new JumpInsnNode(GOTO, clonedJsrLabelNode));
          newInstructions.add(newInstantiation.returnLabel);
          // Insert this new instantiation into the queue to be emitted later.
          worklist.add(newInstantiation);
        } else {
          newInstructions.add(insnNode.clone(instantiation));
        }
      }
    }

    // Emit the try/catch blocks that are relevant for this instantiation.
    for (TryCatchBlockNode tryCatchBlockNode : tryCatchBlocks) {
      final LabelNode start = instantiation.getClonedLabel(tryCatchBlockNode.start);
      final LabelNode end = instantiation.getClonedLabel(tryCatchBlockNode.end);
      if (start != end) {
        final LabelNode handler =
            instantiation.getClonedLabelForJumpInsn(tryCatchBlockNode.handler);
        if (start == null || end == null || handler == null) {
          throw new AssertionError("Internal error!");
        }
        newTryCatchBlocks.add(new TryCatchBlockNode(start, end, handler, tryCatchBlockNode.type));
      }
    }

    // Emit the local variable nodes that are relevant for this instantiation.
    for (LocalVariableNode localVariableNode : localVariables) {
      final LabelNode start = instantiation.getClonedLabel(localVariableNode.start);
      final LabelNode end = instantiation.getClonedLabel(localVariableNode.end);
      if (start != end) {
        newLocalVariables.add(
            new LocalVariableNode(
                localVariableNode.name,
                localVariableNode.desc,
                localVariableNode.signature,
                start,
                end,
                localVariableNode.index));
      }
    }
  }