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

com.sun.btrace.runtime.ClinitInjector Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.btrace.runtime;

import com.sun.btrace.org.objectweb.asm.ClassVisitor;
import com.sun.btrace.org.objectweb.asm.MethodVisitor;
import com.sun.btrace.org.objectweb.asm.Opcodes;
import com.sun.btrace.org.objectweb.asm.Type;

/**
 * This class adapter injects a freshly loaded class with instructions to invoke
 * BTrace class retransformation upon invoking its static initializer.
 * @author Jaroslav Bachorik
 */
public class ClinitInjector extends ClassVisitor {
    private static String CLINIT = "";
    
    private boolean clinitFound = false;
    private boolean transformed = false;
    private final String runtime;
    private final String cname;
    
    public ClinitInjector(ClassVisitor cv, String runtime, String cname) {
        super(Opcodes.ASM4, cv);
        this.runtime = runtime;
        this.cname = cname;
    }

    public boolean isTransformed() {
        return transformed;
    }
    
    @Override
    public void visit(int version, int access, String name, String signature, String supername, String[] interfaces) {
        if (((access & (Opcodes.ACC_INTERFACE | Opcodes.ACC_ANNOTATION)) != 0) ||
            (supername.equals("java/lang/Object") && interfaces.length == 0)) return;
        transformed = true;
        int major = version & 0x0000ffff;
        super.visit(major < Opcodes.V1_5 ? Opcodes.V1_5 : version, access, name, signature, supername, interfaces);
    }
    
    

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
        MethodVisitor visitor = super.visitMethod(access, name, desc, signature, exceptions);
        if (CLINIT.equals(name)) {
            visitor = new MethodVisitor(Opcodes.ASM4, visitor) {
                private boolean exitFound = false;
                private int requiredStack = 0;
                @Override
                public void visitCode() {
                    requiredStack = generateClinit(mv);
                    super.visitCode();
                }

                @Override
                public void visitMaxs(int maxStack, int maxLocals) {
                    super.visitMaxs(maxStack < requiredStack ? requiredStack : maxStack, maxLocals);
                }

                @Override
                public void visitInsn(int i) {
                    // checking for existence of a proper exit instruction
                    if (i == Opcodes.RETURN || i == Opcodes.IRETURN || 
                        i == Opcodes.LRETURN || i == Opcodes.DRETURN ||
                        i == Opcodes.FRETURN || i == Opcodes.ATHROW) {
                        exitFound = true;
                    }
                    super.visitInsn(i);
                }

                @Override
                public void visitEnd() {
                    if (!exitFound) {
                        // no proper exit instruction found; generate RETURN
                        super.visitInsn(Opcodes.RETURN);
                    }
                    super.visitEnd();
                }
            };
            clinitFound = true;
        }
        return visitor;
    }
    
    @Override
    public void visitEnd() {
        if (!clinitFound) {
            MethodVisitor mv = visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, CLINIT, "()V", null, null); // NOI18N
            // this will call this method's visitMethod method, effectively generating the clinit content
            mv.visitCode();
            // need to call visitMaxs explicitely
            mv.visitMaxs(0, 0);
            // properly close the method body
            mv.visitEnd();
        }
        super.visitEnd();
    }
    
    private int generateClinit(MethodVisitor mv) {
        Type clazz = Type.getType("L" + cname + ";");
        
        // the client name (the BTrace script class name)
        mv.visitLdcInsn(runtime);
        // the name of the currently processed class
        mv.visitLdcInsn(clazz); // NOI18N
        // invocatio nof BTraceRuntime.retransform() method
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/sun/btrace/BTraceRuntime", "retransform", "(Ljava/lang/String;Ljava/lang/Class;)V"); // NOI18N
        
        return clazz.getSize() + Type.getType(String.class).getSize();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy