示例#1
0
            private IStrongBox GetBox(ParameterExpression variable)
            {
                // Skip variables that are shadowed by a nested scope/lambda
                foreach (Set <ParameterExpression> hidden in _hiddenVars)
                {
                    if (hidden.Contains(variable))
                    {
                        return(null);
                    }
                }

                HoistedLocals scope = _scope;

                object[] locals = _locals;
                while (true)
                {
                    int hoistIndex;
                    if (scope.Indexes.TryGetValue(variable, out hoistIndex))
                    {
                        return((IStrongBox)locals[hoistIndex]);
                    }
                    scope = scope.Parent;
                    if (scope == null)
                    {
                        break;
                    }
                    locals = HoistedLocals.GetParent(locals);
                }

                // TODO: this should be unreachable because it's an unbound
                // variable, so we should throw here. It's a breaking change,
                // however
                return(null);
            }
示例#2
0
        public void Quote_RuntimeVariables_Hoisted3()
        {
            var x           = Expression.Parameter(typeof(int));
            var y           = Expression.Parameter(typeof(int));
            var variables   = new ReadOnlyCollection <ParameterExpression>(new[] { y });
            var definitions = new Dictionary <ParameterExpression, StorageKind>
            {
                { y, StorageKind.Hoisted | StorageKind.Boxed } // NB: Using Boxed for LINQ ET compatibility.
            };
            var h = new HoistedLocals(parent: null, variables, definitions);

            var e = Expression.Lambda <Func <int, IRuntimeVariables> >(Expression.RuntimeVariables(x, y), x);

            Assert.AreEqual(typeof(Closure <StrongBox <int> >), h.Closure.ClosureType);

            var c = new Closure <StrongBox <int> > {
                Item1 = new StrongBox <int>(42)
            };
            var q = (Expression <Func <int, IRuntimeVariables> >)RuntimeOpsEx.Quote(e, h, c);
            var f = q.Compile();

            Assert.AreEqual(41, f(41)[0]);
            Assert.AreEqual(42, f(41)[1]);
            Assert.AreEqual(2, f(41).Count);

            var r = f(43);

            r[0] = 44;
            r[1] = 45;
            Assert.AreEqual(44, r[0]);
            Assert.AreEqual(45, r[1]);
            Assert.AreEqual(45, c.Item1.Value);
        }
示例#3
0
            private IStrongBox GetBox(ParameterExpression variable)
            {
                int num;

                foreach (Set <ParameterExpression> set in this._shadowedVars)
                {
                    if (set.Contains(variable))
                    {
                        return(null);
                    }
                }
                HoistedLocals parent = this._scope;

                object[] objArray = this._locals;
                while (!parent.Indexes.TryGetValue(variable, out num))
                {
                    parent = parent.Parent;
                    if (parent == null)
                    {
                        throw ContractUtils.Unreachable;
                    }
                    objArray = HoistedLocals.GetParent(objArray);
                }
                return((IStrongBox)objArray[num]);
            }
示例#4
0
 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);
 }
示例#5
0
        public void Quote_Hoisted_Parent()
        {
            var x           = Expression.Parameter(typeof(int));
            var variables   = new ReadOnlyCollection <ParameterExpression>(new[] { x });
            var definitions = new Dictionary <ParameterExpression, StorageKind>
            {
                { x, StorageKind.Hoisted | StorageKind.Boxed } // NB: Using Boxed for LINQ ET compatibility.
            };
            var p = new HoistedLocals(parent: null, variables, definitions);
            var h = new HoistedLocals(p, new ReadOnlyCollection <ParameterExpression>(Array.Empty <ParameterExpression>()), new Dictionary <ParameterExpression, StorageKind>());

            var e = Expression.Lambda <Func <int> >(x);

            Assert.AreEqual(typeof(Closure <Closure <StrongBox <int> > >), h.Closure.ClosureType);

            var c = new Closure <Closure <StrongBox <int> > > {
                Item1 = new Closure <StrongBox <int> > {
                    Item1 = new StrongBox <int>(42)
                }
            };
            var q = (Expression <Func <int> >)RuntimeOpsEx.Quote(e, h, c);
            var f = q.Compile();

            Assert.AreEqual(42, f());

            c.Item1.Item1.Value = 43;
            Assert.AreEqual(43, f());
        }
            private IStrongBox GetBox(ParameterExpression variable)
            {
                // Skip variables that are shadowed by a nested scope/lambda
                foreach (Set <ParameterExpression> hidden in _shadowedVars)
                {
                    if (hidden.Contains(variable))
                    {
                        return(null);
                    }
                }

                HoistedLocals scope = _scope;

                object[] locals = _locals;
                while (true)
                {
                    int hoistIndex;
                    if (scope.Indexes.TryGetValue(variable, out hoistIndex))
                    {
                        return((IStrongBox)locals[hoistIndex]);
                    }
                    scope = scope.Parent;
                    if (scope == null)
                    {
                        break;
                    }
                    locals = HoistedLocals.GetParent(locals);
                }

                // Unbound variable: an error should've been thrown already
                // from VariableBinder
                throw ContractUtils.Unreachable;
            }
示例#7
0
            private IStrongBox GetStrongBox(int index)
            {
                long num = this._indexes[index];

                object[] locals = this._data;
                for (int i = (int)(num >> 0x20); i > 0; i--)
                {
                    locals = HoistedLocals.GetParent(locals);
                }
                return((IStrongBox)locals[(int)num]);
            }
示例#8
0
        // 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);
            }
        }
示例#9
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));
            }

            Dictionary<Expression, int> indexes = new Dictionary<Expression, int>(vars.Count);
            for (int 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);
        }
示例#10
0
            private IStrongBox GetStrongBox(int index)
            {
                // We lookup the closure using two ints:
                // 1. The high dword is the number of parents to go up
                // 2. The low dword is the index into that array
                long closureKey = _indexes[index];

                // walk up the parent chain to find the real environment
                object[] result = _data;
                for (int parents = (int)(closureKey >> 32); parents > 0; parents--)
                {
                    result = HoistedLocals.GetParent(result);
                }

                // Return the variable storage
                return((IStrongBox)result[unchecked ((int)closureKey)]);
            }
示例#11
0
        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);
            }
        }
示例#12
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));
            }

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

            for (int 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);
        }
示例#13
0
            public IStrongBox this[int index] {
                get {
                    // We lookup the closure using two ints:
                    // 1. The high dword is the number of parents to go up
                    // 2. The low dword is the index into that array
                    long closureKey = _indexes[index];

                    // walk up the parent chain to find the real environment
                    object[] result = _data;
                    for (int parents = (int)(closureKey >> 32); parents > 0; parents--)
                    {
                        result = HoistedLocals.GetParent(result);
                    }

                    // Return the variable storage
                    return((IStrongBox)result[(int)closureKey]);
                }
                set {
                    throw Error.CollectionReadOnly();
                }
            }
示例#14
0
        /// <summary>
        /// Resolve a local variable in this scope or a closed over scope
        /// Throws if the variable is defined
        /// </summary>
        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);
        }
示例#15
0
        /// <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)
            CompilerScope parent = _parent;

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

            return(parent);
        }
示例#16
0
        internal void EmitVariableAccess(LambdaCompiler lc, ReadOnlyCollection <ParameterExpression> vars)
        {
            if (NearestHoistedLocals != null)
            {
                // Find what array each variable is on & its index
                var indexes = new List <long>(vars.Count);

                foreach (var variable in vars)
                {
                    // For each variable, find what array it's defined on
                    ulong         parents = 0;
                    HoistedLocals locals  = NearestHoistedLocals;
                    while (!locals.Indexes.ContainsKey(variable))
                    {
                        parents++;
                        locals = locals.Parent;
                        Debug.Assert(locals != null);
                    }

                    // combine the number of parents we walked, with the
                    // real index of variable to get the index to emit.
                    ulong index = (parents << 32) | (uint)locals.Indexes[variable];

                    indexes.Add((long)index);
                }

                if (indexes.Count > 0)
                {
                    EmitGet(NearestHoistedLocals.SelfVariable);
                    lc.EmitConstantArray(indexes.ToArray());
                    lc.IL.Emit(OpCodes.Call, typeof(RuntimeOps).GetMethod("CreateRuntimeVariables", new[] { typeof(object[]), typeof(long[]) }));
                    return;
                }
            }

            // No visible variables
            lc.IL.Emit(OpCodes.Call, typeof(RuntimeOps).GetMethod("CreateRuntimeVariables", Type.EmptyTypes));
            return;
        }
示例#17
0
        public void Quote_RuntimeVariables_Hoisted2()
        {
            var x           = Expression.Parameter(typeof(int));
            var variables   = new ReadOnlyCollection <ParameterExpression>(Array.Empty <ParameterExpression>());
            var definitions = new Dictionary <ParameterExpression, StorageKind>();
            var h           = new HoistedLocals(parent: null, variables, definitions);

            var e = Expression.Lambda <Func <int, IRuntimeVariables> >(Expression.RuntimeVariables(x), x);

            Assert.AreEqual(typeof(Empty), h.Closure.ClosureType);

            var c = new Empty();
            var q = (Expression <Func <int, IRuntimeVariables> >)RuntimeOpsEx.Quote(e, h, c);
            var f = q.Compile();

            Assert.AreEqual(42, f(42)[0]);
            Assert.AreEqual(1, f(41).Count);

            var r = f(43);

            r[0] = 44;
            Assert.AreEqual(44, r[0]);
        }
 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);
            }
        }
        /// <summary>
        /// Resolve a local variable in this scope or a closed over scope
        /// Throws if the variable is defined
        /// </summary>
        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)
            CompilerScope parent = _parent;
            _parent = null;
            _hoistedLocals = null;
            _closureHoistedLocals = null;
            _locals.Clear();

            return parent;
        }
 internal ExpressionQuoter(HoistedLocals scope, object[] locals)
 {
     _scope  = scope;
     _locals = locals;
 }
示例#24
0
 /// <summary>
 /// Creates a new expression quoter.
 /// </summary>
 /// <param name="locals">The hoisted locals information gathered by the compiler at compile time.</param>
 /// <param name="closure">The closure to access for the binding of hoisted variables.</param>
 public ExpressionQuoter(HoistedLocals locals, IRuntimeVariables closure)
 {
     _locals  = locals;
     _closure = closure;
 }