Java tutorial
/** * * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <http://www.gnu.org/licenses/>. * **/ package lucee.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 lucee.commons.io.CharsetUtil; import lucee.commons.io.IOUtil; import lucee.commons.io.res.Resource; import lucee.commons.lang.StringUtil; import lucee.runtime.Mapping; import lucee.runtime.PageSource; import lucee.runtime.component.ImportDefintion; import lucee.runtime.component.ImportDefintionImpl; import lucee.runtime.exp.TemplateException; import lucee.runtime.type.KeyImpl; import lucee.runtime.type.StructImpl; import lucee.runtime.type.UDF; import lucee.runtime.type.scope.Undefined; import lucee.runtime.type.util.KeyConstants; import lucee.transformer.bytecode.expression.Expression; import lucee.transformer.bytecode.literal.LitString; import lucee.transformer.bytecode.literal.LitString.Range; import lucee.transformer.bytecode.statement.Argument; import lucee.transformer.bytecode.statement.HasBodies; import lucee.transformer.bytecode.statement.HasBody; import lucee.transformer.bytecode.statement.IFunction; import lucee.transformer.bytecode.statement.NativeSwitch; import lucee.transformer.bytecode.statement.tag.Attribute; import lucee.transformer.bytecode.statement.tag.Tag; import lucee.transformer.bytecode.statement.tag.TagImport; import lucee.transformer.bytecode.statement.tag.TagThread; import lucee.transformer.bytecode.statement.udf.Function; import lucee.transformer.bytecode.statement.udf.FunctionImpl; import lucee.transformer.bytecode.util.ASMConstants; import lucee.transformer.bytecode.util.ASMUtil; import lucee.transformer.bytecode.util.ExpressionUtil; import lucee.transformer.bytecode.util.Types; import lucee.transformer.bytecode.visitor.ArrayVisitor; import lucee.transformer.bytecode.visitor.ConditionVisitor; import lucee.transformer.bytecode.visitor.DecisionIntVisitor; import lucee.transformer.bytecode.visitor.OnFinally; import lucee.transformer.bytecode.visitor.TryCatchFinallyVisitor; 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; /** * 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(lucee.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 (lucee.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, // relpath 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 final int version; private final long lastModifed; private final boolean _writeLog; private final String name; private final boolean suppressWSbeforeArg; private final boolean output; private final PageSource pageSource; private boolean isComponent; private boolean isInterface; private ArrayList<IFunction> functions = new ArrayList<IFunction>(); private ArrayList<TagThread> threads = new ArrayList<TagThread>(); private Resource staticTextLocation; private int off; private int methodCount = 0; //private final Config config; private boolean splitIfNecessary; public Page(PageSource pageSource, Resource source, String name, int version, long lastModifed, boolean writeLog, boolean suppressWSbeforeArg, boolean output) { name = name.replace('.', '/'); this.name = name; this.version = version; this.lastModifed = lastModifed; this._writeLog = writeLog; this.suppressWSbeforeArg = suppressWSbeforeArg; this.output = output; this.pageSource = pageSource; } /** * result byte code as binary array * @param classFile * @return byte code * @throws IOException * @throws TemplateException */ public byte[] execute(PageSource source, Resource classFile) throws BytecodeException { /* // this is done that the Page can be executed more than once if(initFunctions==null) initFunctions=(ArrayList<IFunction>) functions.clone(); else functions=initFunctions; if(initThreads==null) initThreads=(ArrayList<TagThread>) threads.clone(); else threads=initThreads; methodCount=0; off=0; staticTextLocation=null; print.e(this.functions); print.e(this.threads);*/ Resource p = classFile.getParentResource().getRealResource(classFile.getName() + ".txt"); List<LitString> keys = new ArrayList<LitString>(); ClassWriter cw = ASMUtil.getClassWriter(); ArrayList<String> imports = new ArrayList<String>(); getImports(imports, this); // parent String parent = "lucee/runtime/PagePlus"; if (isComponent()) parent = "lucee/runtime/ComponentPage"; else if (isInterface()) parent = "lucee/runtime/InterfacePage"; cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, name, null, parent, null); cw.visitSource(this.pageSource.getPhyscalFile().getAbsolutePath(), "rel:" + this.pageSource.getFullRealpath()); // when adding more use ; as delimiter // // 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(),suppressWSbeforeArg); // 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(), suppressWSbeforeArg, output); 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", "[Llucee/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", "[Llucee/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", "[Llucee/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, "lucee/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(), suppressWSbeforeArg, output); 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(), suppressWSbeforeArg, output); 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), "(Llucee/runtime/PageContext;Llucee/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(), suppressWSbeforeArg, output), 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(), suppressWSbeforeArg, output), 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(), suppressWSbeforeArg, output), 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(), suppressWSbeforeArg, output); 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), "(Llucee/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(), suppressWSbeforeArg, output), 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(), suppressWSbeforeArg, output); 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); constrAdapter.returnValue(); constrAdapter.endMethod(); 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(), suppressWSbeforeArg, output); 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(), suppressWSbeforeArg, output); 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("lucee.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("lucee.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(), suppressWSbeforeArg, output); Label methodBegin = new Label(); Label methodEnd = new Label(); adapter.visitLocalVariable("this", "L" + name + ";", null, methodBegin, methodEnd, 0); ExpressionUtil.visitLine(bc, component.getStart()); adapter.visitLabel(methodBegin); 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); // relpath 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(), suppressWSbeforeArg, output); Label methodBegin = new Label(); Label methodEnd = new Label(); adapter.visitLocalVariable("this", "L" + name + ";", null, methodBegin, methodEnd, 0); ExpressionUtil.visitLine(bc, interf.getStart()); 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); // relpath 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(), suppressWSbeforeArg, output), 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); BodyBase.writeOut(bc, body); } } 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 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, 0); 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 PageSource getPageSource() { return pageSource; } public void setSplitIfNecessary(boolean splitIfNecessary) { this.splitIfNecessary = splitIfNecessary; } public boolean getSplitIfNecessary() { return splitIfNecessary; } } 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; } }