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; 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.getLine()); 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, ((Member)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=((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",getLine()); 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",getLine()); 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",getLine()); 167 return Variable._writeOutFirstBIF(bc,(BIF)member,mode,last,getLine()); 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 adapter.checkCast(Types.PAGE_CONTEXT_IMPL); 180 return TypeScope.invokeScope(adapter, TypeScope.METHOD_LOCAL_TOUCH,Types.PAGE_CONTEXT_IMPL); 181 } 182 return TypeScope.invokeScope(adapter, variable.scope); 183 } 184 185 // pc.get 186 adapter.loadArg(0); 187 if(last) { 188 TypeScope.invokeScope(adapter, variable.scope); 189 //adapter.invokeVirtual(Types.PAGE_CONTEXT,TypeScope.METHODS[variable.scope]); 190 191 boolean isKey=Variable.registerKey(bc, member.getName()); 192 value.writeOut(bc, MODE_REF); 193 194 if(isKey)adapter.invokeInterface(TypeScope.SCOPES[variable.scope],METHOD_SCOPE_SET_KEY); 195 else adapter.invokeInterface(TypeScope.SCOPES[variable.scope],METHOD_SCOPE_SET); 196 197 } 198 else { 199 adapter.loadArg(0); 200 TypeScope.invokeScope(adapter, variable.scope); 201 if(Variable.registerKey(bc, member.getName())) 202 adapter.invokeVirtual(Types.PAGE_CONTEXT,TOUCH_KEY); 203 else 204 adapter.invokeVirtual(Types.PAGE_CONTEXT,TOUCH); 205 } 206 return Types.OBJECT; 207 208 209 } 210 211 private Type _writeOutEmpty(BytecodeContext bc) throws BytecodeException { 212 GeneratorAdapter adapter = bc.getAdapter(); 213 214 if(variable.scope==Scope.SCOPE_ARGUMENTS) { 215 adapter.loadArg(0); 216 TypeScope.invokeScope(adapter, Scope.SCOPE_ARGUMENTS); 217 adapter.checkCast(TypeScope.SCOPE_ARGUMENT_IMPL); 218 value.writeOut(bc, MODE_REF); 219 adapter.invokeVirtual(TypeScope.SCOPE_ARGUMENT_IMPL,SET_ARGUMENT); 220 } 221 else { 222 adapter.loadArg(0); 223 TypeScope.invokeScope(adapter, Scope.SCOPE_UNDEFINED); 224 Variable.registerKey(bc,LitString.toExprString(ScopeFactory.toStringScope(variable.scope,"undefined"),-1)); 225 value.writeOut(bc, MODE_REF); 226 adapter.invokeInterface(TypeScope.SCOPES[Scope.SCOPE_UNDEFINED],METHOD_SCOPE_SET_KEY); 227 } 228 229 230 return Types.OBJECT; 231 } 232 233 /** 234 * @return the value 235 */ 236 public Expression getValue() { 237 return value; 238 } 239 240 241 /** 242 * @return the variable 243 */ 244 public Variable getVariable() { 245 return variable; 246 } 247 }