⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 methodwriter.java

📁 asm的源码包 并且包含英文的文档
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
                        l.next = stack;
                        stack = l;
                    }
                    b = b.next;
                }
            }
            this.maxStack = max;
        } else {
            this.maxStack = maxStack;
            this.maxLocals = maxLocals;
        }
    }

    public void visitEnd() {
    }

    // ------------------------------------------------------------------------
    // Utility methods: control flow analysis algorithm
    // ------------------------------------------------------------------------

    /**
     * Computes the size of the arguments and of the return value of a method.
     * 
     * @param desc the descriptor of a method.
     * @return the size of the arguments of the method (plus one for the
     *         implicit this argument), argSize, and the size of its return
     *         value, retSize, packed into a single int i =
     *         <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal
     *         to <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>).
     */
    static int getArgumentsAndReturnSizes(final String desc) {
        int n = 1;
        int c = 1;
        while (true) {
            char car = desc.charAt(c++);
            if (car == ')') {
                car = desc.charAt(c);
                return n << 2
                        | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
            } else if (car == 'L') {
                while (desc.charAt(c++) != ';') {
                }
                n += 1;
            } else if (car == '[') {
                while ((car = desc.charAt(c)) == '[') {
                    ++c;
                }
                if (car == 'D' || car == 'J') {
                    n -= 1;
                }
            } else if (car == 'D' || car == 'J') {
                n += 2;
            } else {
                n += 1;
            }
        }
    }

    /**
     * Adds a successor to the {@link #currentBlock currentBlock} block.
     * 
     * @param info information about the control flow edge to be added.
     * @param successor the successor block to be added to the current block.
     */
    private void addSuccessor(final int info, final Label successor) {
        // creates and initializes an Edge object...
        Edge b = new Edge();
        b.info = info;
        b.successor = successor;
        // ...and adds it to the successor list of the currentBlock block
        b.next = currentBlock.successors;
        currentBlock.successors = b;
    }

    /**
     * Ends the current basic block. This method must be used in the case where
     * the current basic block does not have any successor.
     */
    private void noSuccessor() {
        if (compute == FRAMES) {
            Label l = new Label();
            l.frame = new Frame();
            l.frame.owner = l;
            l.resolve(this, code.length, code.data);
            previousBlock.successor = l;
            previousBlock = l;
        } else {
            currentBlock.outputStackMax = maxStackSize;
        }
        currentBlock = null;
    }

    /**
     * Finds the basic blocks that belong to a given subroutine, and marks these
     * blocks as belonging to this subroutine (by using {@link Label#status} as
     * a bit set (see {@link #visitMaxs}). This recursive method follows the
     * control flow graph to find all the blocks that are reachable from the
     * given block WITHOUT following any JSR target.
     * 
     * @param block a block that belongs to the subroutine
     * @param id the id of this subroutine
     */
    private void findSubroutine(final Label block, final int id) {
        // if 'block' is already marked as belonging to subroutine 'id', returns
        if ((block.status & id) != 0) {
            return;
        }
        // marks 'block' as belonging to subroutine 'id'
        block.status |= id;
        // calls this method recursively on each successor, except JSR targets
        Edge e = block.successors;
        while (e != null) {
            // if 'block' is a JSR block, then 'block.successors.next' leads
            // to the JSR target (see {@link #visitJumpInsn}) and must therefore
            // not be followed
            if ((block.status & Label.JSR) == 0 || e != block.successors.next) {
                findSubroutine(e.successor, id);
            }
            e = e.next;
        }
    }

    /**
     * Finds the successors of the RET blocks of the specified subroutine, and
     * of any nested subroutine it calls.
     * 
     * @param id id of the subroutine whose RET block successors must be found.
     * @param JSRs the JSR blocks that were followed to reach this subroutine.
     * @param nJSRs number of JSR blocks in the JSRs array.
     */
    private void findSubroutineSuccessors(
        final int id,
        final Label[] JSRs,
        final int nJSRs)
    {
        // iterates over all the basic blocks...
        Label l = labels;
        while (l != null) {
            // for those that belong to subroutine 'id'...
            if ((l.status & id) != 0) {
                if ((l.status & Label.JSR) != 0) {
                    // finds the subroutine to which 'l' leads by following the
                    // second edge of l.successors (see {@link #visitJumpInsn})
                    int nId = l.successors.next.successor.status & ~0xFFF;
                    if (nId != id) {
                        // calls this method recursively with l pushed onto the
                        // JSRs stack to find the successors of the RET blocks
                        // of this nested subroutine 'nId'
                        JSRs[nJSRs] = l;
                        findSubroutineSuccessors(nId, JSRs, nJSRs + 1);
                    }
                } else if ((l.status & Label.RET) != 0) {
                    /*
                     * finds the JSR block in the JSRs stack that corresponds to
                     * this RET block, and updates the successors of this RET
                     * block accordingly. This corresponding JSR is the one that
                     * leads to the subroutine to which the RET block belongs.
                     * But the RET block can belong to several subroutines (if a
                     * nested subroutine returns to its parent subroutine
                     * implicitely, without a RET). So, in fact, the JSR that
                     * corresponds to this RET is the first block in the JSRs
                     * stack, starting from the bottom of the stack, that leads
                     * to a subroutine to which the RET block belongs.
                     */
                    for (int i = 0; i < nJSRs; ++i) {
                        int JSRstatus = JSRs[i].successors.next.successor.status;
                        if (((JSRstatus & ~0xFFF) & (l.status & ~0xFFF)) != 0) {
                            Edge e = new Edge();
                            e.info = l.inputStackTop;
                            e.successor = JSRs[i].successors.successor;
                            e.next = l.successors;
                            l.successors = e;
                            break;
                        }
                    }
                }
            }
            l = l.successor;
        }
    }

    // ------------------------------------------------------------------------
    // Utility methods: stack map frames
    // ------------------------------------------------------------------------

    /**
     * Visits a frame that has been computed from scratch.
     * 
     * @param f the frame that must be visited.
     */
    private void visitFrame(final Frame f) {
        int i, t;
        int nTop = 0;
        int nLocal = 0;
        int nStack = 0;
        int[] locals = f.inputLocals;
        int[] stacks = f.inputStack;
        // computes the number of locals (ignores TOP types that are just after
        // a LONG or a DOUBLE, and all trailing TOP types)
        for (i = 0; i < locals.length; ++i) {
            t = locals[i];
            if (t == Frame.TOP) {
                ++nTop;
            } else {
                nLocal += nTop + 1;
                nTop = 0;
            }
            if (t == Frame.LONG || t == Frame.DOUBLE) {
                ++i;
            }
        }
        // computes the stack size (ignores TOP types that are just after
        // a LONG or a DOUBLE)
        for (i = 0; i < stacks.length; ++i) {
            t = stacks[i];
            ++nStack;
            if (t == Frame.LONG || t == Frame.DOUBLE) {
                ++i;
            }
        }
        // visits the frame and its content
        startFrame(f.owner.position, nLocal, nStack);
        for (i = 0; nLocal > 0; ++i, --nLocal) {
            t = locals[i];
            frame[frameIndex++] = t;
            if (t == Frame.LONG || t == Frame.DOUBLE) {
                ++i;
            }
        }
        for (i = 0; i < stacks.length; ++i) {
            t = stacks[i];
            frame[frameIndex++] = t;
            if (t == Frame.LONG || t == Frame.DOUBLE) {
                ++i;
            }
        }
        endFrame();
    }

    /**
     * Starts the visit of a stack map frame.
     * 
     * @param offset the offset of the instruction to which the frame
     *        corresponds.
     * @param nLocal the number of local variables in the frame.
     * @param nStack the number of stack elements in the frame.
     */
    private void startFrame(final int offset, final int nLocal, final int nStack)
    {
        int n = 3 + nLocal + nStack;
        if (frame == null || frame.length < n) {
            frame = new int[n];
        }
        frame[0] = offset;
        frame[1] = nLocal;
        frame[2] = nStack;
        frameIndex = 3;
    }

    /**
     * Checks if the visit of the current frame {@link #frame} is finished, and
     * if yes, write it in the StackMapTable attribute.
     */
    private void endFrame() {
        if (previousFrame != null) { // do not write the first frame
            if (stackMap == null) {
                stackMap = new ByteVector();
            }
            writeFrame();
            ++frameCount;
        }
        previousFrame = frame;
        frame = null;
    }

    /**
     * Compress and writes the current frame {@link #frame} in the StackMapTable
     * attribute.
     */
    private void writeFrame() {
        int clocalsSize = frame[1];
        int cstackSize = frame[2];
        if ((cw.version & 0xFFFF) < Opcodes.V1_6) {
            stackMap.putShort(frame[0]).putShort(clocalsSize);
            writeFrameTypes(3, 3 + clocalsSize);
            stackMap.putShort(cstackSize);
            writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize);
            return;
        }
        int localsSize = previousFrame[1];
        int type = FULL_FRAME;
        int k = 0;
        int delta;
        if (frameCount == 0) {
            delta = frame[0];
        } else {
            delta = frame[0] - previousFrame[0] - 1;
        }
        if (cstackSize == 0) {
            k = clocalsSize - localsSize;
            switch (k) {
                case -3:
                case -2:
                case -1:
                    type = CHOP_FRAME;
                    localsSize = clocalsSize;
                    break;
                case 0:
                    type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED;
                    break;
                case 1:
                case 2:
                case 3:
                    type = APPEND_FRAME;
                    break;
            }
        } else if (clocalsSize == localsSize && cstackSize == 1) {
            type = delta < 63
                    ? SAME_LOCALS_1_STACK_ITEM_FRAME
                    : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
        }
        if (type != FULL_FRAME) {
            // verify if locals are the same
            int l = 3;
            for (int j = 0; j < localsSize; j++) {
                if (frame[l] != previousFrame[l]) {
                    type = FULL_FRAME;
                    break;
                }
                l++;
            }
        }
        switch (type) {
            case SAME_FRAME:
                stackMap.putByte(delta);
                break;
            case SAME_LOCALS_1_STACK_ITEM_FRAME:
                stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
                writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
                break;
            case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
                stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
                        .putShort(delta);
                writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
                break;
            case SA

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -