package railo.transformer.bytecode; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; 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.GeneratorAdapter; import org.objectweb.asm.commons.Method; import railo.commons.io.CharsetUtil; import railo.commons.io.IOUtil; import railo.commons.io.res.Resource; import railo.commons.lang.NumberUtil; import railo.commons.lang.StringUtil; import railo.runtime.Mapping; import railo.runtime.PageSource; import railo.runtime.component.ImportDefintion; import railo.runtime.component.ImportDefintionImpl; import railo.runtime.config.Config; import railo.runtime.exp.TemplateException; import railo.runtime.type.KeyImpl; import railo.runtime.type.StructImpl; import railo.runtime.type.UDF; import railo.runtime.type.scope.Undefined; import railo.runtime.type.util.KeyConstants; import railo.transformer.bytecode.expression.Expression; import railo.transformer.bytecode.literal.LitString; import railo.transformer.bytecode.literal.LitString.Range; import railo.transformer.bytecode.statement.Argument; import railo.transformer.bytecode.statement.HasBodies; import railo.transformer.bytecode.statement.HasBody; import railo.transformer.bytecode.statement.IFunction; import railo.transformer.bytecode.statement.NativeSwitch; import railo.transformer.bytecode.statement.tag.Attribute; import railo.transformer.bytecode.statement.tag.Tag; import railo.transformer.bytecode.statement.tag.TagImport; import railo.transformer.bytecode.statement.tag.TagThread; import railo.transformer.bytecode.statement.udf.Function; import railo.transformer.bytecode.statement.udf.FunctionImpl; import railo.transformer.bytecode.util.ASMConstants; import railo.transformer.bytecode.util.ASMUtil; import railo.transformer.bytecode.util.ExpressionUtil; import railo.transformer.bytecode.util.Types; import railo.transformer.bytecode.visitor.ArrayVisitor; import railo.transformer.bytecode.visitor.ConditionVisitor; import railo.transformer.bytecode.visitor.DecisionIntVisitor; import railo.transformer.bytecode.visitor.OnFinally; import railo.transformer.bytecode.visitor.TryCatchFinallyVisitor; /** * represent a single Page like "index.cfm" */ public final class Page extends BodyBase { public void doFinalize(BytecodeContext bc) { ExpressionUtil.visitLine(bc, getEnd()); } public static final Type NULL = Type.getType(railo.runtime.type.Null.class); public static final Type KEY_IMPL = Type.getType(KeyImpl.class); public static final Type KEY_CONSTANTS = Type.getType(KeyConstants.class); public static final Method KEY_INIT = new Method( "init", Types.COLLECTION_KEY, new Type[]{Types.STRING} ); public static final Method KEY_INTERN = new Method( "intern", Types.COLLECTION_KEY, new Type[]{Types.STRING} ); // public static ImportDefintion getInstance(String fullname,ImportDefintion defaultValue) private static final Method ID_GET_INSTANCE = new Method( "getInstance", Types.IMPORT_DEFINITIONS, new Type[]{Types.STRING,Types.IMPORT_DEFINITIONS} ); public final static Method STATIC_CONSTRUCTOR = Method.getMethod("void <clinit> ()V"); //public final static Method CONSTRUCTOR = Method.getMethod("void <init> ()V"); private static final Method CONSTRUCTOR = new Method( "<init>", Types.VOID, new Type[]{}// ); private static final Method CONSTRUCTOR_PS = new Method( "<init>", Types.VOID, new Type[]{Types.PAGE_SOURCE}// ); public static final Type STRUCT_IMPL = Type.getType(StructImpl.class); private static final Method INIT_STRUCT_IMPL = new Method( "<init>", Types.VOID, new Type[]{} ); // void call (railo.runtime.PageContext) private final static Method CALL = new Method( "call", Types.VOID, new Type[]{Types.PAGE_CONTEXT} ); /*/ void _try () private final static Method TRY = new Method( "_try", Types.VOID, new Type[]{} );*/ // int getVersion() private final static Method VERSION = new Method( "getVersion", Types.INT_VALUE, new Type[]{} ); // void _init() private final static Method _INIT = new Method( "initKeys", Types.VOID, new Type[]{} ); private final static Method SET_PAGE_SOURCE = new Method( "setPageSource", Types.VOID, new Type[]{Types.PAGE_SOURCE} ); // public ImportDefintion[] getImportDefintions() private final static Method GET_IMPORT_DEFINITIONS = new Method( "getImportDefintions", Types.IMPORT_DEFINITIONS_ARRAY, new Type[]{} ); // long getSourceLastModified() private final static Method LAST_MOD = new Method( "getSourceLastModified", Types.LONG_VALUE, new Type[]{} ); private final static Method COMPILE_TIME = new Method( "getCompileTime", Types.LONG_VALUE, new Type[]{} ); private static final Type USER_DEFINED_FUNCTION = Type.getType(UDF.class); private static final Method UDF_CALL = new Method( "udfCall", Types.OBJECT, new Type[]{Types.PAGE_CONTEXT, USER_DEFINED_FUNCTION, Types.INT_VALUE} ); private static final Method THREAD_CALL = new Method( "threadCall", Types.VOID, new Type[]{Types.PAGE_CONTEXT, Types.INT_VALUE} ); /*private static final Method UDF_DEFAULT_VALUE = new Method( "udfDefaultValue", Types.OBJECT, new Type[]{Types.PAGE_CONTEXT, Types.INT_VALUE, Types.INT_VALUE} );*/ private static final Method UDF_DEFAULT_VALUE = new Method( "udfDefaultValue", Types.OBJECT, new Type[]{Types.PAGE_CONTEXT, Types.INT_VALUE, Types.INT_VALUE,Types.OBJECT} ); private static final Method NEW_COMPONENT_IMPL_INSTANCE = new Method( "newInstance", Types.COMPONENT_IMPL, new Type[]{Types.PAGE_CONTEXT,Types.STRING,Types.BOOLEAN_VALUE} ); private static final Method NEW_INTERFACE_IMPL_INSTANCE = new Method( "newInstance", Types.INTERFACE_IMPL, new Type[]{Types.STRING,Types.BOOLEAN_VALUE,Types.MAP} ); // void init(PageContext pc,Component Impl c) throws PageException private static final Method INIT_COMPONENT = new Method( "initComponent", Types.VOID, new Type[]{Types.PAGE_CONTEXT,Types.COMPONENT_IMPL} ); private static final Method INIT_INTERFACE = new Method( "initInterface", Types.VOID, new Type[]{Types.INTERFACE_IMPL} ); // public boolean setMode(int mode) { private static final Method SET_MODE = new Method( "setMode", Types.INT_VALUE, new Type[]{Types.INT_VALUE} ); private static final Method CONSTR_INTERFACE_IMPL = new Method( "<init>", Types.VOID, new Type[]{ Types.INTERFACE_PAGE, Types.STRING, // extends Types.STRING, // hind Types.STRING, // display Types.STRING, // callpath Types.BOOLEAN_VALUE, // realpath Types.MAP, //interfaceudfs Types.MAP // meta } ); //void init(PageContext pageContext,ComponentPage componentPage) private static final Method INIT = new Method( "init", Types.VOID, new Type[]{Types.PAGE_CONTEXT,Types.COMPONENT_PAGE} ); private static final Method CHECK_INTERFACE = new Method( "checkInterface", Types.VOID, new Type[]{Types.PAGE_CONTEXT,Types.COMPONENT_PAGE} ); // boolean getOutput() private static final Method GET_OUTPUT = new Method( "getOutput", Types.BOOLEAN_VALUE, new Type[]{} ); private static final Method PUSH_BODY = new Method( "pushBody", Types.BODY_CONTENT, new Type[]{} ); /*/ boolean setSilent() private static final Method SET_SILENT = new Method( "setSilent", Types.BOOLEAN_VALUE, new Type[]{} ); */ // Scope beforeCall(PageContext pc) private static final Method BEFORE_CALL = new Method( "beforeCall", Types.VARIABLES, new Type[]{Types.PAGE_CONTEXT} ); private static final Method TO_PAGE_EXCEPTION = new Method( "toPageException", Types.PAGE_EXCEPTION, new Type[]{Types.THROWABLE}); // boolean unsetSilent() /*private static final Method UNSET_SILENT = new Method( "unsetSilent", Types.BOOLEAN_VALUE, new Type[]{} );*/ // void afterCall(PageContext pc, Scope parent) private static final Method AFTER_CALL = new Method( "afterConstructor", Types.VOID, new Type[]{Types.PAGE_CONTEXT,Types.VARIABLES} ); // ComponentImpl(ComponentPage,boolean, String, String, String) NS==No Style // Component Impl(ComponentPage,boolean, String, String, String, String) WS==With Style private static final Method CONSTR_COMPONENT_IMPL = new Method( "<init>", Types.VOID, new Type[]{ Types.COMPONENT_PAGE, Types.BOOLEAN, Types.BOOLEAN_VALUE, Types.STRING, Types.STRING, Types.STRING, Types.STRING, Types.STRING, Types.BOOLEAN_VALUE, Types.STRING, Types.BOOLEAN_VALUE, Types.BOOLEAN_VALUE, STRUCT_IMPL } ); private static final Method SET_EL = new Method( "setEL", Types.OBJECT, new Type[]{Types.STRING,Types.OBJECT} ); private static final Method UNDEFINED_SCOPE = new Method( "us", Types.UNDEFINED, new Type[]{} ); private static final Method FLUSH_AND_POP = new Method( "flushAndPop", Types.VOID, new Type[]{Types.PAGE_CONTEXT,Types.BODY_CONTENT} ); private static final Method CLEAR_AND_POP = new Method( "clearAndPop", Types.VOID, new Type[]{Types.PAGE_CONTEXT,Types.BODY_CONTENT} ); public static final byte CF = (byte)207; public static final byte _33 = (byte)51; private static final boolean ADD_C33 = false; //private static final String SUB_CALL_UDF = "udfCall"; private static final String SUB_CALL_UDF = "_"; private static final int DEFAULT_VALUE = 3; private int version; private long lastModifed; private String name; //private Body body=new Body(); private Resource source; private final String path; private boolean isComponent; private boolean isInterface; private List<IFunction> functions=new ArrayList<IFunction>(); private List<TagThread> threads=new ArrayList<TagThread>(); private boolean _writeLog; private boolean supressWSbeforeArg; private Resource staticTextLocation; private int len; private int off; private int methodCount=0; private final Config config; public Page(Config config,Resource source,String name,int version, long lastModifed, boolean writeLog, boolean supressWSbeforeArg) { name=name.replace('.', '/'); //body.setParent(this); this.name=name; this.version=version; this.lastModifed=lastModifed; this.source=source; this.path=source.getAbsolutePath(); this._writeLog=writeLog; this.supressWSbeforeArg=supressWSbeforeArg; this.config=config; } /** * result byte code as binary array * @param classFile * @return byte code * @throws IOException * @throws TemplateException */ public byte[] execute(PageSource source,Resource classFile) throws BytecodeException { Resource p = classFile.getParentResource().getRealResource(classFile.getName()+".txt"); List<LitString> keys=new ArrayList<LitString>(); ClassWriter cw = ASMUtil.getClassWriter(); //ClassWriter cw = new ClassWriter(true); ArrayList<String> imports = new ArrayList<String>(); getImports(imports, this); // parent String parent="railo/runtime/PagePlus"; if(isComponent()) parent="railo/runtime/ComponentPage"; else if(isInterface()) parent="railo/runtime/InterfacePage"; cw.visit(Opcodes.V1_2, Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL, name, null, parent, null); cw.visitSource(this.path, null); // static constructor //GeneratorAdapter statConstrAdapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC,STATIC_CONSTRUCTOR,null,null,cw); BytecodeContext statConstr = null;//new BytecodeContext(null,null,this,externalizer,keys,cw,name,statConstrAdapter,STATIC_CONSTRUCTOR,writeLog(),supressWSbeforeArg); // constructor GeneratorAdapter constrAdapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC,CONSTRUCTOR_PS,null,null,cw); BytecodeContext constr = new BytecodeContext(source,null,null,this,keys,cw,name,constrAdapter,CONSTRUCTOR_PS,writeLog(),supressWSbeforeArg); constrAdapter.loadThis(); Type t=Types.PAGE_PLUS; if(isComponent())t=Types.COMPONENT_PAGE; else if(isInterface())t=Types.INTERFACE_PAGE; constrAdapter.invokeConstructor(t, CONSTRUCTOR); // call _init() constrAdapter.visitVarInsn(Opcodes.ALOAD, 0); constrAdapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, constr.getClassName(), "initKeys", "()V"); // private static ImportDefintion[] test=new ImportDefintion[]{...}; { FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, "imports", "[Lrailo/runtime/component/ImportDefintion;", null, null); fv.visitEnd(); constrAdapter.visitVarInsn(Opcodes.ALOAD, 0); ArrayVisitor av=new ArrayVisitor(); av.visitBegin(constrAdapter,Types.IMPORT_DEFINITIONS,imports.size()); int index=0; Iterator<String> it = imports.iterator(); while(it.hasNext()){ av.visitBeginItem(constrAdapter,index++); constrAdapter.push(it.next()); ASMConstants.NULL(constrAdapter); constrAdapter.invokeStatic(Types.IMPORT_DEFINITIONS_IMPL, ID_GET_INSTANCE); av.visitEndItem(constrAdapter); } av.visitEnd(); constrAdapter.visitFieldInsn(Opcodes.PUTFIELD, name, "imports", "[Lrailo/runtime/component/ImportDefintion;"); } // getVersion GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , VERSION, null, null, cw); adapter.push(version); adapter.returnValue(); adapter.endMethod(); // public ImportDefintion[] getImportDefintions() if(imports.size()>0){ adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , GET_IMPORT_DEFINITIONS, null, null, cw); adapter.visitVarInsn(Opcodes.ALOAD, 0); adapter.visitFieldInsn(Opcodes.GETFIELD, name, "imports", "[Lrailo/runtime/component/ImportDefintion;"); adapter.returnValue(); adapter.endMethod(); } else { adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , GET_IMPORT_DEFINITIONS, null, null, cw); adapter.visitInsn(Opcodes.ICONST_0); adapter.visitTypeInsn(Opcodes.ANEWARRAY, "railo/runtime/component/ImportDefintion"); adapter.returnValue(); adapter.endMethod(); } // getSourceLastModified adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , LAST_MOD, null, null, cw); adapter.push(lastModifed); adapter.returnValue(); adapter.endMethod(); // getCompileTime adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , COMPILE_TIME, null, null, cw); adapter.push(System.currentTimeMillis()); adapter.returnValue(); adapter.endMethod(); // newInstance/initComponent/call if(isComponent()) { Tag component=getComponent(); writeOutNewComponent(statConstr,constr,keys,cw,component); writeOutInitComponent(statConstr,constr,keys,cw,component); } else if(isInterface()) { Tag interf=getInterface(); writeOutNewInterface(statConstr,constr,keys,cw,interf); writeOutInitInterface(statConstr,constr,keys,cw,interf); } else { writeOutCall(statConstr,constr,keys,cw); } // udfCall Function[] functions=getFunctions(); ConditionVisitor cv; DecisionIntVisitor div; // less/equal than 10 functions if(isInterface()){} else if(functions.length<=10) { adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , UDF_CALL, null, new Type[]{Types.THROWABLE}, cw); BytecodeContext bc = new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,UDF_CALL,writeLog(),supressWSbeforeArg); if(functions.length==0){} else if(functions.length==1){ ExpressionUtil.visitLine(bc,functions[0].getStart()); functions[0].getBody().writeOut(bc); ExpressionUtil.visitLine(bc,functions[0].getEnd()); } else writeOutUdfCallInner(bc,functions,0,functions.length); adapter.visitInsn(Opcodes.ACONST_NULL); adapter.returnValue(); adapter.endMethod(); } // more than 10 functions else { adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , UDF_CALL, null, new Type[]{Types.THROWABLE}, cw); BytecodeContext bc = new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,UDF_CALL,writeLog(),supressWSbeforeArg); cv = new ConditionVisitor(); cv.visitBefore(); int count=0; for(int i=0;i<functions.length;i+=10) { cv.visitWhenBeforeExpr(); div=new DecisionIntVisitor(); div.visitBegin(); adapter.loadArg(2); div.visitLT(); adapter.push(i+10); div.visitEnd(bc); cv.visitWhenAfterExprBeforeBody(bc); adapter.visitVarInsn(Opcodes.ALOAD, 0); adapter.visitVarInsn(Opcodes.ALOAD, 1); adapter.visitVarInsn(Opcodes.ALOAD, 2); adapter.visitVarInsn(Opcodes.ILOAD, 3); adapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, name, createFunctionName(++count), "(Lrailo/runtime/PageContext;Lrailo/runtime/type/UDF;I)Ljava/lang/Object;"); adapter.visitInsn(Opcodes.ARETURN);//adapter.returnValue(); cv.visitWhenAfterBody(bc); } cv.visitAfter(bc); adapter.visitInsn(Opcodes.ACONST_NULL); adapter.returnValue(); adapter.endMethod(); count=0; Method innerCall; for(int i=0;i<functions.length;i+=10) { innerCall = new Method(createFunctionName(++count),Types.OBJECT,new Type[]{Types.PAGE_CONTEXT, USER_DEFINED_FUNCTION, Types.INT_VALUE}); adapter = new GeneratorAdapter(Opcodes.ACC_PRIVATE+Opcodes.ACC_FINAL , innerCall, null, new Type[]{Types.THROWABLE}, cw); writeOutUdfCallInner(new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,innerCall,writeLog(),supressWSbeforeArg), functions, i, i+10>functions.length?functions.length:i+10); adapter.visitInsn(Opcodes.ACONST_NULL); adapter.returnValue(); adapter.endMethod(); } } // threadCall TagThread[] threads=getThreads(); if(true) { adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , THREAD_CALL, null, new Type[]{Types.THROWABLE}, cw); if(threads.length>0) writeOutThreadCallInner(new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,THREAD_CALL,writeLog(),supressWSbeforeArg),threads,0,threads.length); //adapter.visitInsn(Opcodes.ACONST_NULL); adapter.returnValue(); adapter.endMethod(); } // udfDefaultValue // less/equal than 10 functions if(isInterface()) {} else if(functions.length<=10) { adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , UDF_DEFAULT_VALUE, null, new Type[]{Types.PAGE_EXCEPTION}, cw); if(functions.length>0) writeUdfDefaultValueInner(new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,UDF_DEFAULT_VALUE,writeLog(),supressWSbeforeArg),functions,0,functions.length); adapter.loadArg(DEFAULT_VALUE); adapter.returnValue(); adapter.endMethod(); } else { adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , UDF_DEFAULT_VALUE, null, new Type[]{Types.PAGE_EXCEPTION}, cw); BytecodeContext bc = new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,UDF_DEFAULT_VALUE,writeLog(),supressWSbeforeArg); cv = new ConditionVisitor(); cv.visitBefore(); int count=0; for(int i=0;i<functions.length;i+=10) { cv.visitWhenBeforeExpr(); div=new DecisionIntVisitor(); div.visitBegin(); adapter.loadArg(1); div.visitLT(); adapter.push(i+10); div.visitEnd(bc); cv.visitWhenAfterExprBeforeBody(bc); adapter.visitVarInsn(Opcodes.ALOAD, 0); adapter.visitVarInsn(Opcodes.ALOAD, 1); adapter.visitVarInsn(Opcodes.ILOAD, 2); adapter.visitVarInsn(Opcodes.ILOAD, 3); adapter.visitVarInsn(Opcodes.ALOAD, 4); adapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, name, "udfDefaultValue"+(++count), "(Lrailo/runtime/PageContext;IILjava/lang/Object;)Ljava/lang/Object;"); adapter.visitInsn(Opcodes.ARETURN);//adapter.returnValue(); cv.visitWhenAfterBody(bc); } cv.visitAfter(bc); adapter.visitInsn(Opcodes.ACONST_NULL); adapter.returnValue(); adapter.endMethod(); count=0; Method innerDefaultValue; for(int i=0;i<functions.length;i+=10) { innerDefaultValue = new Method("udfDefaultValue"+(++count),Types.OBJECT,new Type[]{Types.PAGE_CONTEXT, Types.INT_VALUE, Types.INT_VALUE,Types.OBJECT}); adapter = new GeneratorAdapter(Opcodes.ACC_PRIVATE+Opcodes.ACC_FINAL , innerDefaultValue, null, new Type[]{Types.PAGE_EXCEPTION}, cw); writeUdfDefaultValueInner(new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,innerDefaultValue,writeLog(),supressWSbeforeArg), functions, i, i+10>functions.length?functions.length:i+10); adapter.loadArg(DEFAULT_VALUE); //adapter.visitInsn(Opcodes.ACONST_NULL); adapter.returnValue(); adapter.endMethod(); } } // register fields { GeneratorAdapter aInit = new GeneratorAdapter(Opcodes.ACC_PRIVATE+Opcodes.ACC_FINAL , _INIT, null, null, cw); BytecodeContext bcInit = new BytecodeContext(source,statConstr,constr,this,keys,cw,name,aInit,_INIT,writeLog(),supressWSbeforeArg); registerFields(bcInit,keys); aInit.returnValue(); aInit.endMethod(); } //setPageSource(pageSource); constrAdapter.visitVarInsn(Opcodes.ALOAD, 0); constrAdapter.visitVarInsn(Opcodes.ALOAD, 1); constrAdapter.invokeVirtual(t, SET_PAGE_SOURCE); //statConstr.getAdapter().returnValue(); //statConstr.getAdapter().endMethod(); constrAdapter.returnValue(); constrAdapter.endMethod(); if(ADD_C33) { byte[] tmp = cw.toByteArray(); byte[] bLastMod=NumberUtil.longToByteArray(lastModifed); byte[] barr = new byte[tmp.length+10]; // Magic Number barr[0]=CF; // CF barr[1]=_33; // 33 // Last Modified for(int i=0;i<8;i++){ barr[i+2]=bLastMod[i]; } for(int i=0;i<tmp.length;i++){ barr[i+10]=tmp[i]; } return barr; } return cw.toByteArray(); } private String createFunctionName(int i) { return "udfCall"+Integer.toString(i, Character.MAX_RADIX); } private boolean writeLog() { return _writeLog && !isInterface(); } public static void registerFields(BytecodeContext bc, List<LitString> keys) throws BytecodeException { //if(keys.size()==0) return; GeneratorAdapter ga = bc.getAdapter(); FieldVisitor fv = bc.getClassWriter().visitField(Opcodes.ACC_PRIVATE , "keys", Types.COLLECTION_KEY_ARRAY.toString(), null, null); fv.visitEnd(); int index=0; LitString value; Iterator<LitString> it = keys.iterator(); ga.visitVarInsn(Opcodes.ALOAD, 0); ga.push(keys.size()); ga.newArray(Types.COLLECTION_KEY); while(it.hasNext()) { value=it.next(); ga.dup(); ga.push(index++); //value.setExternalize(false); ExpressionUtil.writeOutSilent(value,bc, Expression.MODE_REF); ga.invokeStatic(KEY_IMPL, KEY_INTERN); ga.visitInsn(Opcodes.AASTORE); } ga.visitFieldInsn(Opcodes.PUTFIELD, bc.getClassName(), "keys", Types.COLLECTION_KEY_ARRAY.toString()); } private void writeUdfDefaultValueInner(BytecodeContext bc, Function[] functions, int offset, int length) throws BytecodeException { GeneratorAdapter adapter = bc.getAdapter(); ConditionVisitor cv = new ConditionVisitor(); DecisionIntVisitor div; cv.visitBefore(); for(int i=offset;i<length;i++) { cv.visitWhenBeforeExpr(); div = new DecisionIntVisitor(); div.visitBegin(); adapter.loadArg(1); div.visitEQ(); adapter.push(i); div.visitEnd(bc); cv.visitWhenAfterExprBeforeBody(bc); writeOutFunctionDefaultValueInnerInner(bc, functions[i]); cv.visitWhenAfterBody(bc); } cv.visitAfter(bc); } private void writeOutUdfCallInnerIf(BytecodeContext bc,Function[] functions, int offset, int length) throws BytecodeException { GeneratorAdapter adapter = bc.getAdapter(); ConditionVisitor cv=new ConditionVisitor(); DecisionIntVisitor div; cv.visitBefore(); for(int i=offset;i<length;i++) { cv.visitWhenBeforeExpr(); div=new DecisionIntVisitor(); div.visitBegin(); adapter.loadArg(2); div.visitEQ(); adapter.push(i); div.visitEnd(bc); cv.visitWhenAfterExprBeforeBody(bc); ExpressionUtil.visitLine(bc, functions[i].getStart()); functions[i].getBody().writeOut(bc); ExpressionUtil.visitLine(bc, functions[i].getEnd()); cv.visitWhenAfterBody(bc); } cv.visitAfter(bc); } private void writeOutUdfCallInner(BytecodeContext bc,Function[] functions, int offset, int length) throws BytecodeException { NativeSwitch ns=new NativeSwitch(2,NativeSwitch.ARG_REF,null,null); for(int i=offset;i<length;i++) { ns.addCase(i, functions[i].getBody(),functions[i].getStart(),functions[i].getEnd(),true); } ns._writeOut(bc); } private void writeOutThreadCallInner(BytecodeContext bc,TagThread[] threads, int offset, int length) throws BytecodeException { GeneratorAdapter adapter = bc.getAdapter(); ConditionVisitor cv=new ConditionVisitor(); DecisionIntVisitor div; cv.visitBefore(); //print.ln("functions:"+functions.length); for(int i=offset;i<length;i++) { cv.visitWhenBeforeExpr(); div=new DecisionIntVisitor(); div.visitBegin(); adapter.loadArg(1); div.visitEQ(); adapter.push(i); div.visitEnd(bc); cv.visitWhenAfterExprBeforeBody(bc); Body body = threads[i].getRealBody(); if(body!=null)body.writeOut(bc); cv.visitWhenAfterBody(bc); } cv.visitAfter(bc); } private void writeOutInitComponent(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys, ClassWriter cw, Tag component) throws BytecodeException { final GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , INIT_COMPONENT, null, new Type[]{Types.PAGE_EXCEPTION}, cw); BytecodeContext bc=new BytecodeContext(null,statConstr, constr,this,keys,cw,name,adapter,INIT_COMPONENT,writeLog(),supressWSbeforeArg); Label methodBegin=new Label(); Label methodEnd=new Label(); adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0); adapter.visitLabel(methodBegin); // Scope oldData=null; final int oldData=adapter.newLocal(Types.VARIABLES); ASMConstants.NULL(adapter); adapter.storeLocal(oldData); int localBC=adapter.newLocal(Types.BODY_CONTENT); ConditionVisitor cv=new ConditionVisitor(); cv.visitBefore(); cv.visitWhenBeforeExpr(); adapter.loadArg(1); adapter.invokeVirtual(Types.COMPONENT_IMPL, GET_OUTPUT); cv.visitWhenAfterExprBeforeBody(bc); ASMConstants.NULL(adapter); cv.visitWhenAfterBody(bc); cv.visitOtherviseBeforeBody(); adapter.loadArg(0); adapter.invokeVirtual(Types.PAGE_CONTEXT, PUSH_BODY); cv.visitOtherviseAfterBody(); cv.visitAfter(bc); adapter.storeLocal(localBC); // c.init(pc,this); adapter.loadArg(1); adapter.loadArg(0); adapter.visitVarInsn(Opcodes.ALOAD, 0); adapter.invokeVirtual(Types.COMPONENT_IMPL, INIT); //int oldCheckArgs= pc.undefinedScope().setMode(Undefined.MODE_NO_LOCAL_AND_ARGUMENTS); final int oldCheckArgs = adapter.newLocal(Types.INT_VALUE); adapter.loadArg(0); adapter.invokeVirtual(Types.PAGE_CONTEXT, UNDEFINED_SCOPE); adapter.push(Undefined.MODE_NO_LOCAL_AND_ARGUMENTS); adapter.invokeInterface(Types.UNDEFINED, SET_MODE); adapter.storeLocal(oldCheckArgs); TryCatchFinallyVisitor tcf=new TryCatchFinallyVisitor(new OnFinally() { public void writeOut(BytecodeContext bc) { // undefined.setMode(oldMode); adapter.loadArg(0); adapter.invokeVirtual(Types.PAGE_CONTEXT, UNDEFINED_SCOPE); adapter.loadLocal(oldCheckArgs,Types.INT_VALUE); adapter.invokeInterface(Types.UNDEFINED, SET_MODE); adapter.pop(); // c.afterCall(pc,_oldData); adapter.loadArg(1); adapter.loadArg(0); adapter.loadLocal(oldData); adapter.invokeVirtual(Types.COMPONENT_IMPL, AFTER_CALL); } },null); tcf.visitTryBegin(bc); // oldData=c.beforeCall(pc); adapter.loadArg(1); adapter.loadArg(0); adapter.invokeVirtual(Types.COMPONENT_IMPL, BEFORE_CALL); adapter.storeLocal(oldData); ExpressionUtil.visitLine(bc, component.getStart()); writeOutCallBody(bc,component.getBody(),IFunction.PAGE_TYPE_COMPONENT); ExpressionUtil.visitLine(bc, component.getEnd()); int t = tcf.visitTryEndCatchBeging(bc); // BodyContentUtil.flushAndPop(pc,bc); adapter.loadArg(0); adapter.loadLocal(localBC); adapter.invokeStatic(Types.BODY_CONTENT_UTIL, FLUSH_AND_POP); // throw Caster.toPageException(t); adapter.loadLocal(t); adapter.invokeStatic(Types.CASTER, TO_PAGE_EXCEPTION); adapter.throwException(); tcf.visitCatchEnd(bc); adapter.loadArg(0); adapter.loadLocal(localBC); adapter.invokeStatic(Types.BODY_CONTENT_UTIL, CLEAR_AND_POP); adapter.returnValue(); adapter.visitLabel(methodEnd); adapter.endMethod(); } private void writeOutInitInterface(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys, ClassWriter cw, Tag interf) throws BytecodeException { GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , INIT_INTERFACE, null, new Type[]{Types.PAGE_EXCEPTION}, cw); BytecodeContext bc=new BytecodeContext(null,statConstr, constr,this,keys,cw,name,adapter,INIT_INTERFACE,writeLog(),supressWSbeforeArg); Label methodBegin=new Label(); Label methodEnd=new Label(); adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0); adapter.visitLabel(methodBegin); ExpressionUtil.visitLine(bc, interf.getStart()); writeOutCallBody(bc,interf.getBody(),IFunction.PAGE_TYPE_INTERFACE); ExpressionUtil.visitLine(bc, interf.getEnd()); adapter.returnValue(); adapter.visitLabel(methodEnd); adapter.endMethod(); } private Tag getComponent() throws BytecodeException { Iterator it = getStatements().iterator(); Statement s; Tag t; while(it.hasNext()) { s=(Statement)it.next(); if(s instanceof Tag) { t=(Tag)s; if(t.getTagLibTag().getTagClassName().equals("railo.runtime.tag.Component"))return t; } } throw new BytecodeException("missing component",getStart()); } private Tag getInterface() throws BytecodeException { Iterator it = getStatements().iterator(); Statement s; Tag t; while(it.hasNext()) { s=(Statement)it.next(); if(s instanceof Tag) { t=(Tag)s; if(t.getTagLibTag().getTagClassName().equals("railo.runtime.tag.Interface"))return t; } } throw new BytecodeException("missing interface",getStart()); } private void writeOutFunctionDefaultValueInnerInner(BytecodeContext bc, Function function) throws BytecodeException { GeneratorAdapter adapter = bc.getAdapter(); List<Argument> args = function.getArguments(); if(args.size()==0) { adapter.loadArg(DEFAULT_VALUE); adapter.returnValue(); return; } Iterator<Argument> it = args.iterator(); Argument arg; ConditionVisitor cv=new ConditionVisitor(); DecisionIntVisitor div; cv.visitBefore(); int count=0; while(it.hasNext()) { arg=it.next(); cv.visitWhenBeforeExpr(); div=new DecisionIntVisitor(); div.visitBegin(); adapter.loadArg(2); div.visitEQ(); adapter.push(count++); div.visitEnd(bc); cv.visitWhenAfterExprBeforeBody(bc); Expression defaultValue = arg.getDefaultValue(); if(defaultValue!=null) { /*if(defaultValue instanceof Null) { adapter.invokeStatic(NULL, GET_INSTANCE); } else*/ defaultValue.writeOut(bc, Expression.MODE_REF); } else adapter.loadArg(DEFAULT_VALUE); //adapter.visitInsn(Opcodes.ACONST_NULL); adapter.returnValue(); cv.visitWhenAfterBody(bc); } cv.visitOtherviseBeforeBody(); //adapter.visitInsn(ACONST_NULL); //adapter.returnValue(); cv.visitOtherviseAfterBody(); cv.visitAfter(bc); } private Function[] getFunctions() { Function[] funcs=new Function[functions.size()]; Iterator it = functions.iterator(); int count=0; while(it.hasNext()) { funcs[count++]=(Function) it.next(); } return funcs; } private TagThread[] getThreads() { TagThread[] threads=new TagThread[this.threads.size()]; Iterator it = this.threads.iterator(); int count=0; while(it.hasNext()) { threads[count++]=(TagThread) it.next(); } return threads; } public void _writeOut(BytecodeContext bc) throws BytecodeException { } private void writeOutNewComponent(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys,ClassWriter cw, Tag component) throws BytecodeException { GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , NEW_COMPONENT_IMPL_INSTANCE, null, new Type[]{Types.PAGE_EXCEPTION}, cw); BytecodeContext bc=new BytecodeContext(null,statConstr, constr,this,keys,cw,name,adapter,NEW_COMPONENT_IMPL_INSTANCE,writeLog(),supressWSbeforeArg); Label methodBegin=new Label(); Label methodEnd=new Label(); adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0); adapter.visitLabel(methodBegin); //ExpressionUtil.visitLine(adapter, component.getStartLine()); int comp=adapter.newLocal(Types.COMPONENT_IMPL); adapter.newInstance(Types.COMPONENT_IMPL); adapter.dup(); Attribute attr; // ComponentPage adapter.visitVarInsn(Opcodes.ALOAD, 0); adapter.checkCast(Types.COMPONENT_PAGE); // !!! also check CFMLScriptTransformer.addMetaData if you do any change here !!! // Output attr = component.removeAttribute("output"); if(attr!=null) { ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF); } else ASMConstants.NULL(adapter); // synchronized attr = component.removeAttribute("synchronized"); if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_VALUE); else adapter.push(false); // extends attr = component.removeAttribute("extends"); if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF); else adapter.push(""); // implements attr = component.removeAttribute("implements"); if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF); else adapter.push(""); // hint attr = component.removeAttribute("hint"); if(attr!=null) { Expression value = attr.getValue(); if(!(value instanceof Literal)){ value=LitString.toExprString("[runtime expression]"); } ExpressionUtil.writeOutSilent(value,bc, Expression.MODE_REF); } else adapter.push(""); // dspName attr = component.removeAttribute("displayname"); if(attr==null) attr=component.getAttribute("display"); if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF); else adapter.push(""); // callpath adapter.visitVarInsn(Opcodes.ALOAD, 2); // realpath adapter.visitVarInsn(Opcodes.ILOAD, 3); // style attr = component.removeAttribute("style"); if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF); else adapter.push(""); // persistent attr = component.removeAttribute("persistent"); boolean persistent=false; if(attr!=null) { persistent=ASMUtil.toBoolean(attr,component.getStart()).booleanValue(); } // persistent attr = component.removeAttribute("accessors"); boolean accessors=false; if(attr!=null) { accessors=ASMUtil.toBoolean(attr,component.getStart()).booleanValue(); } adapter.push(persistent); adapter.push(accessors); //ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_VALUE); //adapter.visitVarInsn(Opcodes.ALOAD, 4); createMetaDataStruct(bc,component.getAttributes(),component.getMetaData()); adapter.invokeConstructor(Types.COMPONENT_IMPL, CONSTR_COMPONENT_IMPL); adapter.storeLocal(comp); //Component Impl(ComponentPage componentPage,boolean output, String extend, String hint, String dspName) // initComponent(pc,c); adapter.visitVarInsn(Opcodes.ALOAD, 0); adapter.loadArg(0); adapter.loadLocal(comp); adapter.invokeVirtual(Types.COMPONENT_PAGE, INIT_COMPONENT); adapter.visitLabel(methodEnd); // return component; adapter.loadLocal(comp); adapter.returnValue(); //ExpressionUtil.visitLine(adapter, component.getEndLine()); adapter.endMethod(); } private void writeOutNewInterface(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys,ClassWriter cw, Tag interf) throws BytecodeException { GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , NEW_INTERFACE_IMPL_INSTANCE, null, new Type[]{Types.PAGE_EXCEPTION}, cw); BytecodeContext bc=new BytecodeContext(null,statConstr, constr,this,keys,cw,name,adapter,NEW_INTERFACE_IMPL_INSTANCE,writeLog(),supressWSbeforeArg); Label methodBegin=new Label(); Label methodEnd=new Label(); adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0); adapter.visitLabel(methodBegin); //ExpressionUtil.visitLine(adapter, interf.getStartLine()); int comp=adapter.newLocal(Types.INTERFACE_IMPL); adapter.newInstance(Types.INTERFACE_IMPL); adapter.dup(); Attribute attr; // Interface Page adapter.visitVarInsn(Opcodes.ALOAD, 0); adapter.checkCast(Types.INTERFACE_PAGE); // extened attr = interf.removeAttribute("extends"); if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF); else adapter.push(""); // hint attr = interf.removeAttribute("hint"); if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF); else adapter.push(""); // dspName attr = interf.removeAttribute("displayname"); if(attr==null) attr=interf.getAttribute("display"); if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF); else adapter.push(""); // callpath adapter.visitVarInsn(Opcodes.ALOAD, 1); // realpath adapter.visitVarInsn(Opcodes.ILOAD, 2); // interface udfs adapter.visitVarInsn(Opcodes.ALOAD, 3); createMetaDataStruct(bc,interf.getAttributes(),interf.getMetaData()); adapter.invokeConstructor(Types.INTERFACE_IMPL, CONSTR_INTERFACE_IMPL); adapter.storeLocal(comp); // initInterface(pc,c); adapter.visitVarInsn(Opcodes.ALOAD, 0); //adapter.loadArg(0); adapter.loadLocal(comp); adapter.invokeVirtual(Types.INTERFACE_PAGE, INIT_INTERFACE); adapter.visitLabel(methodEnd); // return interface; adapter.loadLocal(comp); adapter.returnValue(); //ExpressionUtil.visitLine(adapter, interf.getEndLine()); adapter.endMethod(); } public static boolean hasMetaDataStruct(Map attrs, Map meta) { if((attrs==null || attrs.size()==0) && (meta==null || meta.size()==0)){ return false; } return true; } public static void createMetaDataStruct(BytecodeContext bc, Map attrs, Map meta) throws BytecodeException { GeneratorAdapter adapter = bc.getAdapter(); if((attrs==null || attrs.size()==0) && (meta==null || meta.size()==0)){ ASMConstants.NULL(bc.getAdapter()); bc.getAdapter().cast(Types.OBJECT,STRUCT_IMPL); return; } int sct=adapter.newLocal(STRUCT_IMPL); adapter.newInstance(STRUCT_IMPL); adapter.dup(); adapter.invokeConstructor(STRUCT_IMPL, INIT_STRUCT_IMPL); adapter.storeLocal(sct); if(meta!=null) { _createMetaDataStruct(bc,adapter,sct,meta); } if(attrs!=null) { _createMetaDataStruct(bc,adapter,sct,attrs); } adapter.loadLocal(sct); } private static void _createMetaDataStruct(BytecodeContext bc, GeneratorAdapter adapter, int sct, Map attrs) throws BytecodeException { Attribute attr; Iterator it = attrs.entrySet().iterator(); Entry entry; while(it.hasNext()){ entry = (Map.Entry)it.next(); attr=(Attribute) entry.getValue(); adapter.loadLocal(sct); adapter.push(attr.getName()); if(attr.getValue() instanceof Literal) ExpressionUtil.writeOutSilent(attr.getValue(),bc,Expression.MODE_REF); else adapter.push("[runtime expression]"); adapter.invokeVirtual(STRUCT_IMPL, SET_EL); adapter.pop(); } } private void writeOutCall(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys,ClassWriter cw) throws BytecodeException { //GeneratorAdapter adapter = bc.getAdapter(); GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , CALL, null, new Type[]{Types.THROWABLE}, cw); Label methodBegin=new Label(); Label methodEnd=new Label(); adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0); adapter.visitLabel(methodBegin); writeOutCallBody(new BytecodeContext(null,statConstr, constr,this,keys,cw,name,adapter,CALL,writeLog(),supressWSbeforeArg),this,IFunction.PAGE_TYPE_REGULAR); adapter.visitLabel(methodEnd); adapter.returnValue(); adapter.endMethod(); } private void writeOutCallBody(BytecodeContext bc,Body body, int pageType) throws BytecodeException { // Other List<IFunction> functions=new ArrayList<IFunction>(); getFunctions(functions,bc,body,pageType); String className = Types.UDF_PROPERTIES_ARRAY.toString(); //FieldVisitor fv = bc.getClassWriter().visitField(Opcodes.ACC_PRIVATE , "udfs",className , null, null); //fv.visitEnd(); BytecodeContext constr = bc.getConstructor(); GeneratorAdapter cga = constr.getAdapter(); cga.visitVarInsn(Opcodes.ALOAD, 0); cga.push(functions.size()); //cga.visitTypeInsn(Opcodes.ANEWARRAY, Types.UDF_PROPERTIES.toString()); cga.newArray(Types.UDF_PROPERTIES); cga.visitFieldInsn(Opcodes.PUTFIELD, bc.getClassName(), "udfs", className); Iterator<IFunction> it = functions.iterator(); while(it.hasNext()){ it.next().writeOut(bc, pageType); } if(pageType==IFunction.PAGE_TYPE_COMPONENT) { GeneratorAdapter adapter = bc.getAdapter(); adapter.loadArg(1); adapter.loadArg(0); adapter.visitVarInsn(Opcodes.ALOAD, 0); adapter.invokeVirtual(Types.COMPONENT_IMPL, CHECK_INTERFACE); } if(pageType!=IFunction.PAGE_TYPE_INTERFACE){ BodyBase.writeOut(bc.getStaticConstructor(),bc.getConstructor(),bc.getKeys(),body.getStatements(), bc); } } private static void getImports(List<String> list,Body body) throws BytecodeException { if(ASMUtil.isEmpty(body)) return; Statement stat; List stats = body.getStatements(); int len=stats.size(); for(int i=0;i<len;i++) { stat = (Statement)stats.get(i); // IFunction if(stat instanceof TagImport && !StringUtil.isEmpty(((TagImport)stat).getPath(),true)) { ImportDefintion id = ImportDefintionImpl.getInstance(((TagImport) stat).getPath(), null); if(id!=null && (!list.contains(id.toString()) && !list.contains(id.getPackage()+".*"))){ list.add(id.toString()); } stats.remove(i); len--; i--; } else if(stat instanceof HasBody) getImports(list, ((HasBody)stat).getBody()); else if(stat instanceof HasBodies) { Body[] bodies=((HasBodies)stat).getBodies(); for(int y=0;y<bodies.length;y++) { getImports(list,bodies[y]); } } } } private static void getFunctions(List<IFunction> functions,BytecodeContext bc, Body body, int pageType) throws BytecodeException { //writeOutImports(bc, body, pageType); if(ASMUtil.isEmpty(body)) return; Statement stat; List stats = body.getStatements(); int len=stats.size(); for(int i=0;i<len;i++) { stat = (Statement)stats.get(i); // IFunction if(stat instanceof IFunction) { functions.add((IFunction)stat); //((IFunction)stat).writeOut(bc,pageType); stats.remove(i); len--; i--; } else if(stat instanceof HasBody) getFunctions(functions,bc, ((HasBody)stat).getBody(), pageType); else if(stat instanceof HasBodies) { Body[] bodies=((HasBodies)stat).getBodies(); for(int y=0;y<bodies.length;y++) { getFunctions(functions,bc,bodies[y] , pageType); } } } } /** * @return the source */ public String getSource() { return path; } /** * @return if it is a component */ public boolean isComponent() { return isComponent; } /** * set if the page is a component or not * @param cfc */ public void setIsComponent(boolean isComponent) { this.isComponent = isComponent; } /** * @return if it is a component */ public boolean isInterface() { return isInterface; } public boolean isPage() { return !isInterface && !isComponent; } /** * set if the page is a component or not * @param cfc */ public void setIsInterface(boolean isInterface) { this.isInterface = isInterface; } /** * @return the lastModifed */ public long getLastModifed() { return lastModifed; } public int[] addFunction(IFunction function) { int[] indexes=new int[2]; Iterator<IFunction> it = functions.iterator(); while(it.hasNext()){ if(it.next() instanceof FunctionImpl)indexes[IFunction.ARRAY_INDEX]++; } indexes[IFunction.VALUE_INDEX]=functions.size(); functions.add(function); return indexes; } public int addThread(TagThread thread) { threads.add(thread); return threads.size()-1; } public static byte[] setSourceLastModified(byte[] barr, long lastModified) { ClassReader cr = new ClassReader(barr); ClassWriter cw = ASMUtil.getClassWriter(); ClassVisitor ca = new SourceLastModifiedClassAdapter(cw,lastModified); cr.accept(ca, ClassReader.SKIP_DEBUG); return cw.toByteArray(); } public Range registerString(BytecodeContext bc, String str) throws IOException { boolean append=true; if(staticTextLocation==null) { PageSource ps = bc.getPageSource(); Mapping m = ps.getMapping(); staticTextLocation=m.getClassRootDirectory(); staticTextLocation.mkdirs(); staticTextLocation=staticTextLocation.getRealResource(ps.getJavaName()+".txt"); if(staticTextLocation.exists()) append=false; else staticTextLocation.createFile(true); off=0; } IOUtil.write(staticTextLocation, str, CharsetUtil.UTF8, append); Range r = new Range(off,str.length()); off+=str.length(); return r; } public int getMethodCount() { return ++methodCount; } public Config getConfig() { return config; } } class SourceLastModifiedClassAdapter extends ClassVisitor { private long lastModified; public SourceLastModifiedClassAdapter(ClassWriter cw, long lastModified) { super(Opcodes.ASM4,cw); this.lastModified=lastModified; } public MethodVisitor visitMethod(int access,String name, String desc, String signature, String[] exceptions) { if(!name.equals("getSourceLastModified"))return super.visitMethod(access,name, desc, signature, exceptions); MethodVisitor mv = cv.visitMethod(access,name, desc, signature, exceptions); mv.visitCode(); mv.visitLdcInsn(Long.valueOf(lastModified)); mv.visitInsn(Opcodes.LRETURN); mv.visitEnd(); return mv; } }