jodd-proxetta/src/main/java/jodd/asm7/MethodWriter.java
private void computeAllFrames() {
    // Complete the control flow graph with exception handler blocks.
    Handler handler = firstHandler;
    while (handler != null) {
      String catchTypeDescriptor =
          handler.catchTypeDescriptor == null ? "java/lang/Throwable" : handler.catchTypeDescriptor;
      int catchType = Frame.getAbstractTypeFromInternalName(symbolTable, catchTypeDescriptor);
      // Mark handlerBlock as an exception handler.
      Label handlerBlock = handler.handlerPc.getCanonicalInstance();
      handlerBlock.flags |= Label.FLAG_JUMP_TARGET;
      // Add handlerBlock as a successor of all the basic blocks in the exception handler range.
      Label handlerRangeBlock = handler.startPc.getCanonicalInstance();
      Label handlerRangeEnd = handler.endPc.getCanonicalInstance();
      while (handlerRangeBlock != handlerRangeEnd) {
        handlerRangeBlock.outgoingEdges =
            new Edge(catchType, handlerBlock, handlerRangeBlock.outgoingEdges);
        handlerRangeBlock = handlerRangeBlock.nextBasicBlock;
      }
      handler = handler.nextHandler;
    }

    // Create and visit the first (implicit) frame.
    Frame firstFrame = firstBasicBlock.frame;
    firstFrame.setInputFrameFromDescriptor(symbolTable, accessFlags, descriptor, this.maxLocals);
    firstFrame.accept(this);

    // Fix point algorithm: add the first basic block to a list of blocks to process (i.e. blocks
    // whose stack map frame has changed) and, while there are blocks to process, remove one from
    // the list and update the stack map frames of its successor blocks in the control flow graph
    // (which might change them, in which case these blocks must be processed too, and are thus
    // added to the list of blocks to process). Also compute the maximum stack size of the method,
    // as a by-product.
    Label listOfBlocksToProcess = firstBasicBlock;
    listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST;
    int maxStackSize = 0;
    while (listOfBlocksToProcess != Label.EMPTY_LIST) {
      // Remove a basic block from the list of blocks to process.
      Label basicBlock = listOfBlocksToProcess;
      listOfBlocksToProcess = listOfBlocksToProcess.nextListElement;
      basicBlock.nextListElement = null;
      // By definition, basicBlock is reachable.
      basicBlock.flags |= Label.FLAG_REACHABLE;
      // Update the (absolute) maximum stack size.
      int maxBlockStackSize = basicBlock.frame.getInputStackSize() + basicBlock.outputStackMax;
      if (maxBlockStackSize > maxStackSize) {
        maxStackSize = maxBlockStackSize;
      }
      // Update the successor blocks of basicBlock in the control flow graph.
      Edge outgoingEdge = basicBlock.outgoingEdges;
      while (outgoingEdge != null) {
        Label successorBlock = outgoingEdge.successor.getCanonicalInstance();
        boolean successorBlockChanged =
            basicBlock.frame.merge(symbolTable, successorBlock.frame, outgoingEdge.info);
        if (successorBlockChanged && successorBlock.nextListElement == null) {
          // If successorBlock has changed it must be processed. Thus, if it is not already in the
          // list of blocks to process, add it to this list.
          successorBlock.nextListElement = listOfBlocksToProcess;
          listOfBlocksToProcess = successorBlock;
        }
        outgoingEdge = outgoingEdge.nextEdge;
      }
    }

    // Loop over all the basic blocks and visit the stack map frames that must be stored in the
    // StackMapTable attribute. Also replace unreachable code with NOP* ATHROW, and remove it from
    // exception handler ranges.
    Label basicBlock = firstBasicBlock;
    while (basicBlock != null) {
      if ((basicBlock.flags & (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE))
          == (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE)) {
        basicBlock.frame.accept(this);
      }
      if ((basicBlock.flags & Label.FLAG_REACHABLE) == 0) {
        // Find the start and end bytecode offsets of this unreachable block.
        Label nextBasicBlock = basicBlock.nextBasicBlock;
        int startOffset = basicBlock.bytecodeOffset;
        int endOffset = (nextBasicBlock == null ? code.length : nextBasicBlock.bytecodeOffset) - 1;
        if (endOffset >= startOffset) {
          // Replace its instructions with NOP ... NOP ATHROW.
          for (int i = startOffset; i < endOffset; ++i) {
            code.data[i] = Opcodes.NOP;
          }
          code.data[endOffset] = (byte) Opcodes.ATHROW;
          // Emit a frame for this unreachable block, with no local and a Throwable on the stack
          // (so that the ATHROW could consume this Throwable if it were reachable).
          int frameIndex = visitFrameStart(startOffset, /* numLocal = */ 0, /* numStack = */ 1);
          currentFrame[frameIndex] =
              Frame.getAbstractTypeFromInternalName(symbolTable, "java/lang/Throwable");
          visitFrameEnd();
          // Remove this unreachable basic block from the exception handler ranges.
          firstHandler = Handler.removeRange(firstHandler, basicBlock, nextBasicBlock);
          // The maximum stack size is now at least one, because of the Throwable declared above.
          maxStackSize = Math.max(maxStackSize, 1);
        }
      }
      basicBlock = basicBlock.nextBasicBlock;
    }

    this.maxStack = maxStackSize;
  }
private void computeAllFrames() {
    // Complete the control flow graph with exception handler blocks.
    Handler handler = firstHandler;
    while (handler != null) {
      String catchTypeDescriptor =
          handler.catchTypeDescriptor == null ? "java/lang/Throwable" : handler.catchTypeDescriptor;
      int catchType = Frame.getAbstractTypeFromInternalName(symbolTable, catchTypeDescriptor);
      // Mark handlerBlock as an exception handler.
      Label handlerBlock = handler.handlerPc.getCanonicalInstance();
      handlerBlock.flags |= Label.FLAG_JUMP_TARGET;
      // Add handlerBlock as a successor of all the basic blocks in the exception handler range.
      Label handlerRangeBlock = handler.startPc.getCanonicalInstance();
      Label handlerRangeEnd = handler.endPc.getCanonicalInstance();
      while (handlerRangeBlock != handlerRangeEnd) {
        handlerRangeBlock.outgoingEdges =
            new Edge(catchType, handlerBlock, handlerRangeBlock.outgoingEdges);
        handlerRangeBlock = handlerRangeBlock.nextBasicBlock;
      }
      handler = handler.nextHandler;
    }

    // Create and visit the first (implicit) frame.
    Frame firstFrame = firstBasicBlock.frame;
    firstFrame.setInputFrameFromDescriptor(symbolTable, accessFlags, descriptor, this.maxLocals);
    firstFrame.accept(this);

    // Fix point algorithm: add the first basic block to a list of blocks to process (i.e. blocks
    // whose stack map frame has changed) and, while there are blocks to process, remove one from
    // the list and update the stack map frames of its successor blocks in the control flow graph
    // (which might change them, in which case these blocks must be processed too, and are thus
    // added to the list of blocks to process). Also compute the maximum stack size of the method,
    // as a by-product.
    Label listOfBlocksToProcess = firstBasicBlock;
    listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST;
    int maxStackSize = 0;
    while (listOfBlocksToProcess != Label.EMPTY_LIST) {
      // Remove a basic block from the list of blocks to process.
      Label basicBlock = listOfBlocksToProcess;
      listOfBlocksToProcess = listOfBlocksToProcess.nextListElement;
      basicBlock.nextListElement = null;
      // By definition, basicBlock is reachable.
      basicBlock.flags |= Label.FLAG_REACHABLE;
      // Update the (absolute) maximum stack size.
      int maxBlockStackSize = basicBlock.frame.getInputStackSize() + basicBlock.outputStackMax;
      if (maxBlockStackSize > maxStackSize) {
        maxStackSize = maxBlockStackSize;
      }
      // Update the successor blocks of basicBlock in the control flow graph.
      Edge outgoingEdge = basicBlock.outgoingEdges;
      while (outgoingEdge != null) {
        Label successorBlock = outgoingEdge.successor.getCanonicalInstance();
        boolean successorBlockChanged =
            basicBlock.frame.merge(symbolTable, successorBlock.frame, outgoingEdge.info);
        if (successorBlockChanged && successorBlock.nextListElement == null) {
          // If successorBlock has changed it must be processed. Thus, if it is not already in the
          // list of blocks to process, add it to this list.
          successorBlock.nextListElement = listOfBlocksToProcess;
          listOfBlocksToProcess = successorBlock;
        }
        outgoingEdge = outgoingEdge.nextEdge;
      }
    }

    // Loop over all the basic blocks and visit the stack map frames that must be stored in the
    // StackMapTable attribute. Also replace unreachable code with NOP* ATHROW, and remove it from
    // exception handler ranges.
    Label basicBlock = firstBasicBlock;
    while (basicBlock != null) {
      if ((basicBlock.flags & (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE))
          == (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE)) {
        basicBlock.frame.accept(this);
      }
      if ((basicBlock.flags & Label.FLAG_REACHABLE) == 0) {
        // Find the start and end bytecode offsets of this unreachable block.
        Label nextBasicBlock = basicBlock.nextBasicBlock;
        int startOffset = basicBlock.bytecodeOffset;
        int endOffset = (nextBasicBlock == null ? code.length : nextBasicBlock.bytecodeOffset) - 1;
        if (endOffset >= startOffset) {
          // Replace its instructions with NOP ... NOP ATHROW.
          for (int i = startOffset; i < endOffset; ++i) {
            code.data[i] = Opcodes.NOP;
          }
          code.data[endOffset] = (byte) Opcodes.ATHROW;
          // Emit a frame for this unreachable block, with no local and a Throwable on the stack
          // (so that the ATHROW could consume this Throwable if it were reachable).
          int frameIndex = visitFrameStart(startOffset, /* numLocal = */ 0, /* numStack = */ 1);
          currentFrame[frameIndex] =
              Frame.getAbstractTypeFromInternalName(symbolTable, "java/lang/Throwable");
          visitFrameEnd();
          // Remove this unreachable basic block from the exception handler ranges.
          firstHandler = Handler.removeRange(firstHandler, basicBlock, nextBasicBlock);
          // The maximum stack size is now at least one, because of the Throwable declared above.
          maxStackSize = Math.max(maxStackSize, 1);
        }
      }
      basicBlock = basicBlock.nextBasicBlock;
    }

    this.maxStack = maxStackSize;
  }
private void computeAllFrames ( ) { // Complete the control flow graph with exception handler blocks. Handler handler = firstHandler ; while ( handler != null ) { String catchTypeDescriptor = handler . catchTypeDescriptor == null ? "java/lang/Throwable" : handler . catchTypeDescriptor ; int catchType = Frame . getAbstractTypeFromInternalName ( symbolTable , catchTypeDescriptor ) ; // Mark handlerBlock as an exception handler. Label handlerBlock = handler . handlerPc . getCanonicalInstance ( ) ; handlerBlock . flags |= Label . FLAG_JUMP_TARGET ; // Add handlerBlock as a successor of all the basic blocks in the exception handler range. Label handlerRangeBlock = handler . startPc . getCanonicalInstance ( ) ; Label handlerRangeEnd = handler . endPc . getCanonicalInstance ( ) ; while ( handlerRangeBlock != handlerRangeEnd ) { handlerRangeBlock . outgoingEdges = new Edge ( catchType , handlerBlock , handlerRangeBlock . outgoingEdges ) ; handlerRangeBlock = handlerRangeBlock . nextBasicBlock ; } handler = handler . nextHandler ; } // Create and visit the first (implicit) frame. Frame firstFrame = firstBasicBlock . frame ; firstFrame . setInputFrameFromDescriptor ( symbolTable , accessFlags , descriptor , this . maxLocals ) ; firstFrame . accept ( this ) ; // Fix point algorithm: add the first basic block to a list of blocks to process (i.e. blocks // whose stack map frame has changed) and, while there are blocks to process, remove one from // the list and update the stack map frames of its successor blocks in the control flow graph // (which might change them, in which case these blocks must be processed too, and are thus // added to the list of blocks to process). Also compute the maximum stack size of the method, // as a by-product. Label listOfBlocksToProcess = firstBasicBlock ; listOfBlocksToProcess . nextListElement = Label . EMPTY_LIST ; int maxStackSize = 0 ; while ( listOfBlocksToProcess != Label . EMPTY_LIST ) { // Remove a basic block from the list of blocks to process. Label basicBlock = listOfBlocksToProcess ; listOfBlocksToProcess = listOfBlocksToProcess . nextListElement ; basicBlock . nextListElement = null ; // By definition, basicBlock is reachable. basicBlock . flags |= Label . FLAG_REACHABLE ; // Update the (absolute) maximum stack size. int maxBlockStackSize = basicBlock . frame . getInputStackSize ( ) + basicBlock . outputStackMax ; if ( maxBlockStackSize > maxStackSize ) { maxStackSize = maxBlockStackSize ; } // Update the successor blocks of basicBlock in the control flow graph. Edge outgoingEdge = basicBlock . outgoingEdges ; while ( outgoingEdge != null ) { Label successorBlock = outgoingEdge . successor . getCanonicalInstance ( ) ; boolean successorBlockChanged = basicBlock . frame . merge ( symbolTable , successorBlock . frame , outgoingEdge . info ) ; if ( successorBlockChanged && successorBlock . nextListElement == null ) { // If successorBlock has changed it must be processed. Thus, if it is not already in the // list of blocks to process, add it to this list. successorBlock . nextListElement = listOfBlocksToProcess ; listOfBlocksToProcess = successorBlock ; } outgoingEdge = outgoingEdge . nextEdge ; } } // Loop over all the basic blocks and visit the stack map frames that must be stored in the // StackMapTable attribute. Also replace unreachable code with NOP* ATHROW, and remove it from // exception handler ranges. Label basicBlock = firstBasicBlock ; while ( basicBlock != null ) { if ( ( basicBlock . flags & ( Label . FLAG_JUMP_TARGET | Label . FLAG_REACHABLE ) ) == ( Label . FLAG_JUMP_TARGET | Label . FLAG_REACHABLE ) ) { basicBlock . frame . accept ( this ) ; } if ( ( basicBlock . flags & Label . FLAG_REACHABLE ) == 0 ) { // Find the start and end bytecode offsets of this unreachable block. Label nextBasicBlock = basicBlock . nextBasicBlock ; int startOffset = basicBlock . bytecodeOffset ; int endOffset = ( nextBasicBlock == null ? code . length : nextBasicBlock . bytecodeOffset ) - 1 ; if ( endOffset >= startOffset ) { // Replace its instructions with NOP ... NOP ATHROW. for ( int i = startOffset ; i < endOffset ; ++ i ) { code . data [ i ] = Opcodes . NOP ; } code . data [ endOffset ] = ( byte ) Opcodes . ATHROW ; // Emit a frame for this unreachable block, with no local and a Throwable on the stack // (so that the ATHROW could consume this Throwable if it were reachable). int frameIndex = visitFrameStart ( startOffset , /* numLocal = */ 0 , /* numStack = */ 1 ) ; currentFrame [ frameIndex ] = Frame . getAbstractTypeFromInternalName ( symbolTable , "java/lang/Throwable" ) ; visitFrameEnd ( ) ; // Remove this unreachable basic block from the exception handler ranges. firstHandler = Handler . removeRange ( firstHandler , basicBlock , nextBasicBlock ) ; // The maximum stack size is now at least one, because of the Throwable declared above. maxStackSize = Math . max ( maxStackSize , 1 ) ; } } basicBlock = basicBlock . nextBasicBlock ; } this . maxStack = maxStackSize ; }
Computes all the stack map frames of the method, from scratch.
Computes all the stack map frames of the method from scratch .