package railo.transformer.bytecode.statement.tag; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.Method; import railo.runtime.type.scope.Undefined; import railo.runtime.util.NumberIterator; import railo.transformer.bytecode.BytecodeContext; import railo.transformer.bytecode.BytecodeException; import railo.transformer.bytecode.Statement; import railo.transformer.bytecode.cast.CastInt; import railo.transformer.bytecode.expression.Expression; import railo.transformer.bytecode.literal.LitString; import railo.transformer.bytecode.util.Types; import railo.transformer.bytecode.visitor.DecisionIntVisitor; import railo.transformer.bytecode.visitor.NotVisitor; import railo.transformer.bytecode.visitor.OnFinally; import railo.transformer.bytecode.visitor.ParseBodyVisitor; import railo.transformer.bytecode.visitor.TryFinallyVisitor; import railo.transformer.bytecode.visitor.WhileVisitor; public class TagGroupUtil { // Undefined us() public static final Type UNDEFINED = Type.getType(Undefined.class); public static final Method US = new Method( "us", UNDEFINED, new Type[]{}); // void addQuery(Query coll) public static final Method ADD_QUERY = new Method( "addQuery", Types.VOID, new Type[]{Types.QUERY}); // void removeQuery() public static final Method REMOVE_QUERY = new Method( "removeQuery", Types.VOID, new Type[]{}); // int getRecordcount() public static final Method GET_RECORDCOUNT = new Method( "getRecordcount", Types.INT_VALUE, new Type[]{}); // double range(double number, double from) public static final Method RANGE = new Method( "range", Types.INT_VALUE, new Type[]{Types.INT_VALUE,Types.INT_VALUE}); public static final Type NUMBER_ITERATOR = Type.getType(NumberIterator.class); // NumberIterator load(double from, double to, double max) public static final Method LOAD_MAX = new Method( "loadMax", NUMBER_ITERATOR, new Type[]{Types.INT_VALUE,Types.INT_VALUE,Types.INT_VALUE}); public static final Method LOAD_END = new Method( "loadEnd", NUMBER_ITERATOR, new Type[]{Types.INT_VALUE,Types.INT_VALUE,Types.INT_VALUE}); // NumberIterator load(double from, double to, double max) public static final Method LOAD_2 = new Method( "load", NUMBER_ITERATOR, new Type[]{Types.INT_VALUE,Types.INT_VALUE}); // NumberIterator load(NumberIterator ni, Query query, String groupName, boolean caseSensitive) public static final Method LOAD_5 = new Method( "load", NUMBER_ITERATOR, new Type[]{Types.PAGE_CONTEXT, NUMBER_ITERATOR,Types.QUERY,Types.STRING,Types.BOOLEAN_VALUE}); // boolean isValid() /*public static final Method IS_VALID_0 = new Method( "isValid", Types.BOOLEAN_VALUE, new Type[]{});*/ public static final Method IS_VALID_1 = new Method( "isValid", Types.BOOLEAN_VALUE, new Type[]{Types.INT_VALUE}); // int current() public static final Method CURRENT = new Method( "current", Types.INT_VALUE, new Type[]{}); // void release(NumberIterator ni) public static final Method REALEASE = new Method( "release", Types.VOID, new Type[]{NUMBER_ITERATOR}); // void setCurrent(int current) public static final Method SET_CURRENT = new Method( "setCurrent", Types.VOID, new Type[]{Types.INT_VALUE}); // void reset() public static final Method RESET = new Method( "reset", Types.VOID, new Type[]{Types.INT_VALUE}); // int first() public static final Method FIRST = new Method( "first", Types.INT_VALUE, new Type[]{}); public static final Method GET_ID = new Method( "getId", Types.INT_VALUE, new Type[]{}); public static void writeOutTypeQuery(final TagGroup tag, BytecodeContext bc) throws BytecodeException { final GeneratorAdapter adapter = bc.getAdapter(); tag.setNumberIterator(adapter.newLocal(NUMBER_ITERATOR)); boolean isOutput=tag.getType()==TagGroup.TAG_OUTPUT; ParseBodyVisitor pbv=isOutput?new ParseBodyVisitor():null; if(isOutput)pbv.visitBegin(bc); // Query query=pc.getQuery(@query); tag.setQuery(adapter.newLocal(Types.QUERY)); adapter.loadArg(0); Expression val = tag.getAttribute("query").getValue(); val.writeOut(bc, Expression.MODE_REF); if(val instanceof LitString) adapter.invokeVirtual(Types.PAGE_CONTEXT, TagLoop.GET_QUERY_STRING); else adapter.invokeVirtual(Types.PAGE_CONTEXT, TagLoop.GET_QUERY_OBJ); adapter.storeLocal(tag.getQuery()); tag.setPID(adapter.newLocal(Types.INT_VALUE)); adapter.loadArg(0); adapter.invokeVirtual(Types.PAGE_CONTEXT, TagLoop.GET_ID); adapter.storeLocal(tag.getPID()); // int startAt=query.getCurrentrow(); final int startAt=adapter.newLocal(Types.INT_VALUE); adapter.loadLocal(tag.getQuery()); adapter.loadLocal(tag.getPID()); //adapter.loadArg(0); //adapter.invokeVirtual(Types.PAGE_CONTEXT, TagLoop.GET_ID); adapter.invokeInterface(Types.QUERY, TagLoop.GET_CURRENTROW_1); adapter.storeLocal(startAt); // if(query.getRecordcount()>0) { DecisionIntVisitor div=new DecisionIntVisitor(); div.visitBegin(); adapter.loadLocal(tag.getQuery()); adapter.invokeInterface(Types.QUERY, GET_RECORDCOUNT); div.visitGT(); adapter.push(0); div.visitEnd(bc); Label ifRecCount=new Label(); adapter.ifZCmp(Opcodes.IFEQ, ifRecCount); // startrow int from = adapter.newLocal(Types.INT_VALUE); Attribute attrStartRow = tag.getAttribute("startrow"); if(attrStartRow!=null){ // NumberRange.range(@startrow,1) //attrStartRow.getValue().writeOut(bc, Expression.MODE_VALUE); CastInt.toExprInt(attrStartRow.getValue()).writeOut(bc, Expression.MODE_VALUE); //adapter.visitInsn(Opcodes.D2I); adapter.push(1); adapter.invokeStatic(Types.NUMBER_RANGE, RANGE); //adapter.visitInsn(Opcodes.D2I); } else { adapter.push(1); } adapter.storeLocal(from); // numberIterator adapter.loadLocal(from); adapter.loadLocal(tag.getQuery()); adapter.invokeInterface(Types.QUERY, GET_RECORDCOUNT); //adapter.visitInsn(Opcodes.I2D); Attribute attrMaxRow = tag.getAttribute("maxrows"); Attribute attrEndRow = tag.getAttribute("endrow"); if(attrMaxRow!=null) { CastInt.toExprInt(attrMaxRow.getValue()).writeOut(bc, Expression.MODE_VALUE); adapter.invokeStatic(NUMBER_ITERATOR, LOAD_MAX); } else if(attrEndRow!=null) { CastInt.toExprInt(attrEndRow.getValue()).writeOut(bc, Expression.MODE_VALUE); adapter.invokeStatic(NUMBER_ITERATOR, LOAD_END); } else { adapter.invokeStatic(NUMBER_ITERATOR, LOAD_2); } adapter.storeLocal(tag.getNumberIterator()); // Group Attribute attrGroup = tag.getAttribute("group"); Attribute attrGroupCS = tag.getAttribute("groupcasesensitive"); tag.setGroup(adapter.newLocal(Types.STRING)); final int groupCaseSensitive=adapter.newLocal(Types.BOOLEAN_VALUE); if(attrGroup!=null) { attrGroup.getValue().writeOut(bc, Expression.MODE_REF); adapter.storeLocal(tag.getGroup()); if(attrGroupCS!=null) attrGroupCS.getValue().writeOut(bc, Expression.MODE_VALUE); else adapter.push(false); adapter.storeLocal(groupCaseSensitive); } // pc.us().addQuery(query); adapter.loadArg(0); adapter.invokeVirtual(Types.PAGE_CONTEXT, US); adapter.loadLocal(tag.getQuery()); adapter.invokeInterface(UNDEFINED, ADD_QUERY); // current final int current=adapter.newLocal(Types.INT_VALUE); adapter.loadLocal(from); adapter.push(1); adapter.visitInsn(Opcodes.ISUB); adapter.storeLocal(current); // Try TryFinallyVisitor tfv=new TryFinallyVisitor(new OnFinally() { public void writeOut(BytecodeContext bc) { // query.reset(); // query.go(startAt); adapter.loadLocal(tag.getQuery()); adapter.loadLocal(startAt); adapter.loadLocal(tag.getPID()); //adapter.loadArg(0); //adapter.invokeVirtual(Types.PAGE_CONTEXT, TagLoop.GET_ID); adapter.invokeInterface(Types.QUERY, TagLoop.GO); adapter.pop(); // pc.us().removeQuery(); adapter.loadArg(0); adapter.invokeVirtual(Types.PAGE_CONTEXT, US); adapter.invokeInterface(UNDEFINED, REMOVE_QUERY); // NumberIterator.release(ni); adapter.loadLocal(tag.getNumberIterator()); adapter.invokeStatic(NUMBER_ITERATOR, REALEASE); } },null); tfv.visitTryBegin(bc); WhileVisitor wv = new WhileVisitor(); if(tag instanceof TagLoop) ((TagLoop)tag).setLoopVisitor(wv); wv.visitBeforeExpression(bc); //while(ni.isValid()) { adapter.loadLocal(tag.getNumberIterator()); adapter.loadLocal(current); adapter.push(1); adapter.visitInsn(Opcodes.IADD); adapter.invokeVirtual(NUMBER_ITERATOR, IS_VALID_1); wv.visitAfterExpressionBeforeBody(bc); // if(!query.go(ni.current()))break; adapter.loadLocal(tag.getQuery()); adapter.loadLocal(tag.getNumberIterator()); adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT); adapter.loadLocal(tag.getPID()); adapter.invokeInterface(Types.QUERY, TagLoop.GO); NotVisitor.visitNot(bc); Label _if=new Label(); adapter.ifZCmp(Opcodes.IFEQ, _if); wv.visitBreak(bc); adapter.visitLabel(_if); if(attrGroup!=null) { // NumberIterator oldNi=numberIterator; int oldNi=adapter.newLocal(NUMBER_ITERATOR); adapter.loadLocal(tag.getNumberIterator()); adapter.storeLocal(oldNi); // numberIterator=NumberIterator.load(ni,query,group,grp_case); adapter.loadArg(0); adapter.loadLocal(tag.getNumberIterator()); adapter.loadLocal(tag.getQuery()); adapter.loadLocal(tag.getGroup()); adapter.loadLocal(groupCaseSensitive); adapter.invokeStatic(NUMBER_ITERATOR, LOAD_5); adapter.storeLocal(tag.getNumberIterator()); // current=oldNi.current(); adapter.loadLocal(oldNi); adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT); adapter.storeLocal(current); tag.getBody().writeOut(bc); //tmp(adapter,current); // NumberIterator.release(ni); adapter.loadLocal(tag.getNumberIterator()); adapter.invokeStatic(NUMBER_ITERATOR, REALEASE); // numberIterator=oldNi; adapter.loadLocal(oldNi); adapter.storeLocal(tag.getNumberIterator()); } else { // current=ni.current(); adapter.loadLocal(tag.getNumberIterator()); adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT); adapter.storeLocal(current); tag.getBody().writeOut(bc); } // ni.setCurrent(current+1); /*adapter.loadLocal(tag.getNumberIterator()); adapter.loadLocal(current); adapter.push(1); adapter.visitInsn(Opcodes.IADD); adapter.invokeVirtual(NUMBER_ITERATOR, SET_CURRENT);*/ wv.visitAfterBody(bc,tag.getEnd()); tfv.visitTryEnd(bc); adapter.visitLabel(ifRecCount); if(isOutput)pbv.visitEnd(bc); } public static void writeOutTypeGroup(TagGroup tag,BytecodeContext bc) throws BytecodeException { GeneratorAdapter adapter = bc.getAdapter(); boolean isOutput=tag.getType()==TagGroup.TAG_OUTPUT; ParseBodyVisitor pbv=isOutput?new ParseBodyVisitor():null; if(isOutput)pbv.visitBegin(bc); // Group Attribute attrGroup = tag.getAttribute("group"); tag.setGroup(adapter.newLocal(Types.STRING)); attrGroup.getValue().writeOut(bc, Expression.MODE_REF); adapter.storeLocal(tag.getGroup()); // Group Case Sensitve Attribute attrGroupCS = tag.getAttribute("groupcasesensitive"); int groupCaseSensitive=adapter.newLocal(Types.BOOLEAN_VALUE); if(attrGroupCS!=null) attrGroupCS.getValue().writeOut(bc, Expression.MODE_VALUE); else adapter.push(true); adapter.storeLocal(groupCaseSensitive); TagGroup parent = getParentTagGroupQuery(tag,tag.getType()); tag.setNumberIterator(parent.getNumberIterator()); tag.setQuery(parent.getQuery()); //queryImpl = parent.getQueryImpl(); // current int current=adapter.newLocal(Types.INT_VALUE); adapter.loadLocal(tag.getNumberIterator()); adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT); adapter.storeLocal(current); // current int icurrent=adapter.newLocal(Types.INT_VALUE); adapter.loadLocal(current); adapter.push(1); adapter.visitInsn(Opcodes.ISUB); adapter.storeLocal(icurrent); WhileVisitor wv = new WhileVisitor(); if(tag instanceof TagLoop) ((TagLoop)tag).setLoopVisitor(wv); wv.visitBeforeExpression(bc); //while(ni.isValid()) { adapter.loadLocal(tag.getNumberIterator()); adapter.loadLocal(icurrent); adapter.push(1); adapter.visitInsn(Opcodes.IADD); adapter.invokeVirtual(NUMBER_ITERATOR, IS_VALID_1); wv.visitAfterExpressionBeforeBody(bc); // if(!query.go(ni.current()))break; adapter.loadLocal(tag.getQuery()); adapter.loadLocal(tag.getNumberIterator()); adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT); adapter.loadArg(0); adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_ID); adapter.invokeInterface(Types.QUERY, TagLoop.GO); NotVisitor.visitNot(bc); Label _if=new Label(); adapter.ifZCmp(Opcodes.IFEQ, _if); wv.visitBreak(bc); adapter.visitLabel(_if); // NumberIterator oldNi=numberIterator; int oldNi=adapter.newLocal(NUMBER_ITERATOR); adapter.loadLocal(tag.getNumberIterator()); adapter.storeLocal(oldNi); // numberIterator=NumberIterator.load(ni,query,group,grp_case); adapter.loadArg(0); adapter.loadLocal(tag.getNumberIterator()); adapter.loadLocal(tag.getQuery()); adapter.loadLocal(tag.getGroup()); adapter.loadLocal(groupCaseSensitive); adapter.invokeStatic(NUMBER_ITERATOR, LOAD_5); adapter.storeLocal(tag.getNumberIterator()); // current=oldNi.current(); adapter.loadLocal(oldNi); adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT); adapter.storeLocal(icurrent); tag.getBody().writeOut(bc); //tmp(adapter,current); // NumberIterator.release(ni); adapter.loadLocal(tag.getNumberIterator()); adapter.invokeStatic(NUMBER_ITERATOR, REALEASE); // numberIterator=oldNi; adapter.loadLocal(oldNi); adapter.storeLocal(tag.getNumberIterator()); // ni.setCurrent(current+1); /*adapter.loadLocal(tag.getNumberIterator()); adapter.loadLocal(icurrent); adapter.push(1); adapter.visitInsn(Opcodes.IADD); adapter.invokeVirtual(NUMBER_ITERATOR, SET_CURRENT); */ wv.visitAfterBody(bc,tag.getEnd()); //query.go(ni.current(),pc.getId()) resetCurrentrow(adapter,tag,current); // ni.first(); adapter.loadLocal(tag.getNumberIterator()); adapter.invokeVirtual(NUMBER_ITERATOR, FIRST); adapter.pop(); if(isOutput)pbv.visitEnd(bc); } public static void writeOutTypeInnerGroup(TagGroup tag,BytecodeContext bc) throws BytecodeException { GeneratorAdapter adapter = bc.getAdapter(); TagGroup parent = getParentTagGroupQuery(tag,tag.getType()); tag.setNumberIterator(parent.getNumberIterator()); tag.setQuery(parent.getQuery()); //queryImpl = parent.getQueryImpl(); int current=adapter.newLocal(Types.INT_VALUE); adapter.loadLocal(tag.getNumberIterator()); adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT); adapter.storeLocal(current); // inner current int icurrent=adapter.newLocal(Types.INT_VALUE); adapter.loadLocal(current); adapter.push(1); adapter.visitInsn(Opcodes.ISUB); adapter.storeLocal(icurrent); WhileVisitor wv = new WhileVisitor(); if(tag instanceof TagLoop) ((TagLoop)tag).setLoopVisitor(wv); wv.visitBeforeExpression(bc); //while(ni.isValid()) { adapter.loadLocal(tag.getNumberIterator()); adapter.loadLocal(icurrent); adapter.push(1); adapter.visitInsn(Opcodes.IADD); adapter.invokeVirtual(NUMBER_ITERATOR, IS_VALID_1); wv.visitAfterExpressionBeforeBody(bc); // if(!query.go(ni.current()))break; adapter.loadLocal(tag.getQuery()); adapter.loadLocal(tag.getNumberIterator()); adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT); adapter.loadArg(0); adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_ID); adapter.invokeInterface(Types.QUERY, TagLoop.GO); /*OLD adapter.invokeInterface(Types.QUERY, TagLoop.GO_1); */ NotVisitor.visitNot(bc); Label _if=new Label(); adapter.ifZCmp(Opcodes.IFEQ, _if); wv.visitBreak(bc); adapter.visitLabel(_if); // current=ni.current(); adapter.loadLocal(tag.getNumberIterator()); adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT); adapter.storeLocal(icurrent); tag.getBody().writeOut(bc); // ni.setCurrent(current+1); /*adapter.loadLocal(tag.getNumberIterator()); adapter.loadLocal(icurrent); adapter.push(1); adapter.visitInsn(Opcodes.IADD); adapter.invokeVirtual(NUMBER_ITERATOR, SET_CURRENT);*/ wv.visitAfterBody(bc,tag.getEnd()); resetCurrentrow(adapter,tag,current); // ni.first(); adapter.loadLocal(tag.getNumberIterator()); adapter.invokeVirtual(NUMBER_ITERATOR, FIRST); adapter.pop(); } public static void writeOutTypeInnerQuery(TagGroup tag,BytecodeContext bc) throws BytecodeException { GeneratorAdapter adapter = bc.getAdapter(); //if(tr ue)return ; TagGroup parent = getParentTagGroupQuery(tag,tag.getType()); tag.setNumberIterator(parent.getNumberIterator()); tag.setQuery(parent.getQuery()); tag.setPID(parent.getPID()); //queryImpl = parent.getQueryImpl(); //int currentOuter=ni.current(); int current=adapter.newLocal(Types.INT_VALUE); adapter.loadLocal(tag.getNumberIterator()); adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT); adapter.storeLocal(current); // current int icurrent=adapter.newLocal(Types.INT_VALUE); adapter.loadLocal(current); adapter.push(1); adapter.visitInsn(Opcodes.ISUB); adapter.storeLocal(icurrent); WhileVisitor wv = new WhileVisitor(); if(tag instanceof TagLoop) ((TagLoop)tag).setLoopVisitor(wv); wv.visitBeforeExpression(bc); //while(ni.isValid()) { adapter.loadLocal(tag.getNumberIterator()); adapter.loadLocal(icurrent); adapter.push(1); adapter.visitInsn(Opcodes.IADD); adapter.invokeVirtual(NUMBER_ITERATOR, IS_VALID_1); wv.visitAfterExpressionBeforeBody(bc); // if(!query.go(ni.current()))break; adapter.loadLocal(tag.getQuery()); adapter.loadLocal(tag.getNumberIterator()); adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT); adapter.loadLocal(tag.getPID()); adapter.invokeInterface(Types.QUERY, TagLoop.GO); NotVisitor.visitNot(bc); Label _if=new Label(); adapter.ifZCmp(Opcodes.IFEQ, _if); wv.visitBreak(bc); adapter.visitLabel(_if); // current=ni.current(); adapter.loadLocal(tag.getNumberIterator()); adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT); adapter.storeLocal(icurrent); tag.getBody().writeOut(bc); // ni.setCurrent(current+1); /*adapter.loadLocal(tag.getNumberIterator()); adapter.loadLocal(icurrent); adapter.push(1); adapter.visitInsn(Opcodes.IADD); adapter.invokeVirtual(NUMBER_ITERATOR, SET_CURRENT);*/ wv.visitAfterBody(bc,tag.getEnd()); // ni.setCurrent(currentOuter); adapter.loadLocal(tag.getNumberIterator()); adapter.loadLocal(current); adapter.invokeVirtual(NUMBER_ITERATOR, SET_CURRENT); adapter.loadLocal(tag.getQuery()); adapter.loadLocal(current); adapter.loadLocal(tag.getPID()); //adapter.loadArg(0); //adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_ID); adapter.invokeInterface(Types.QUERY, TagLoop.GO); adapter.pop(); //adapter.pop(); } public static TagGroup getParentTagGroupQuery(Statement st, short type) throws BytecodeException { Statement parent=st.getParent(); if(parent==null) throw new BytecodeException("there is no parent output with query",null); else if(parent instanceof TagGroup && type==((TagGroup)parent).getType()) { if(((TagGroup)parent).hasQuery()) return ((TagGroup)parent); } return getParentTagGroupQuery(parent,type); } private static void resetCurrentrow(GeneratorAdapter adapter,TagGroup tg, int current) { //query.go(ni.current(),pc.getId()) adapter.loadLocal(tg.getQuery()); adapter.loadLocal(current); adapter.loadArg(0); adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_ID); adapter.invokeInterface(Types.QUERY, TagLoop.GO); /* OLD adapter.invokeInterface(Types.QUERY, TagLoop.GO_1); */ adapter.pop(); } }