internal Slot CreateSlot(CodeGen cg) { switch (_kind) { case VariableKind.Local: if (_storage == null) { // Fall back on a runtime lookup if this variable does not have storage associated with it // (e.g. if the variable belongs to a block in interpreted mode). return new LocalNamedFrameSlot(cg.ContextSlot, _name); } else { return CreateSlotForVariable(cg); } case VariableKind.Parameter: if (_lift) { if (_storage == null) { return new LocalNamedFrameSlot(cg.ContextSlot, _name); } else { return CreateSlotForVariable(cg); } } else { //Debug.Assert(cg.Allocator.ActiveScope == _block); return MarkLocal(GetArgumentSlot(cg)); } case VariableKind.Global: if (_storage == null) { return new NamedFrameSlot(cg.ContextSlot, _name); } else { // Globals are accessed via context slot return _storage.CreateSlot(cg.ContextSlot); } case VariableKind.Temporary: return cg.GetNamedLocal(_type, SymbolTable.IdToString(_name)); case VariableKind.GeneratorTemporary: if (!cg.IsGenerator) { goto case VariableKind.Temporary; } // Allocate in environment if emitting generator. // This must be done here for now because the environment // allocation, which is generally done in Allocate(), // is done in the context of the outer generator codegen, // which is not marked IsGenerator so the generator temps // would go onto CLR stack rather than environment. // TODO: Fix this once we have lifetime analysis in place. _storage = _block.EnvironmentFactory.MakeEnvironmentReference(_name, _type); return CreateSlotForVariable(cg); } Debug.Assert(false, "Unexpected variable kind: " + _kind.ToString()); return null; }
/// <summary> /// Will allocate the storage in the environment and return slot to access /// the variable in the current scope (so that it can be initialized) /// </summary> private Slot AllocInEnv(CodeGen cg) { //Debug.Assert(_storage == null); Debug.Assert(_block.EnvironmentFactory != null, "Allocating in environment without environment factory.\nIs HasEnvironment set?"); _storage = _block.EnvironmentFactory.MakeEnvironmentReference(_name, _type); return _storage.CreateSlot(cg.Allocator.GetClosureAccessSlot(_block)); }
internal void Allocate(CodeGen cg) { Debug.Assert(cg.Allocator.Block == Block); switch (_kind) { case VariableKind.Local: if (_block.IsGlobal) { // Local on global level, simply allocate the storage _storage = cg.Allocator.LocalAllocator.AllocateStorage(_name, _type); if (_defaultValue != null) { Slot slot = CreateSlotForVariable(cg); _defaultValue.Emit(cg); slot.EmitSet(cg); } } else { Slot slot; // If lifting local into closure, allocate in the environment if (_lift) { // allocate space in the environment and set it to Uninitialized slot = AllocInEnv(cg); } else { // Allocate the storage _storage = cg.Allocator.LocalAllocator.AllocateStorage(_name, _type); // No access slot for local variables, pass null. slot = _storage.CreateSlot(_storage.RequireAccessSlot ? cg.Allocator.GetScopeAccessSlot(_block) : null); MarkLocal(slot); } if (_uninitialized || _defaultValue != null) { // Emit initialization (environments will be initialized all at once) if (_defaultValue != null) { _defaultValue.Emit(cg); slot.EmitSet(cg); } else if (_type == typeof(object)) { // Only set variables of type object to "Uninitialized" //throw new UnInitializedUsageException(this, "Attempted to use uninitialized variable"); slot.EmitSetUninitialized(cg); } } } break; case VariableKind.Parameter: // Lifting parameter into closure, allocate in env and move. if (_lift) { Slot slot = AllocInEnv(cg); Slot src = GetArgumentSlot(cg); // Copy the value from the parameter (src) into the environment (slot) slot.EmitSet(cg, src); } else { Debug.Assert(cg.Allocator.Block == Block); // Nothing to do here } break; case VariableKind.Global: if (_defaultValue is UnboundExpression || cg.Allocator.Parent.Parent.Parent != null) { _storage = cg.Allocator.GlobalAllocator.AllocateStorage(_name, _type); } else { _storage = cg.Allocator.Parent.LocalAllocator.AllocateStorage(_name, _type); } Debug.Assert(_storage != null); break; case VariableKind.Temporary: // Nothing to do here break; case VariableKind.GeneratorTemporary: // Do the work in CreateSlot break; } }