public void inline()

in bytekit-core/src/main/java/com/alibaba/bytekit/asm/MethodProcessor.java [668:761]


    public void inline(String owner, MethodNode toInlineMethodNode, boolean removeLineNumber) {

        ListIterator<AbstractInsnNode> originMethodIter = this.methodNode.instructions.iterator();

        while(originMethodIter.hasNext()) {
            AbstractInsnNode originMethodInsnNode = originMethodIter.next();

            if (originMethodInsnNode instanceof MethodInsnNode) {
                MethodInsnNode methodInsnNode = (MethodInsnNode) originMethodInsnNode;
                if (methodInsnNode.owner.equals(owner) && methodInsnNode.name.equals(toInlineMethodNode.name)
                        && methodInsnNode.desc.equals(toInlineMethodNode.desc)) {
                    // 要copy一份,否则inline多次会出问题
                    MethodNode tmpToInlineMethodNode = AsmUtils.copy(toInlineMethodNode);
                    if (removeLineNumber) {
                        tmpToInlineMethodNode = AsmUtils.removeLineNumbers(tmpToInlineMethodNode);
                    }

                    LabelNode end = new LabelNode();
                    this.methodNode.instructions.insert(methodInsnNode, end);

                    InsnList instructions = new InsnList();

                    // 要先记录好当前的 maxLocals ,然后再依次把 栈上的 args保存起来 ,后面调整 VarInsnNode index里,要加上当前的 maxLocals
                    // save args to local vars
                    int currentMaxLocals = this.nextLocals;

                    int off = (tmpToInlineMethodNode.access & Opcodes.ACC_STATIC) != 0 ? 0 : 1;
                    Type[] args = Type.getArgumentTypes(tmpToInlineMethodNode.desc);
                    int argsOff = off;

                    for(int i = 0; i < args.length; ++i) {
                        argsOff += args[i].getSize();
                    }
                    // 记录新的 maxLocals
                    this.nextLocals += argsOff;
                    methodNode.maxLocals = this.nextLocals;


                    for(int i = args.length - 1; i >= 0; --i) {
                        argsOff -= args[i].getSize();
//                        this.visitVarInsn(args[i].getOpcode(Opcodes.ISTORE), argsOff);

                        AsmOpUtils.storeVar(instructions, args[i], currentMaxLocals + argsOff);
                    }

                    // this
                    if (off > 0) {
//                        this.visitVarInsn(Opcodes.ASTORE, 0);
                        AsmOpUtils.storeVar(instructions, OBJECT_TYPE, currentMaxLocals);
                    }


                    ListIterator<AbstractInsnNode> inlineIterator = tmpToInlineMethodNode.instructions.iterator();
                    while(inlineIterator.hasNext()) {
                        AbstractInsnNode abstractInsnNode = inlineIterator.next();
                        if(abstractInsnNode instanceof FrameNode) {
                            continue;
                        }

                        //修改inline代码中的使用到局部变量的指令的var操作数(变量slot)
                        if(abstractInsnNode instanceof  VarInsnNode) {
                            VarInsnNode varInsnNode = (VarInsnNode) abstractInsnNode;
                            varInsnNode.var += currentMaxLocals;
                        } else if (abstractInsnNode instanceof IincInsnNode) {
                            IincInsnNode iincInsnNode = (IincInsnNode) abstractInsnNode;
                            iincInsnNode.var += currentMaxLocals;
                        }

                        int opcode = abstractInsnNode.getOpcode();
                        if (opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) {
//                            super.visitJumpInsn(Opcodes.GOTO, end);
//                            instructions.add(new JumpInsnNode(Opcodes.GOTO, end));
                            inlineIterator.remove();
                            instructions.add(new JumpInsnNode(Opcodes.GOTO, end));
                            continue;
                        }
                        inlineIterator.remove();
                        instructions.add(abstractInsnNode);
                    }


                    // 插入inline之后的代码,再删除掉原来的 MethodInsnNode
                    this.methodNode.instructions.insertBefore(methodInsnNode, instructions);
                    originMethodIter.remove();
                    // try catch 块加上,然后排序
                    if(this.methodNode.tryCatchBlocks != null && tmpToInlineMethodNode.tryCatchBlocks != null) {
                        this.methodNode.tryCatchBlocks.addAll(tmpToInlineMethodNode.tryCatchBlocks);
                    }
                    this.sortTryCatchBlock();
                }
            }
        }

    }