All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.codehaus.groovy.classgen.asm.MethodCallInliner Maven / Gradle / Ivy

There is a newer version: 3.9
Show newest version
/*
 * Copyright 2003-2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.codehaus.groovy.classgen.asm;

import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.LocalVariablesSorter;
import org.objectweb.asm.commons.Remapper;
import org.objectweb.asm.commons.RemappingMethodAdapter;
import org.objectweb.asm.commons.SimpleRemapper;
import org.objectweb.asm.tree.MethodNode;

import java.util.*;

public class MethodCallInliner
        extends LocalVariablesSorter {
    private final String oldClass;
    private final String newClass;
    private final MethodNode mn;
    private List blocks = new ArrayList();
    private boolean inlining;

    private MethodCallInliner(int access,
                              String desc, MethodVisitor mv, MethodNode mn,
                              String oldClass, String newClass) {
        super(access, desc, mv);
        this.oldClass = oldClass;
        this.newClass = newClass;
        this.mn = mn;
    }

    public void visitMethodInsn(int opcode,
                                String owner, String name, String desc) {
        if (!canBeInlined(owner, name, desc)) {
            mv.visitMethodInsn(opcode,
                    owner, name, desc);
            return;
        }
        Map map = Collections.singletonMap(
                oldClass, newClass);
        Remapper remapper = new SimpleRemapper(map);
        Label end = new Label();
        inlining = true;
        mn.instructions.resetLabels();
        mn.accept(new InliningAdapter(this,
                opcode == Opcodes.INVOKESTATIC ?
                        Opcodes.ACC_STATIC : 0,
                desc, remapper, end));
        inlining = false;
        super.visitLabel(end);
    }

    private boolean canBeInlined(final String owner, final String name, final String desc) {
        return "org/codehaus/groovy/runtime/DefaultGroovyMethods".equals(owner);
    }

    public void visitTryCatchBlock(Label start,
                                   Label end, Label handler, String type) {
        if (!inlining) {
            blocks.add(new CatchBlock(start, end,
                    handler, type));
        } else {
            super.visitTryCatchBlock(start, end,
                    handler, type);
        }
    }

    public void visitMaxs(int stack, int locals) {
        Iterator it = blocks.iterator();
        while (it.hasNext()) {
            CatchBlock b = (CatchBlock) it.next();
            super.visitTryCatchBlock(b.start, b.end,
                    b.handler, b.type);
        }
        super.visitMaxs(stack, locals);
    }

    public static class InliningAdapter
            extends RemappingMethodAdapter {
        private final LocalVariablesSorter lvs;
        private final Label end;

        public InliningAdapter(LocalVariablesSorter mv,
                               int acc, String desc,
                               Remapper remapper,
                               Label end) {
            super(acc, desc, mv, remapper);
            this.lvs = mv;
            this.end = end;
            int off = (acc & Opcodes.ACC_STATIC) != 0 ?
                    0 : 1;
            Type[] args = Type.getArgumentTypes(desc);
            for (int i = args.length - 1; i >= 0; i--) {
                super.visitVarInsn(args[i].getOpcode(
                        Opcodes.ISTORE), i + off);
            }
            if (off > 0) {
                super.visitVarInsn(Opcodes.ASTORE, 0);
            }
        }

        public void visitInsn(int opcode) {
            if (opcode == Opcodes.RETURN) {
                super.visitJumpInsn(Opcodes.GOTO, end);
            } else {
                super.visitInsn(opcode);
            }
        }

        public void visitMaxs(int stack, int locals) {
        }

        protected int newLocalMapping(Type type) {
            return lvs.newLocal(type);
        }
    }

    private static class CatchBlock {
        private final Label start;
        private final Label end;
        private final Label handler;
        private final String type;

        private CatchBlock(final Label end, final Label start, final Label handler, final String type) {
            this.end = end;
            this.start = start;
            this.handler = handler;
            this.type = type;
        }
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy