001 package railo.transformer.bytecode.statement; 002 003 import org.objectweb.asm.Label; 004 import org.objectweb.asm.Opcodes; 005 import org.objectweb.asm.Type; 006 import org.objectweb.asm.commons.GeneratorAdapter; 007 import org.objectweb.asm.commons.Method; 008 009 import railo.runtime.util.ForEachUtil; 010 import railo.transformer.bytecode.Body; 011 import railo.transformer.bytecode.BytecodeContext; 012 import railo.transformer.bytecode.BytecodeException; 013 import railo.transformer.bytecode.Position; 014 import railo.transformer.bytecode.expression.Expression; 015 import railo.transformer.bytecode.expression.var.Variable; 016 import railo.transformer.bytecode.expression.var.VariableRef; 017 import railo.transformer.bytecode.util.ExpressionUtil; 018 import railo.transformer.bytecode.util.Types; 019 import railo.transformer.bytecode.visitor.OnFinally; 020 import railo.transformer.bytecode.visitor.TryFinallyVisitor; 021 022 public final class ForEach extends StatementBase implements FlowControlBreak,FlowControlContinue,HasBody { 023 024 025 private Body body; 026 private VariableRef key; 027 private Variable value; 028 029 private final static Method HAS_NEXT = new Method("hasNext",Types.BOOLEAN_VALUE,new Type[]{}); 030 private final static Method NEXT = new Method("next",Types.OBJECT,new Type[]{}); 031 private final static Method SET = new Method("set",Types.OBJECT,new Type[]{Types.PAGE_CONTEXT,Types.OBJECT}); 032 public static final Method TO_ITERATOR = new Method("toIterator",Types.ITERATOR,new Type[]{Types.OBJECT}); 033 private static final Type FOR_EACH_UTIL = Type.getType(ForEachUtil.class); 034 protected static final Method RESET = new Method("reset",Types.VOID,new Type[]{Types.ITERATOR}); 035 036 //private static final Type COLLECTION_UTIL = Type.getType(CollectionUtil.class); 037 038 private Label begin = new Label(); 039 private Label end = new Label(); 040 private FlowControlFinal fcf; 041 private String label; 042 043 /** 044 * Constructor of the class 045 * @param key 046 * @param value 047 * @param body 048 * @param line 049 */ 050 public ForEach(Variable key,Variable value,Body body,Position start, Position end,String label) { 051 super(start,end); 052 this.key=new VariableRef(key); 053 this.value=value; 054 this.body=body; 055 this.label=label; 056 body.setParent(this); 057 058 } 059 060 @Override 061 public void _writeOut(BytecodeContext bc) throws BytecodeException { 062 GeneratorAdapter adapter = bc.getAdapter(); 063 final int it=adapter.newLocal(Types.ITERATOR); 064 final int item=adapter.newLocal(Types.REFERENCE); 065 066 //Value 067 // ForEachUtil.toIterator(value) 068 value.writeOut(bc, Expression.MODE_REF); 069 adapter.invokeStatic(FOR_EACH_UTIL, TO_ITERATOR); 070 //adapter.invokeStatic(COLLECTION_UTIL, TO_ITERATOR); 071 // Iterator it=... 072 adapter.storeLocal(it); 073 TryFinallyVisitor tfv=new TryFinallyVisitor(new OnFinally() { 074 075 @Override 076 public void writeOut(BytecodeContext bc) throws BytecodeException { 077 GeneratorAdapter a = bc.getAdapter(); 078 //if(fcf!=null && fcf.getAfterFinalGOTOLabel()!=null)ASMUtil.visitLabel(a,fcf.getFinalEntryLabel()); 079 a.loadLocal(it); 080 a.invokeStatic(FOR_EACH_UTIL, RESET); 081 /*if(fcf!=null){ 082 Label l=fcf.getAfterFinalGOTOLabel(); 083 if(l!=null)a.visitJumpInsn(Opcodes.GOTO, l); 084 }*/ 085 } 086 },getFlowControlFinal()); 087 tfv.visitTryBegin(bc); 088 // Key 089 // new VariableReference(...) 090 key.writeOut(bc, Expression.MODE_REF); 091 // VariableReference item=... 092 adapter.storeLocal(item); 093 094 // while 095 ExpressionUtil.visitLine(bc, getStart()); 096 adapter.visitLabel(begin); 097 098 // hasNext 099 adapter.loadLocal(it); 100 adapter.invokeInterface(Types.ITERATOR, HAS_NEXT); 101 adapter.ifZCmp(Opcodes.IFEQ, end); 102 103 // item.set(pc,it.next()); 104 adapter.loadLocal(item); 105 adapter.loadArg(0); 106 adapter.loadLocal(it); 107 adapter.invokeInterface(Types.ITERATOR, NEXT); 108 adapter.invokeInterface(Types.REFERENCE, SET); 109 adapter.pop(); 110 111 // Body 112 body.writeOut(bc); 113 adapter.visitJumpInsn(Opcodes.GOTO, begin); 114 adapter.visitLabel(end); 115 tfv.visitTryEnd(bc); 116 117 } 118 119 @Override 120 public Label getBreakLabel() { 121 return end; 122 } 123 124 @Override 125 public Label getContinueLabel() { 126 return begin; 127 } 128 129 @Override 130 public Body getBody() { 131 return body; 132 } 133 134 @Override 135 public FlowControlFinal getFlowControlFinal() { 136 if(fcf==null) fcf=new FlowControlFinalImpl(); 137 return fcf; 138 } 139 140 @Override 141 public String getLabel() { 142 return label; 143 } 144 }