package org.glassfish.pfl.dynamic.codegen.impl;
import java.util.Properties ;
import java.util.HashSet ;
import java.util.HashMap ;
import java.io.IOException ;
import java.io.PrintStream ;
import java.io.FileOutputStream ;
import java.io.File ;
import org.glassfish.pfl.objectweb.asm.ClassWriter ;
import org.glassfish.pfl.objectweb.asm.ClassVisitor ;
import org.glassfish.pfl.objectweb.asm.MethodVisitor ;
import org.glassfish.pfl.objectweb.asm.ClassAdapter ;
import org.glassfish.pfl.objectweb.asm.MethodAdapter ;
import org.glassfish.pfl.objectweb.asm.ClassReader ;
import org.glassfish.pfl.objectweb.asm.util.CheckClassAdapter ;
import org.glassfish.pfl.dynamic.codegen.spi.ImportList ;
import org.glassfish.pfl.dynamic.codegen.spi.Type ;
import org.glassfish.pfl.dynamic.codegen.spi.Variable ;
import org.glassfish.pfl.dynamic.codegen.spi.Wrapper ;
import java.io.PrintWriter;
import org.glassfish.pfl.basic.contain.Pair;
import org.glassfish.pfl.basic.func.NullaryFunction;
public class ASMUtil {
public enum RequiredEmitterType { GETTER, SETTER, NONE } ;
public static String bcName( Type type ) {
return type.name().replace( '.', '/' ) ;
}
private static void displayNode( PrintStream ps, String msg, Node node ) {
ps.println( ) ;
ps.println( "=======================================================" ) ;
ps.println( msg ) ;
Util.display( node, ps ) ;
ps.println() ;
Util.checkTree( node, ps ) ;
ps.println() ;
ps.println( "=======================================================" ) ;
}
public static void generateSourceCode( PrintStream ps, ClassGeneratorImpl cg,
ImportList imports, Properties options ) throws IOException {
TreeWalkerContext context = new TreeWalkerContext() ;
Visitor visitor = new SourceStatementVisitor( context,
imports, new CodegenPrinter( ps ) ) ;
cg.accept( visitor ) ;
}
public static File getFile( String genDir, String className,
String suffix ) {
Pair<String,String> names = Wrapper.splitClassName( className ) ;
String pkgName = names.first().replace( '.', File.separatorChar ) ;
File sdir = new File( genDir, pkgName ) ;
sdir.mkdirs() ;
String sfname = names.second() + suffix ;
File sfile = new File( sdir, sfname ) ;
return sfile ;
}
public static void generateSourceCode( String sourceGenDir, ClassGeneratorImpl cg,
ImportList imports, Properties options ) throws IOException {
PrintStream ps = null ;
try {
File sfile = getFile( sourceGenDir, cg.name(), ".java" ) ;
ps = new PrintStream( sfile ) ;
generateSourceCode( ps, cg, imports, options ) ;
} finally {
if (ps != null)
ps.close() ;
}
}
private static class FixStackSizeClassVisitor extends ClassAdapter {
public FixStackSizeClassVisitor( final ClassVisitor cv ) {
super( cv ) ;
}
public MethodVisitor visitMethod( final int access, final String name,
final String desc, final String signature, final String[] exceptions ) {
MethodVisitor mv = cv.visitMethod( access, name, desc, signature, exceptions ) ;
return mv == null ? null : new FixStackSizeMethodVisitor( mv ) ;
}
}
private static class FixStackSizeMethodVisitor extends MethodAdapter {
public FixStackSizeMethodVisitor( final MethodVisitor mv ) {
super( mv ) ;
}
public void visitMaxs( int maxStack, int maxLocals ) {
mv.visitMaxs( 0, 0 ) ;
}
}
private static byte[] fixStackSize( byte[] code ) {
ClassReader cr = new ClassReader( code );
ClassWriter cw = new ClassWriter( ClassWriter.COMPUTE_MAXS ) ;
ClassVisitor visitor = new FixStackSizeClassVisitor( cw ) ;
cr.accept( visitor, 0 ) ;
return cw.toByteArray() ;
}
public static byte[] generate( ClassLoader cl, ClassGeneratorImpl cg,
ImportList imports, Properties options, PrintStream debugOutput ) {
CurrentClassLoader.set( cl ) ;
boolean dumpConstantPool = false ;
boolean dumpAfterSetupVisitor = false ;
boolean traceByteCodeGeneration = false ;
boolean useAsmVerifier = false ;
String classGenDir = null ;
String sourceGenDir = null ;
if (options != null) {
dumpConstantPool = Boolean.parseBoolean(
options.getProperty( Wrapper.DUMP_CONSTANT_POOL )) ;
dumpAfterSetupVisitor = Boolean.parseBoolean(
options.getProperty( Wrapper.DUMP_AFTER_SETUP_VISITOR )) ;
traceByteCodeGeneration = Boolean.parseBoolean(
options.getProperty( Wrapper.TRACE_BYTE_CODE_GENERATION )) ;
useAsmVerifier = Boolean.parseBoolean(
options.getProperty( Wrapper.USE_ASM_VERIFIER )) ;
classGenDir = options.getProperty(
Wrapper.CLASS_GENERATION_DIRECTORY ) ;
sourceGenDir = options.getProperty(
Wrapper.SOURCE_GENERATION_DIRECTORY ) ;
}
if (sourceGenDir != null) {
try {
generateSourceCode( sourceGenDir, cg, imports, options ) ;
} catch (IOException exc) {
throw new IllegalArgumentException(
"Could not generate source code for class "
+ cg.name(), exc ) ;
}
}
ClassWriter cw = new ClassWriter( ClassWriter.COMPUTE_MAXS ) ;
TreeWalkerContext twc = new TreeWalkerContext() ;
Visitor v1 = new ASMSetupVisitor( twc ) ;
cg.accept( v1 ) ;
if (dumpAfterSetupVisitor)
displayNode( debugOutput, "Contents of AST after SetupVisitor", cg ) ;
twc = new TreeWalkerContext() ;
Visitor v2 = new ASMByteCodeVisitor( twc, cw, traceByteCodeGeneration,
debugOutput ) ;
cg.accept( v2 ) ;
byte[] result = fixStackSize( cw.toByteArray() ) ;
if (dumpConstantPool) {
}
if (classGenDir != null) {
File cfile = getFile( classGenDir, cg.name(), ".class" ) ;
FileOutputStream fos = null ;
try {
fos = new FileOutputStream( cfile ) ;
fos.write( result, 0, result.length ) ;
} catch (IOException exc) {
throw new IllegalArgumentException(
"Could not dump generated bytecode to file "
+ cfile ) ;
} finally {
if (fos != null)
try {
fos.close() ;
} catch (IOException exc) {
}
}
}
if (useAsmVerifier) {
debugOutput.println( "*** Using ASM verifier ***" ) ;
verify( debugOutput, result ) ;
}
return result ;
}
private static void verify( final PrintStream ps, byte[] classData ) {
ClassReader cr = new ClassReader( classData ) ;
PrintWriter pw = new PrintWriter( ps ) ;
CheckClassAdapter.verify( cr, true, pw ) ;
}
private static NullaryFunction<MyLabel> makeLabel =
new NullaryFunction<MyLabel>() {
public MyLabel evaluate() {
return new MyLabel() ;
}
} ;
static Attribute<MyLabel> returnLabel = new Attribute<MyLabel>(
MyLabel.class, "returnLabel", makeLabel ) ;
static Attribute<MyLabel> statementStartLabel = new Attribute<MyLabel>(
MyLabel.class, "statementStartLabel", makeLabel ) ;
static Attribute<MyLabel> statementEndLabel = new Attribute<MyLabel>(
MyLabel.class, "statementEndLabel", makeLabel ) ;
static Attribute<MyLabel> throwEndLabel = new Attribute<MyLabel>(
MyLabel.class, "throwEndLabel", makeLabel ) ;
static Attribute<Node> next = new Attribute<Node>(
Node.class, "next", (Node)null ) ;
static Attribute<Variable> returnVariable = new Attribute<Variable>(
Variable.class, "returnVariable", (Variable)null ) ;
static Attribute<Integer> stackFrameSlot = new Attribute<Integer>(
Integer.class, "stackFrameSlot", 0 ) ;
static Attribute<EmitterFactory.Emitter> getEmitter = new Attribute<EmitterFactory.Emitter>(
EmitterFactory.Emitter.class, "getEmitter", (EmitterFactory.Emitter)null ) ;
static Attribute<EmitterFactory.Emitter> setEmitter = new Attribute<EmitterFactory.Emitter>(
EmitterFactory.Emitter.class, "setEmitter", (EmitterFactory.Emitter)null ) ;
static Attribute<EmitterFactory.Emitter> emitter = new Attribute<EmitterFactory.Emitter>(
EmitterFactory.Emitter.class, "emitter", (EmitterFactory.Emitter)null ) ;
static Attribute<RequiredEmitterType> requiredEmitterType = new Attribute<RequiredEmitterType>(
RequiredEmitterType.class, "requiredEmitterType", RequiredEmitterType.GETTER ) ;
static Attribute<Statement> lastStatement = new Attribute<Statement>(
Statement.class, "lastStatement", (Statement)null ) ;
static Attribute<Variable> uncaughtException = new Attribute<Variable>(
Variable.class, "uncaughtException", (Variable)null ) ;
static Attribute<Variable> returnAddress = new Attribute<Variable>(
Variable.class, "returnAddress", (Variable)null ) ;
static Attribute<BlockStatement> lastBlock = new Attribute<BlockStatement>(
BlockStatement.class, "lastBlock", (BlockStatement)null ) ;
static Attribute<MyLabel> uncaughtExceptionHandler = new Attribute<MyLabel>(
MyLabel.class, "uncaughtExceptionHandler", makeLabel ) ;
static Attribute<Integer> ctr = new Attribute<Integer>(
Integer.class, "ctr", 0 ) ;
public static class LineNumberTable extends HashMap<MyLabel,Integer> {
public LineNumberTable() {
super() ;
}
}
private static NullaryFunction<LineNumberTable> tableMaker =
new NullaryFunction<LineNumberTable>() {
public LineNumberTable evaluate() {
return new LineNumberTable() ;
}
} ;
static Attribute<LineNumberTable> lineNumberTable = new Attribute<LineNumberTable>(
LineNumberTable.class, "lineNumberTable", tableMaker ) ;
public static class VariablesInMethod extends HashSet<Variable> {
public VariablesInMethod() {
super() ;
}
}
private static NullaryFunction<VariablesInMethod> vmMaker =
new NullaryFunction<VariablesInMethod>() {
public VariablesInMethod evaluate() {
return new VariablesInMethod() ;
}
} ;
static Attribute<VariablesInMethod> variablesInMethod = new Attribute<VariablesInMethod>(
VariablesInMethod.class, "variablesInMethod", vmMaker ) ;
}