private void EmitClosureToVariable(LambdaCompiler lc, HoistedLocals locals)
 {
     lc.EmitClosureArgument();
     lc.IL.Emit(OpCodes.Ldfld, typeof(Closure).GetField("Locals"));
     AddLocal(lc, locals.SelfVariable);
     EmitSet(locals.SelfVariable);
 }
        // Creates IL locals for accessing closures
        private void EmitClosureAccess(LambdaCompiler lc, HoistedLocals locals)
        {
            if (locals == null)
            {
                return;
            }

            EmitClosureToVariable(lc, locals);

            while ((locals = locals.Parent) != null)
            {
                var v     = locals.SelfVariable;
                var local = new LocalStorage(lc, v);
                local.EmitStore(ResolveVariable(v));
                _locals.Add(v, local);
            }
        }
        private void SetParent(LambdaCompiler lc, CompilerScope parent)
        {
            Debug.Assert(_parent == null && parent != this);
            _parent = parent;

            if (NeedsClosure && _parent != null)
            {
                _closureHoistedLocals = _parent.NearestHoistedLocals;
            }

            var hoistedVars = GetVariables().Where(p => Definitions[p] == VariableStorageKind.Hoisted).ToReadOnly();

            if (hoistedVars.Count > 0)
            {
                _hoistedLocals = new HoistedLocals(_closureHoistedLocals, hoistedVars);
                AddLocal(lc, _hoistedLocals.SelfVariable);
            }
        }
예제 #4
0
        internal HoistedLocals(HoistedLocals parent, ReadOnlyCollection <ParameterExpression> vars)
        {
            if (parent != null)
            {
                // Add the parent locals array as the 0th element in the array
                vars = new TrueReadOnlyCollection <ParameterExpression>(vars.AddFirst(parent.SelfVariable));
            }

            var indexes = new Dictionary <Expression, int>(vars.Count);

            for (var i = 0; i < vars.Count; i++)
            {
                indexes.Add(vars[i], i);
            }

            SelfVariable = Expression.Variable(typeof(object[]), null);
            Parent       = parent;
            Variables    = vars;
            Indexes      = new ReadOnlyDictionary <Expression, int>(indexes);
        }
        private Storage ResolveVariable(ParameterExpression variable, HoistedLocals hoistedLocals)
        {
            // Search IL locals and arguments, but only in this lambda
            for (CompilerScope s = this; s != null; s = s._parent)
            {
                Storage storage;
                if (s._locals.TryGetValue(variable, out storage))
                {
                    return(storage);
                }

                // if this is a lambda, we're done
                if (s.IsMethod)
                {
                    break;
                }
            }

            // search hoisted locals
            for (HoistedLocals h = hoistedLocals; h != null; h = h.Parent)
            {
                int index;
                if (h.Indexes.TryGetValue(variable, out index))
                {
                    return(new ElementBoxStorage(
                               ResolveVariable(h.SelfVariable, hoistedLocals),
                               index,
                               variable
                               ));
                }
            }

            //
            // If this is an unbound variable in the lambda, the error will be
            // thrown from VariableBinder. So an error here is generally caused
            // by an internal error, e.g. a scope was created but it bypassed
            // VariableBinder.
            //
            throw Error.UndefinedVariable(variable.Name, variable.Type, CurrentLambdaName);
        }
        /// <summary>
        /// Frees unnamed locals, clears state associated with this compiler
        /// </summary>
        internal CompilerScope Exit()
        {
            // free scope's variables
            if (!IsMethod)
            {
                foreach (Storage storage in _locals.Values)
                {
                    storage.FreeLocal();
                }
            }

            // Clear state that is associated with this parent
            // (because the scope can be reused in another context)
            var parent = _parent;

            _parent               = null;
            _hoistedLocals        = null;
            _closureHoistedLocals = null;
            _locals.Clear();

            return(parent);
        }