001 package railo.transformer.bytecode.expression.var; 002 003 import org.objectweb.asm.Type; 004 import org.objectweb.asm.commons.GeneratorAdapter; 005 import org.objectweb.asm.commons.Method; 006 007 import railo.runtime.type.scope.Scope; 008 import railo.runtime.type.scope.ScopeFactory; 009 import railo.runtime.type.scope.ScopeSupport; 010 import railo.transformer.bytecode.BytecodeContext; 011 import railo.transformer.bytecode.BytecodeException; 012 import railo.transformer.bytecode.expression.Expression; 013 import railo.transformer.bytecode.expression.ExpressionBase; 014 import railo.transformer.bytecode.literal.LitString; 015 import railo.transformer.bytecode.util.ExpressionUtil; 016 import railo.transformer.bytecode.util.TypeScope; 017 import railo.transformer.bytecode.util.Types; 018 019 public class Assign extends ExpressionBase { 020 021 //final static Method[] METHODS_SCOPE_SET = new Method[6]; 022 023 024 025 // java.lang.Object set(String,Object) 026 private final static Method METHOD_SCOPE_SET = new Method("set", 027 Types.OBJECT, 028 new Type[]{Types.STRING,Types.OBJECT}); 029 030 // java.lang.Object set(String,Object) 031 private final static Method METHOD_SCOPE_SET_KEY = new Method("set", 032 Types.OBJECT, 033 new Type[]{Types.COLLECTION_KEY,Types.OBJECT}); 034 035 // .setArgument(obj) 036 private final static Method SET_ARGUMENT = new Method("setArgument", 037 Types.OBJECT, 038 new Type[]{Types.OBJECT}); 039 040 041 // Object touch (Object,String) 042 private final static Method TOUCH = new Method("touch", 043 Types.OBJECT, 044 new Type[]{Types.OBJECT,Types.STRING}); 045 046 // Object touch (Object,String) 047 private final static Method TOUCH_KEY = new Method("touch", 048 Types.OBJECT, 049 new Type[]{Types.OBJECT,Types.COLLECTION_KEY}); 050 051 052 //Object set (Object,String,Object) 053 private final static Method SET_KEY = new Method("set", 054 Types.OBJECT, 055 new Type[]{Types.OBJECT,Types.COLLECTION_KEY,Types.OBJECT}); 056 057 //Object set (Object,String,Object) 058 private final static Method SET = new Method("set", 059 Types.OBJECT, 060 new Type[]{Types.OBJECT,Types.STRING,Types.OBJECT}); 061 062 // Object getFunction (Object,String,Object[]) 063 private final static Method GET_FUNCTION = new Method("getFunction", 064 Types.OBJECT, 065 new Type[]{Types.OBJECT,Types.STRING,Types.OBJECT_ARRAY}); 066 067 // Object getFunctionWithNamedValues (Object,String,Object[]) 068 private final static Method GET_FUNCTION_WITH_NAMED_ARGS = new Method("getFunctionWithNamedValues", 069 Types.OBJECT, 070 new Type[]{Types.OBJECT,Types.STRING,Types.OBJECT_ARRAY}); 071 072 073 // Object getFunction (Object,String,Object[]) 074 private final static Method GET_FUNCTION_KEY = new Method("getFunction", 075 Types.OBJECT, 076 new Type[]{Types.OBJECT,Types.COLLECTION_KEY,Types.OBJECT_ARRAY}); 077 078 // Object getFunctionWithNamedValues (Object,String,Object[]) 079 private final static Method GET_FUNCTION_WITH_NAMED_ARGS_KEY = new Method("getFunctionWithNamedValues", 080 Types.OBJECT, 081 new Type[]{Types.OBJECT,Types.COLLECTION_KEY,Types.OBJECT_ARRAY}); 082 083 084 private Variable variable; 085 private Expression value; 086 087 088 /** 089 * Constructor of the class 090 * @param variable 091 * @param value 092 */ 093 public Assign(Variable variable, Expression value) { 094 super(variable.getStart(),variable.getEnd()); 095 this.variable=variable; 096 this.value=value; 097 //this.returnOldValue=returnOldValue; 098 } 099 100 101 public Type _writeOut(BytecodeContext bc, int mode) throws BytecodeException { 102 GeneratorAdapter adapter = bc.getAdapter(); 103 int count=variable.countFM+variable.countDM; 104 // count 0 105 if(count==0){ 106 if(variable.ignoredFirstMember() && variable.scope==ScopeSupport.SCOPE_VAR){ 107 //print.dumpStack(); 108 return Types.VOID; 109 } 110 return _writeOutEmpty(bc); 111 } 112 113 boolean doOnlyScope=variable.scope==Scope.SCOPE_LOCAL; 114 115 Type rtn=Types.OBJECT; 116 //boolean last; 117 for(int i=doOnlyScope?0:1;i<count;i++) { 118 adapter.loadArg(0); 119 } 120 rtn=_writeOutFirst(bc, (variable.members.get(0)),mode,count==1,doOnlyScope); 121 122 // pc.get( 123 for(int i=doOnlyScope?0:1;i<count;i++) { 124 Member member=(variable.members.get(i)); 125 boolean last=(i+1)==count; 126 127 128 // Data Member 129 if(member instanceof DataMember) { 130 //((DataMember)member).getName().writeOut(bc, MODE_REF); 131 boolean isKey=Variable.registerKey(bc, ((DataMember)member).getName()); 132 133 if(last)value.writeOut(bc, MODE_REF); 134 if(isKey)adapter.invokeVirtual(Types.PAGE_CONTEXT,last?SET_KEY:TOUCH_KEY); 135 else adapter.invokeVirtual(Types.PAGE_CONTEXT,last?SET:TOUCH); 136 rtn=Types.OBJECT; 137 } 138 139 // UDF 140 else if(member instanceof UDF) { 141 if(last)throw new BytecodeException("can't asign value to a user defined function",getStart()); 142 UDF udf=(UDF) member; 143 boolean isKey=Variable.registerKey(bc, udf.getName()); 144 //udf.getName().writeOut(bc, MODE_REF); 145 ExpressionUtil.writeOutExpressionArray(bc, Types.OBJECT, udf.getArguments()); 146 147 if(isKey)adapter.invokeVirtual(Types.PAGE_CONTEXT,udf.hasNamedArgs()?GET_FUNCTION_WITH_NAMED_ARGS_KEY:GET_FUNCTION_KEY); 148 else adapter.invokeVirtual(Types.PAGE_CONTEXT,udf.hasNamedArgs()?GET_FUNCTION_WITH_NAMED_ARGS:GET_FUNCTION); 149 rtn=Types.OBJECT; 150 } 151 } 152 return rtn; 153 } 154 155 private Type _writeOutFirst(BytecodeContext bc, Member member, int mode, boolean last, boolean doOnlyScope) throws BytecodeException { 156 157 if(member instanceof DataMember) { 158 return _writeOutOneDataMember(bc,(DataMember)member,last,doOnlyScope); 159 //return Variable._writeOutFirstDataMember(adapter,(DataMember)member,variable.scope, last); 160 } 161 else if(member instanceof UDF) { 162 if(last)throw new BytecodeException("can't assign value to a user defined function",getStart()); 163 return Variable._writeOutFirstUDF(bc,(UDF)member,variable.scope,doOnlyScope); 164 } 165 else { 166 if(last)throw new BytecodeException("can't assign value to a built in function",getStart()); 167 return Variable._writeOutFirstBIF(bc,(BIF)member,mode,last,getStart()); 168 } 169 } 170 171 172 173 private Type _writeOutOneDataMember(BytecodeContext bc, DataMember member,boolean last, boolean doOnlyScope) throws BytecodeException { 174 GeneratorAdapter adapter = bc.getAdapter(); 175 176 if(doOnlyScope){ 177 adapter.loadArg(0); 178 if(variable.scope==Scope.SCOPE_LOCAL){ 179 return TypeScope.invokeScope(adapter, TypeScope.METHOD_LOCAL_TOUCH,Types.PAGE_CONTEXT); 180 } 181 return TypeScope.invokeScope(adapter, variable.scope); 182 } 183 184 // pc.get 185 adapter.loadArg(0); 186 if(last) { 187 TypeScope.invokeScope(adapter, variable.scope); 188 //adapter.invokeVirtual(Types.PAGE_CONTEXT,TypeScope.METHODS[variable.scope]); 189 190 boolean isKey=Variable.registerKey(bc, member.getName()); 191 value.writeOut(bc, MODE_REF); 192 193 if(isKey)adapter.invokeInterface(TypeScope.SCOPES[variable.scope],METHOD_SCOPE_SET_KEY); 194 else adapter.invokeInterface(TypeScope.SCOPES[variable.scope],METHOD_SCOPE_SET); 195 196 } 197 else { 198 adapter.loadArg(0); 199 TypeScope.invokeScope(adapter, variable.scope); 200 if(Variable.registerKey(bc, member.getName())) 201 adapter.invokeVirtual(Types.PAGE_CONTEXT,TOUCH_KEY); 202 else 203 adapter.invokeVirtual(Types.PAGE_CONTEXT,TOUCH); 204 } 205 return Types.OBJECT; 206 207 208 } 209 210 private Type _writeOutEmpty(BytecodeContext bc) throws BytecodeException { 211 GeneratorAdapter adapter = bc.getAdapter(); 212 213 if(variable.scope==Scope.SCOPE_ARGUMENTS) { 214 adapter.loadArg(0); 215 TypeScope.invokeScope(adapter, Scope.SCOPE_ARGUMENTS); 216 value.writeOut(bc, MODE_REF); 217 adapter.invokeInterface(TypeScope.SCOPE_ARGUMENT,SET_ARGUMENT); 218 } 219 else { 220 adapter.loadArg(0); 221 TypeScope.invokeScope(adapter, Scope.SCOPE_UNDEFINED); 222 Variable.registerKey(bc,LitString.toExprString(ScopeFactory.toStringScope(variable.scope,"undefined"))); 223 value.writeOut(bc, MODE_REF); 224 adapter.invokeInterface(TypeScope.SCOPES[Scope.SCOPE_UNDEFINED],METHOD_SCOPE_SET_KEY); 225 } 226 227 228 return Types.OBJECT; 229 } 230 231 /** 232 * @return the value 233 */ 234 public Expression getValue() { 235 return value; 236 } 237 238 239 /** 240 * @return the variable 241 */ 242 public Variable getVariable() { 243 return variable; 244 } 245 }