Exemple #1
0
 internal static RedwoodType[] GetTypesFromMethodInfo(MethodInfo methodInfo)
 {
     ParameterInfo[] parameters = methodInfo.GetParameters();
     RedwoodType[]   types      = new RedwoodType[parameters.Length];
     for (int i = 0; i < parameters.Length; i++)
     {
         types[i] = RedwoodType.GetForCSharpType(parameters[i].ParameterType);
     }
     return(types);
 }
Exemple #2
0
 internal static RedwoodType GetTypeOf(object o)
 {
     if (o == null)
     {
         return(null);
     }
     else if (o is RedwoodObject rwo)
     {
         return(rwo.Type);
     }
     else
     {
         return(RedwoodType.GetForCSharpType(o.GetType()));
     }
 }
Exemple #3
0
 internal static RedwoodType[] GetTypesFromArgs(object[] args)
 {
     RedwoodType[] types = new RedwoodType[args.Length];
     for (int i = 0; i < types.Length; i++)
     {
         if (args[i] is RedwoodObject o)
         {
             types[i] = o.Type;
         }
         else
         {
             types[i] = RedwoodType.GetForCSharpType(args[i].GetType());
         }
     }
     return(types);
 }
Exemple #4
0
        static RedwoodType()
        {
            specialMappedTypes.Add("?", null);

            specialMappedTypes.Add("int", GetForCSharpType(typeof(int)));
            specialMappedTypes.Add("string", GetForCSharpType(typeof(string)));
            specialMappedTypes.Add("double", GetForCSharpType(typeof(double)));
            specialMappedTypes.Add("bool", GetForCSharpType(typeof(bool)));
            specialMappedTypes.Add("object", GetForCSharpType(typeof(object)));

            NullType.staticSlotMap = new Dictionary <string, int>();
            NullType.staticSlotMap[RuntimeUtil.NameForOperator(BinaryOperator.Equals)]    = 0;
            NullType.staticSlotMap[RuntimeUtil.NameForOperator(BinaryOperator.NotEquals)] = 1;
            NullType.staticSlotTypes = new RedwoodType[]
            {
                RedwoodType.GetForLambdaArgsTypes(
                    typeof(InPlaceLambda),
                    RedwoodType.GetForCSharpType(typeof(bool)),
                    new RedwoodType[] { null, null }
                    ),
                RedwoodType.GetForLambdaArgsTypes(
                    typeof(InPlaceLambda),
                    RedwoodType.GetForCSharpType(typeof(bool)),
                    new RedwoodType[] { null, null }
                    )
            };

            NullType.staticLambdas = new Lambda[] {
                new InPlaceLambda(
                    new RedwoodType[] { null, null },
                    GetForCSharpType(typeof(bool)),
                    new InPlaceLambdaExecutor((stack, locs) => {
                    return(stack[locs[0]] == null && stack[locs[1]] == null);
                })
                    ),
                new InPlaceLambda(
                    new RedwoodType[] { null, null },
                    GetForCSharpType(typeof(bool)),
                    new InPlaceLambdaExecutor((stack, locs) => {
                    return(stack[locs[0]] != null || stack[locs[1]] != null);
                })
                    )
            };
        }
Exemple #5
0
        internal static Type EmitInterfaceProxyType(RedwoodType type, Type @interface)
        {
            TypeBuilder tb = interfaceModules.DefineType(
                @interface.Name + "RedwoodProxy",
                TypeAttributes.Public | TypeAttributes.AutoClass | TypeAttributes.AnsiClass,
                typeof(object),
                new Type[] { @interface });

            FieldBuilder fb = tb.DefineField("proxy", typeof(object[]), FieldAttributes.Private);

            ConstructorBuilder cb = tb.DefineConstructor(
                MethodAttributes.Public |
                MethodAttributes.HideBySig |
                MethodAttributes.SpecialName |
                MethodAttributes.RTSpecialName,
                CallingConventions.HasThis,
                new Type[] { typeof(object[]) }
                );


            ILGenerator constructorGenerator = cb.GetILGenerator();
            // Call our base constructor
            ConstructorInfo objectConstructor = typeof(object).GetConstructor(new Type[] { });

            constructorGenerator.Emit(OpCodes.Ldarg_0);
            constructorGenerator.Emit(OpCodes.Call, objectConstructor);

            // Load this, then load arg 1, then set the local field
            constructorGenerator.Emit(OpCodes.Ldarg_0);
            constructorGenerator.Emit(OpCodes.Ldarg_1);
            constructorGenerator.Emit(OpCodes.Stfld, fb);

            constructorGenerator.Emit(OpCodes.Ret);

            MethodInfo runMethod = typeof(Lambda).GetMethod("Run");

            foreach (MethodInfo method in @interface.GetMethods())
            {
                Type[] paramTypes = method
                                    .GetParameters()
                                    .Select(param => param.ParameterType)
                                    .ToArray();

                // The method is on an interface so it is guaranteed
                // to have the abstract tag so we have to reverse that
                MethodBuilder mb = tb.DefineMethod(
                    method.Name,
                    method.Attributes ^ MethodAttributes.Abstract,
                    method.ReturnType,
                    paramTypes
                    );
                int numberOfArguments = method.GetParameters().Length;

                // The index into our proxy object array holding the overload
                int index = type.GetSlotNumberForOverload(
                    method.Name,
                    paramTypes
                    .Select(type => RedwoodType.GetForCSharpType(type))
                    .ToArray()
                    );

                ILGenerator generator = mb.GetILGenerator();
                generator.DeclareLocal(typeof(int));

                // Let's load the proxy object because we're going
                // to be accessing on it a little later
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Ldfld, fb);

                // Now go fishing for our overload
                generator.Emit(OpCodes.Ldc_I4, index);
                generator.Emit(OpCodes.Ldelem_Ref);
                // ILSpy says we do this check now -- I guess the actual throw
                // is handled by the runtime?
                generator.Emit(OpCodes.Isinst, typeof(Lambda));

                // Create an array to pass as the params argument
                generator.Emit(OpCodes.Ldc_I4, numberOfArguments);
                generator.Emit(OpCodes.Newarr, typeof(object));

                // Set each argument on the params array
                for (int i = 0; i < numberOfArguments; i++)
                {
                    // Get a copy of the array
                    generator.Emit(OpCodes.Dup);
                    // Index
                    generator.Emit(OpCodes.Ldc_I4, i);
                    // Element
                    generator.Emit(OpCodes.Ldarg, i + 1);

                    // Since we're going into an object array, we need
                    // to box our value types
                    if (paramTypes[i].IsValueType)
                    {
                        // TODO: is there a separate boxed type from value type?
                        generator.Emit(OpCodes.Box, paramTypes[i]);
                    }

                    // Set
                    generator.Emit(OpCodes.Stelem_Ref);
                }

                generator.Emit(OpCodes.Callvirt, runMethod);
                if (method.ReturnType.IsValueType)
                {
                    generator.Emit(OpCodes.Unbox_Any, method.ReturnType);
                }

                // For some reason, the compiler likes to store and load before
                // returning, so lets do it here too
                // TODO: does this look different for non-value types?
                generator.Emit(OpCodes.Stloc_0);
                generator.Emit(OpCodes.Ldloc_0);

                generator.Emit(OpCodes.Ret);
            }

            return(tb.CreateType());
        }
Exemple #6
0
        /// <summary>
        /// For the most part, the MemberResolver is able to resolve the
        /// methods, fields, and properties on C# types, but populating the
        /// slots for an interface will allow us to map to a specific order
        /// needed by the interface stitching done by the Emitter.
        /// </summary>
        private void InitInterfaceIfNecessary()
        {
            if (CSharpType == null || !CSharpType.IsInterface)
            {
                return;
            }

            IsInterface = true;

            var overloads = new Dictionary <string, Tuple <List <RedwoodType[]>, List <int> > >();
            int slot      = 0;
            List <RedwoodType> slotTypes = new List <RedwoodType>();

            slotMap      = new Dictionary <string, int>();
            overloadsMap = new Dictionary <int, Tuple <RedwoodType[][], int[]> >();

            foreach (MethodInfo method in CSharpType.GetMethods())
            {
                RedwoodType[] parameterTypes = method
                                               .GetParameters()
                                               .Select(param => RedwoodType.GetForCSharpType(param.ParameterType))
                                               .ToArray();
                if (!overloads.ContainsKey(method.Name))
                {
                    overloads[method.Name] = new Tuple <List <RedwoodType[]>, List <int> >(
                        new List <RedwoodType[]>(),
                        new List <int>()
                        );
                }

                slotTypes.Add(RedwoodType.GetForLambdaArgsTypes(
                                  typeof(ExternalLambda),
                                  RedwoodType.GetForCSharpType(method.ReturnType),
                                  parameterTypes
                                  ));

                overloads[method.Name].Item1.Add(parameterTypes);
                overloads[method.Name].Item2.Add(slot);
                slot++;
            }

            // For interfaces, the methods are all at the beginnings, overloads
            // all at the end
            foreach (string overloadName in overloads.Keys)
            {
                // TODO: Do we care about the overload type here?
                int[] overloadSlots = overloads[overloadName].Item2.ToArray();
                slotTypes.Add(RedwoodType
                              .GetForCSharpType(typeof(LambdaGroup))
                              .GetGenericSpecialization(
                                  overloadSlots
                                  .Select(slot => slotTypes[slot])
                                  .ToArray()
                                  )
                              );;


                slotMap[overloadName] = slot;
                overloadsMap[slot]    = new Tuple <RedwoodType[][], int[]>(
                    overloads[overloadName].Item1.ToArray(),
                    overloadSlots
                    );
                slot++;
            }

            numSlots       = slot;
            this.slotTypes = slotTypes.ToArray();
            // Technically a proxy type can occur from any redwood type to
            // any C# interface, but we emit for the interface we created
            // and then reuse it so that we can keep a cceiling on the
            // number of these classes that we create
            proxyType = Emitter.EmitInterfaceProxyType(this, CSharpType);
            ConstructorInfo constructor = proxyType.GetConstructor(new Type[] { typeof(object[]) });

            Constructor = new ExternalLambda(this, constructor);
        }
        static MemberResolver()
        {
            primitiveOperators = new Dictionary <Type, Dictionary <OperatorDescriptor, Lambda> >();

            // int operators
            RedwoodType boolType = RedwoodType.GetForCSharpType(typeof(bool));
            RedwoodType type     = RedwoodType.GetForCSharpType(typeof(int));

            RedwoodType[] unaryOperatorsType  = new RedwoodType[] { type };
            RedwoodType[] binaryOperatorsType = new RedwoodType[] { type, type };


            Dictionary <OperatorDescriptor, Lambda> intOperators =
                new Dictionary <OperatorDescriptor, Lambda>();

            intOperators.Add(
                new OperatorDescriptor(UnaryOperator.BitwiseNegate),
                new InPlaceLambda(unaryOperatorsType, type,
                                  (object[] stack, int[] locs) => ~(int)stack[locs[0]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(UnaryOperator.Negative),
                new InPlaceLambda(unaryOperatorsType, type,
                                  (object[] stack, int[] locs) => - (int)stack[locs[0]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.Multiply),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] * (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.Divide),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] / (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.Modulus),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] % (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.Add),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] + (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.Subtract),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] - (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.LeftShift),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] << (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.RightShift),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] >> (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.LessThan),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] < (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.GreaterThan),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] > (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.LessThanOrEquals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] <= (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.GreaterThanOrEquals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] >= (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.Equals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] == (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.NotEquals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] != (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.BitwiseAnd),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] & (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.BitwiseXor),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] ^ (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.BitwiseOr),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] | (int)stack[locs[1]]
                                  )
                );

            primitiveOperators[typeof(int)] = intOperators;

            // string operators
            type = RedwoodType.GetForCSharpType(typeof(string));

            Dictionary <OperatorDescriptor, Lambda> stringOperators =
                new Dictionary <OperatorDescriptor, Lambda>();

            stringOperators.Add(
                new OperatorDescriptor(BinaryOperator.Add),
                new LambdaGroup(new InPlaceLambda[]
            {
                new InPlaceLambda(
                    new RedwoodType[] { type, type },
                    type,
                    (object[] stack, int[] locs) => (string)stack[locs[0]] + (string)stack[locs[1]]),
                new InPlaceLambda(
                    new RedwoodType[] { type, RedwoodType.GetForCSharpType(typeof(int)) },
                    type,
                    (object[] stack, int[] locs) => (string)stack[locs[0]] + (int)stack[locs[1]]),
                new InPlaceLambda(
                    new RedwoodType[] { type, RedwoodType.GetForCSharpType(typeof(double)) },
                    type,
                    (object[] stack, int[] locs) => (string)stack[locs[0]] + (double)stack[locs[1]]),
                new InPlaceLambda(
                    new RedwoodType[] { type, RedwoodType.GetForCSharpType(typeof(bool)) },
                    type,
                    (object[] stack, int[] locs) => (string)stack[locs[0]] + (bool)stack[locs[1]])
            })
                );

            primitiveOperators[typeof(string)] = stringOperators;

            type = RedwoodType.GetForCSharpType(typeof(double));
            unaryOperatorsType  = new RedwoodType[] { type };
            binaryOperatorsType = new RedwoodType[] { type, type };

            Dictionary <OperatorDescriptor, Lambda> doubleOperators =
                new Dictionary <OperatorDescriptor, Lambda>();

            doubleOperators.Add(
                new OperatorDescriptor(UnaryOperator.Negative),
                new InPlaceLambda(unaryOperatorsType, type,
                                  (object[] stack, int[] locs) => - (double)stack[locs[0]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.Multiply),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] * (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.Divide),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] / (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.Modulus),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] % (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.Add),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] + (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.Subtract),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] - (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.LessThan),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] < (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.GreaterThan),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] > (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.LessThanOrEquals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] <= (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.GreaterThanOrEquals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] >= (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.Equals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] == (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.NotEquals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] != (double)stack[locs[1]]
                                  )
                );

            primitiveOperators[typeof(double)] = doubleOperators;

            Dictionary <OperatorDescriptor, Lambda> boolOperators =
                new Dictionary <OperatorDescriptor, Lambda>();

            binaryOperatorsType = new RedwoodType[] { boolType, boolType };

            boolOperators.Add(
                new OperatorDescriptor(BinaryOperator.Equals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (bool)stack[locs[0]] == (bool)stack[locs[1]]
                                  )
                );

            boolOperators.Add(
                new OperatorDescriptor(BinaryOperator.NotEquals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (bool)stack[locs[0]] != (bool)stack[locs[1]]
                                  )
                );

            primitiveOperators[typeof(bool)] = boolOperators;
        }