Пример #1
0
 internal LocalStorage(LambdaCompiler compiler, ParameterExpression variable)
     : base(compiler, variable) {
     // ByRef variables are supported. This is used internally by
     // the compiler when emitting an inlined lambda invoke, to 
     // handle ByRef parameters. BlockExpression prevents this
     // from being exposed to user created trees.
     _local = compiler.GetNamedLocal(variable.IsByRef ? variable.Type.MakeByRefType() : variable.Type, variable);
 }
        private void EmitConstantFromArray(LambdaCompiler lc, object value, Type type)
        {
            int index;

            if (!_indexes.TryGetValue(value, out index))
            {
                _indexes.Add(value, index = _values.Count);
                _values.Add(value);
            }

            lc.IL.EmitInt(index);
            lc.IL.Emit(OpCodes.Ldelem_Ref);
            if (type.IsValueType)
            {
                lc.IL.Emit(OpCodes.Unbox_Any, type);
            }
            else if (type != typeof(object))
            {
                lc.IL.Emit(OpCodes.Castclass, type);
            }
        }
        public void Test1()
        {
            Expression <Func <TestClassA, int?> > exp = o => o.ArrayB[0].X;
            Func <TestClassA, int?> compiledExp       = LambdaCompiler.Compile(exp, CompilerOptions.All);

            Assert.That(compiledExp(null), Is.EqualTo(null));
            Assert.That(compiledExp(new TestClassA()), Is.EqualTo(null));
            Assert.That(compiledExp(new TestClassA {
                ArrayB = new TestClassB[] { null }
            }), Is.EqualTo(null));
            Assert.That(compiledExp(new TestClassA {
                ArrayB = new[] { new TestClassB() }
            }), Is.EqualTo(null));
            int?actual = compiledExp(new TestClassA {
                ArrayB = new[] { new TestClassB {
                                     X = 1
                                 } }
            });

            Assert.That(actual, Is.EqualTo(1));
        }
Пример #4
0
        public void TestLogical4()
        {
            Expression <Func <TestClassA, bool?> > exp = o => !(o.B.X > 0);
            Func <TestClassA, bool?> compiledExp       = LambdaCompiler.Compile(exp, CompilerOptions.All);

            Assert.IsNull(compiledExp(null));
            Assert.IsNull(compiledExp(new TestClassA()));
            Assert.IsNull(compiledExp(new TestClassA {
                B = new TestClassB()
            }));
            Assert.AreEqual(true, compiledExp(new TestClassA {
                B = new TestClassB {
                    X = -1
                }
            }));
            Assert.AreEqual(false, compiledExp(new TestClassA {
                B = new TestClassB {
                    X = 1
                }
            }));
        }
Пример #5
0
        public void Each_03()
        {
            var lambda = LambdaCompiler.Compile <Nothing>(new Nothing(), @"
var(@foo, list(""57"", ""67"", ""77"", ""88.88"", ""97""))
var(@bar, list())
each(@ix, foo, {
  if(any(@eq(""57"", ix), @eq(""77"", ix), @eq(""88.88"", ix)), {
    add(bar, number(ix))
  })
})
bar");
            var result = lambda();

            Assert.IsTrue(result is List <object>);
            var list = result as List <object>;

            Assert.AreEqual(3, list.Count);
            Assert.AreEqual(57, list[0]);
            Assert.AreEqual(77, list[1]);
            Assert.AreEqual(88.88, list[2]);
        }
Пример #6
0
        public Test2()
        {
            list = new List <TestData>();
            for (int i = 0; i < 1000000; ++i)
            {
                list.Add(new TestData {
                    X = i
                });
            }
            linq       = x => x.Aggregate(0, (s, o) => s + o.X);
            loopsSharp = x =>
            {
                int res = 0;
                for (int i = 0; i < x.Count; i++)
                {
                    res = res + x[i].X;
                }
                return(res);
            };
            Expression <Func <List <TestData>, int> > exp = x => x.Aggregate(0, (s, o) => s + o.X);

            loopsExpression = LambdaCompiler.Compile(exp.EliminateLinq(), CompilerOptions.None);
        }
Пример #7
0
        public void TestEnumConstant()
        {
            var typeBuilder   = moduleBuilder.DefineType(Guid.NewGuid().ToString(), TypeAttributes.Class);
            var methodName    = nameof(TestEnumConstant);
            var methodBuilder = typeBuilder.DefineMethod(methodName, MethodAttributes.Public | MethodAttributes.Static);

            // Cannot use Expression<Func<>> interface here because enum type gets optimized to int
            // Expression<Func<TestEnum, string>> expression = x => x == TestEnum.Two ? "2" : x.ToString();
            var parameter = Expression.Parameter(typeof(TestEnum));
            var constant  = Expression.Constant(TestEnum.Two, typeof(TestEnum));
            var condition = Expression.Condition(Expression.Equal(parameter, constant),
                                                 Expression.Constant("2", typeof(string)),
                                                 Expression.Call(parameter, typeof(object).GetMethod("ToString", Type.EmptyTypes)));
            var lambda = Expression.Lambda(condition, parameter);

            LambdaCompiler.CompileToMethod(lambda, methodBuilder, CompilerOptions.All);

            var type   = typeBuilder.CreateType();
            var method = type.GetMethod(methodName, new[] { typeof(TestEnum) });

            Assert.That(method.Invoke(null, new object[] { TestEnum.Two }), Is.EqualTo("2"));
            Assert.That(method.Invoke(null, new object[] { TestEnum.One }), Is.EqualTo("One"));
        }
Пример #8
0
        public void TestNullablePrimitiveConstant()
        {
            var typeBuilder   = moduleBuilder.DefineType(Guid.NewGuid().ToString(), TypeAttributes.Class);
            var methodName    = nameof(TestNullablePrimitiveConstant);
            var methodBuilder = typeBuilder.DefineMethod(methodName, MethodAttributes.Public | MethodAttributes.Static);

            // Cannot declare constant of nullable type via Expression<Func<>> interface
            // Expression<Func<int?, string>> expression = x => x == (int? 2) ? "two" : x.ToString();
            var parameter = Expression.Parameter(typeof(int?));
            var constant  = Expression.Constant((int?)2, typeof(int?));
            var condition = Expression.Condition(Expression.Equal(parameter, constant),
                                                 Expression.Constant("two", typeof(string)),
                                                 Expression.Call(parameter, typeof(int?).GetMethod("ToString", Type.EmptyTypes)));
            var lambda = Expression.Lambda(condition, parameter);

            LambdaCompiler.CompileToMethod(lambda, methodBuilder, CompilerOptions.All);

            var type   = typeBuilder.CreateType();
            var method = type.GetMethod(methodName, new[] { typeof(int?) });

            Assert.That(method.Invoke(null, new object[] { new int?(2) }), Is.EqualTo("two"));
            Assert.That(method.Invoke(null, new object[] { new int?(3) }), Is.EqualTo("3"));
        }
Пример #9
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);
 }
Пример #10
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);
            }
        }
Пример #11
0
 private void CacheBoxToLocal(LambdaCompiler lc, ParameterExpression v) {
     Debug.Assert(ShouldCache(v) && !_locals.ContainsKey(v));
     var local = new LocalBoxStorage(lc, v);
     local.EmitStoreBox();
     _locals.Add(v, local);
 }
Пример #12
0
        // Emits creation of the hoisted local storage
        private void EmitNewHoistedLocals(LambdaCompiler lc) {
            if (_hoistedLocals == null) {
                return;
            }

            // create the array
            lc.IL.EmitInt(_hoistedLocals.Variables.Count);
            lc.IL.Emit(OpCodes.Newarr, typeof(object));

            // initialize all elements
            int i = 0;
            foreach (ParameterExpression v in _hoistedLocals.Variables) {
                // array[i] = new StrongBox<T>(...);
                lc.IL.Emit(OpCodes.Dup);
                lc.IL.EmitInt(i++);
                Type boxType = typeof(StrongBox<>).MakeGenericType(v.Type);

                if (IsMethod && lc.Parameters.Contains(v)) {
                    // array[i] = new StrongBox<T>(argument);
                    int index = lc.Parameters.IndexOf(v);
                    lc.EmitLambdaArgument(index);
                    lc.IL.Emit(OpCodes.Newobj, boxType.GetConstructor(new Type[] { v.Type }));
                } else if (v == _hoistedLocals.ParentVariable) {
                    // array[i] = new StrongBox<T>(closure.Locals);
                    ResolveVariable(v, _closureHoistedLocals).EmitLoad();
                    lc.IL.Emit(OpCodes.Newobj, boxType.GetConstructor(new Type[] { v.Type }));
                } else {
#if CLR2
                    // array[i] = new StrongBox<T>(default(T));
                    lc.IL.EmitDefault(v.Type);
                    lc.IL.Emit(OpCodes.Newobj, boxType.GetConstructor(new Type[] { v.Type }));
#else
                    // array[i] = new StrongBox<T>();
                    lc.IL.Emit(OpCodes.Newobj, boxType.GetConstructor(Type.EmptyTypes));
#endif
                }
                // if we want to cache this into a local, do it now
                if (ShouldCache(v)) {
                    lc.IL.Emit(OpCodes.Dup);
                    CacheBoxToLocal(lc, v);
                }
                lc.IL.Emit(OpCodes.Stelem_Ref);
            }

            // store it
            EmitSet(_hoistedLocals.SelfVariable);
        }
Пример #13
0
 internal LocalBoxStorage(LambdaCompiler compiler, ParameterExpression variable)
     : base(compiler, variable) {
     _boxType = typeof(StrongBox<>).MakeGenericType(variable.Type);
     _boxValueField = _boxType.GetField("Value");
     _boxLocal = compiler.GetNamedLocal(_boxType, variable);
 }
Пример #14
0
        /// <summary>
        /// Called when entering a lambda/block. Performs all variable allocation
        /// needed, including creating hoisted locals and IL locals for accessing
        /// parent locals
        /// </summary>
        internal CompilerScope Enter(LambdaCompiler lc, CompilerScope parent) {
            SetParent(lc, parent);

            AllocateLocals(lc);

            if (IsMethod && _closureHoistedLocals != null) {
                EmitClosureAccess(lc, _closureHoistedLocals);
            }

            EmitNewHoistedLocals(lc);

            if (IsMethod) {
                EmitCachedVariables();
            }

            return this;
        }
Пример #15
0
 // Allocates slots for IL locals or IL arguments
 private void AllocateLocals(LambdaCompiler lc) {
     foreach (ParameterExpression v in GetVariables()) {
         if (Definitions[v] == VariableStorageKind.Local) {
             //
             // If v is in lc.Parameters, it is a parameter.
             // Otherwise, it is a local variable.
             //
             // Also, for inlined lambdas we'll create a local, which
             // is possibly a byref local if the parameter is byref.
             //
             Storage s;
             if (IsMethod && lc.Parameters.Contains(v)) {
                 s = new ArgumentStorage(lc, v);
             } else {
                 s = new LocalStorage(lc, v);
             }
             _locals.Add(v, s);
         }
     }
 }
Пример #16
0
        private void EmitInlinedInvoke(InvocationExpression invoke, CompilationFlags flags) {
            var lambda = invoke.LambdaOperand;

            // This is tricky: we need to emit the arguments outside of the
            // scope, but set them inside the scope. Fortunately, using the IL
            // stack it is entirely doable.

            // 1. Emit invoke arguments
            List<WriteBack> wb = EmitArguments(lambda.Type.GetMethod("Invoke"), invoke);

            // 2. Create the nested LambdaCompiler
            var inner = new LambdaCompiler(this, lambda);

            // 3. Emit the body
            // if the inlined lambda is the last expression of the whole lambda,
            // tail call can be applied.
            if (wb.Count != 0) {
                flags = UpdateEmitAsTailCallFlag(flags, CompilationFlags.EmitAsNoTail);
            }
            inner.EmitLambdaBody(_scope, true, flags);

            // 4. Emit writebacks if needed
            EmitWriteBack(wb);
        }
Пример #17
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;
        }
Пример #18
0
 internal Storage(LambdaCompiler compiler, ParameterExpression variable) {
     Compiler = compiler;
     Variable = variable;
 }
Пример #19
0
 /// <summary>
 /// Adds a new virtual variable corresponding to an IL local
 /// </summary>
 internal void AddLocal(LambdaCompiler gen, ParameterExpression variable) {
     _locals.Add(variable, new LocalStorage(gen, variable));
 }
Пример #20
0
 internal ArgumentStorage(LambdaCompiler compiler, ParameterExpression p)
     : base(compiler, p) {
     _argument = compiler.GetLambdaArgument(compiler.Parameters.IndexOf(p));
 }
Пример #21
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);
            }
        }