private Variable GetAndCreateVariable(uint vid, bool create) { Variable v = vars[vid] as Variable; if(v == null) { if(IsBlock) { Variable dv = GetMethodScope().vars[vid] as Variable; if(dv != null) { if(create) { dv.IsDynamic = true; dv.closure_slot = GetMethodScope().CreateClosureSlot(); } else if(!dv.IsDynamic) { throw new Exception("bug: missing dynamic data for dynamic var: " + context.id2name(vid)); } return dv; } } if(create) { v = new Variable(); vars[vid] = v; return v; } else { throw new Exception("Local not found: " + context.id2name(vid)); } } return v; }
internal override void Walk(EmitContext ec) { // Due to the slightly weird RNode inheritance hierarchy bool is_load = this is RNLVar || this is RNDVar; if(!(is_load || this is RNDAsgn || this is RNLAsgn)) { throw new NotSupportedException("bug: variable type not supported: " + this.GetType().Name); } if(ec.Resolving) { v = ec.scope.MarkVariable(vid); } if(!is_load) val.Walk(ec); if(ec.Emitting) { if(is_load) { Variable v = ec.scope.GetVariable(vid); ec.EmitLoadVar(v); } else { ec.EmitDup(); ec.EmitStoreVar(v); } } }
// ( -- val ) internal void EmitLoadVar(Variable v) { if(v.IsDynamic) { EmitLoadClosureArray(); EmitInt(v.closure_slot); ig.Emit(OpCodes.Ldelem_Ref); } else { AllocateLocal(v); ig.Emit(OpCodes.Ldloc, v.local); } }
// ( -- ) internal void EmitStoreVar(Variable v) { if(v.IsDynamic) { LocalBuilder tmp = EmitStoreTemp(); EmitLoadClosureArray(); EmitInt(v.closure_slot); EmitLoadTemp(tmp); ig.Emit(OpCodes.Stelem_Ref); } else { AllocateLocal(v); ig.Emit(OpCodes.Stloc, v.local); } }
void AllocateLocal(Variable v) { if(v.local == null) { v.local = ig.DeclareLocal(typeof(RBasic)); } }