org.glassfish.pfl.tf.spi.Util Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of webservices-rt Show documentation
Show all versions of webservices-rt Show documentation
This module contains the Metro runtime code.
/*
* 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 ;
}
}