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

org.glassfish.pfl.tf.spi.Util Maven / Gradle / Ivy

There is a newer version: 4.0.4
Show newest version
/*
 * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Distribution License v. 1.0, which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

package org.glassfish.pfl.tf.spi;

import java.io.PrintWriter;
import org.glassfish.pfl.basic.func.UnaryFunction;
import org.glassfish.pfl.objectweb.asm.ClassAdapter;
import org.glassfish.pfl.objectweb.asm.ClassReader;
import org.glassfish.pfl.objectweb.asm.ClassVisitor;
import org.glassfish.pfl.objectweb.asm.ClassWriter;
import org.glassfish.pfl.objectweb.asm.MethodVisitor;
import org.glassfish.pfl.objectweb.asm.Opcodes;
import org.glassfish.pfl.objectweb.asm.Type;
import org.glassfish.pfl.objectweb.asm.tree.LocalVariableNode;
import org.glassfish.pfl.objectweb.asm.tree.MethodInsnNode;
import org.glassfish.pfl.objectweb.asm.tree.MethodNode;
import org.glassfish.pfl.objectweb.asm.util.AbstractVisitor;
import org.glassfish.pfl.objectweb.asm.util.CheckClassAdapter;

/** Some useful utilities for generating code using ASM.  Nothing in here
 * should be specific to the classfile enhancer for tracing.
 *
 * @author ken
 */
public class Util {
    private final boolean debug ;
    private final int verbose ;

    public Util( final boolean debug, final int verbose ) {
        this.debug = debug ;

        if (debug && (verbose < 1)) {
            this.verbose = 1 ;
        } else {
            this.verbose = verbose ;
        }
    }

    public boolean getDebug() {
        return debug ;
    }

    public void info( int level, String str ) {
        if (verbose >= level) {
            final String format = level>1 ? "%" + (4*(level-1) + 1) + "s"
                                          : "%s" ;
            final String pad = String.format( format, ">" ) ;
            msg( pad + str ) ;
        }
    }

    public void msg( String str ) {
        System.out.println( str ) ;
    }

    public void error( String str ) {
        throw new RuntimeException( str ) ;
    }

    public void initLocal( MethodVisitor mv, LocalVariableNode var ) {
        info( 2, "Initializing variable " + var ) ;
        Type type = Type.getType( var.desc ) ;
        switch (type.getSort()) {
            case Type.BYTE :
            case Type.BOOLEAN :
            case Type.CHAR :
            case Type.SHORT :
            case Type.INT :
                mv.visitInsn( Opcodes.ICONST_0 ) ;
                mv.visitVarInsn( Opcodes.ISTORE, var.index ) ;
                break ;

            case Type.LONG :
                mv.visitInsn( Opcodes.LCONST_0 ) ;
                mv.visitVarInsn( Opcodes.LSTORE, var.index ) ;
                break ;

            case Type.FLOAT :
                mv.visitInsn( Opcodes.FCONST_0 ) ;
                mv.visitVarInsn( Opcodes.FSTORE, var.index ) ;
                break ;

            case Type.DOUBLE :
                mv.visitInsn( Opcodes.DCONST_0 ) ;
                mv.visitVarInsn( Opcodes.DSTORE, var.index ) ;
                break ;

            default :
                mv.visitInsn( Opcodes.ACONST_NULL ) ;
                mv.visitVarInsn( Opcodes.ASTORE, var.index ) ;
        }
    }

    public String getFullMethodDescriptor( String name, String desc ) {
        return name + desc ;
    }

    public String getFullMethodDescriptor( MethodNode mn ) {
        return mn.name + mn.desc ;
    }

    public String getFullMethodDescriptor( MethodInsnNode mn ) {
        return mn.name + mn.desc ;
    }

    public String getFullMethodDescriptor( java.lang.reflect.Method method ) {
	final String desc = Type.getMethodDescriptor(method) ;
	return method.getName() + desc ;
    }

    public void newWithSimpleConstructor( MethodVisitor mv, Class cls ) {
        info( 2, "generating new for class " + cls ) ;
        Type type = Type.getType( cls ) ;
        mv.visitTypeInsn( Opcodes.NEW, type.getInternalName() );
        mv.visitInsn( Opcodes.DUP ) ;
        mv.visitMethodInsn( Opcodes.INVOKESPECIAL,
            type.getInternalName(), "", "()V" );
    }

    public String augmentInfoMethodDescriptor( String desc ) {
        info( 2, "Augmenting infoMethod descriptor " + desc ) ;
        // Compute new descriptor
        Type[] oldArgTypes = Type.getArgumentTypes( desc ) ;
        Type retType = Type.getReturnType( desc ) ;

        int oldlen = oldArgTypes.length ;
        Type[] argTypes = new Type[ oldlen + 2 ] ;
        System.arraycopy(oldArgTypes, 0, argTypes, 0, oldlen);

        argTypes[oldlen] = Type.getType( MethodMonitor.class ) ;
        argTypes[oldlen+1] = Type.INT_TYPE ;

        String newDesc = Type.getMethodDescriptor(retType, argTypes) ;
        info( 3, "result is " + newDesc ) ;
        return newDesc ;
    }

    public void emitIntConstant( MethodVisitor mv, int val ) {
        info( 2, "Emitting constant " + val ) ;
        if (val <= 5) {
            switch (val) {
                case 0:
                    mv.visitInsn( Opcodes.ICONST_0 ) ;
                    break ;
                case 1:
                    mv.visitInsn( Opcodes.ICONST_1 ) ;
                    break ;
                case 2:
                    mv.visitInsn( Opcodes.ICONST_2 ) ;
                    break ;
                case 3:
                    mv.visitInsn( Opcodes.ICONST_3 ) ;
                    break ;
                case 4:
                    mv.visitInsn( Opcodes.ICONST_4 ) ;
                    break ;
                case 5:
                    mv.visitInsn( Opcodes.ICONST_5 ) ;
                    break ;
            }
        } else {
            mv.visitLdcInsn( val );
        }
    }

    // Wrap the argument at index argIndex of type atype into
    // an Object as needed.  Returns the index of the next
    // argument.
    public int wrapArg( MethodVisitor mv, int argIndex, Type atype ) {
        info( 2, "Emitting code to wrap argument at " + argIndex
            + " of type " + atype ) ;

        switch (atype.getSort() ) {
            case Type.BOOLEAN :
                mv.visitVarInsn( Opcodes.ILOAD,  argIndex ) ;
                mv.visitMethodInsn( Opcodes.INVOKESTATIC,
                    Type.getInternalName( Boolean.class ), "valueOf",
                    "(Z)Ljava/lang/Boolean;" );
                break ;
            case Type.BYTE :
                mv.visitVarInsn( Opcodes.ILOAD,  argIndex ) ;
                mv.visitMethodInsn( Opcodes.INVOKESTATIC,
                    Type.getInternalName( Byte.class ), "valueOf",
                    "(B)Ljava/lang/Byte;" );
                break ;
            case Type.CHAR :
                mv.visitVarInsn( Opcodes.ILOAD,  argIndex ) ;
                mv.visitMethodInsn( Opcodes.INVOKESTATIC,
                    Type.getInternalName( Character.class ), "valueOf",
                    "(C)Ljava/lang/Character;" );
                break ;
            case Type.SHORT :
                mv.visitVarInsn( Opcodes.ILOAD,  argIndex ) ;
                mv.visitMethodInsn( Opcodes.INVOKESTATIC,
                    Type.getInternalName( Short.class ), "valueOf",
                    "(S)Ljava/lang/Short;" );
                break ;
            case Type.INT :
                mv.visitVarInsn( Opcodes.ILOAD,  argIndex ) ;
                mv.visitMethodInsn( Opcodes.INVOKESTATIC,
                    Type.getInternalName( Integer.class ), "valueOf",
                    "(I)Ljava/lang/Integer;" );
                break ;
            case Type.LONG :
                mv.visitVarInsn( Opcodes.LLOAD,  argIndex ) ;
                mv.visitMethodInsn( Opcodes.INVOKESTATIC,
                    Type.getInternalName( Long.class ), "valueOf",
                    "(J)Ljava/lang/Long;" );
                break ;
            case Type.DOUBLE :
                mv.visitVarInsn( Opcodes.DLOAD,  argIndex ) ;
                mv.visitMethodInsn( Opcodes.INVOKESTATIC,
                    Type.getInternalName( Double.class ), "valueOf",
                    "(D)Ljava/lang/Double;" );
                break ;
            case Type.FLOAT :
                mv.visitVarInsn( Opcodes.FLOAD,  argIndex ) ;
                mv.visitMethodInsn( Opcodes.INVOKESTATIC,
                    Type.getInternalName( Float.class ), "valueOf",
                    "(F)Ljava/lang/Float;" );
                break ;
            default :
                mv.visitVarInsn( Opcodes.ALOAD,  argIndex ) ;
                break ;
        }

        return argIndex + atype.getSize() ;
    }

    // Emit code to wrap all of the argumnts as Object[],
    // which is left on the stack
    public void wrapArgs( MethodVisitor mv, int access, String desc ) {
        info( 2, "Wrapping args for descriptor " + desc ) ;

        Type[] atypes = Type.getArgumentTypes( desc ) ;
        emitIntConstant( mv, atypes.length ) ;
        mv.visitTypeInsn( Opcodes.ANEWARRAY, "java/lang/Object" ) ;

        int argIndex ;
        if ((access & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC) {
            argIndex = 0 ;
        } else {
            argIndex = 1 ;
        }

        for (int ctr=0; ctr opcodes.length)) {
            return "ILLEGAL[" + opcode + "]" ;
        } else {
            return opcodes[opcode] ;
        }
    }

    public byte[] transform( final boolean debug, final byte[] cls,
        final UnaryFunction factory ) {

        final ClassReader cr = new ClassReader(cls) ;
        final ClassWriter cw = new ClassWriter(
            ClassWriter.COMPUTE_MAXS ) ;
            // ClassWriter.COMPUTE_FRAMES + ClassWriter.COMPUTE_MAXS ) ;

        PrintWriter pw = null ;
        // TraceClassVisitor tcv = null ;
        ClassVisitor cv = cw ;

        if (debug) {
            pw = new PrintWriter( System.out ) ;
            // tcv = new TraceClassVisitor( cw, new PrintWriter( System.out ) ) ;
            // cv = tcv ;
        }

        ClassAdapter xform = factory.evaluate( cv ) ;

        try {
            cr.accept( xform, ClassReader.SKIP_FRAMES ) ;
        } catch (TraceEnhancementException exc) { 
            throw exc ;
        } catch (Exception exc) {
            info( 1, "Exception: " + exc ) ;
            if (debug) {
                exc.printStackTrace() ;
            }
        } finally {
            if (pw != null) {
                pw.flush() ;
                pw.close() ;
            }
        }

        byte[] enhancedClass = cw.toByteArray() ;

        verify( enhancedClass ) ;

        return enhancedClass ;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy