Exemplo n.º 1
0
        public CompilationContext(
            TypeBuilder exportsBuilder,
            FieldBuilder memory,
            Signature[] functionSignatures,
            MethodInfo[] methods,
            Signature[] types,
            Compile.Indirect[] functionElements,
            ModuleBuilder module,
            Compile.GlobalInfo[] globalGetters,
            Compile.GlobalInfo[] globalSetters
            )
        {
            Assert(exportsBuilder != null);
            Assert(functionSignatures != null);
            Assert(methods != null);
            Assert(types != null);
            Assert(module != null);

            this.ExportsBuilder     = exportsBuilder;
            this.Memory             = memory;
            this.FunctionSignatures = functionSignatures;
            this.Methods            = methods;
            this.Types         = types;
            this.GlobalGetters = globalGetters;
            this.GlobalSetters = globalSetters;

            if (functionElements == null)
            {
                return;
            }

            //Capture the information about indirectly-callable functions.
            var indirectBuilder = module.DefineType("☣ Indirect",
                                                    TypeAttributes.Public | //Change to something more appropriate once behavior is validated.
                                                    TypeAttributes.Sealed | TypeAttributes.SequentialLayout | TypeAttributes.BeforeFieldInit,
                                                    typeof(System.ValueType)
                                                    );

            var indirectTypeFieldBuilder = indirectBuilder.DefineField(
                "☣ Type",
                typeof(uint),
                FieldAttributes.Public | FieldAttributes.InitOnly);

            var indirectMethodFieldBuilder = indirectBuilder.DefineField(
                "☣ Method",
                typeof(IntPtr),
                FieldAttributes.Public | FieldAttributes.InitOnly);

            var indirectConstructorBuilder = indirectBuilder.DefineConstructor(
                MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
                CallingConventions.HasThis,
                new[]
            {
                typeof(uint),
                typeof(IntPtr),
            }
                );

            var il = indirectConstructorBuilder.GetILGenerator();

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Stfld, indirectTypeFieldBuilder);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldarg_2);
            il.Emit(OpCodes.Stfld, indirectMethodFieldBuilder);

            il.Emit(OpCodes.Ret);

            var indirectLocationsFieldBuilder = indirectBuilder.DefineField(
                "☣ Locations",
                typeof(IntPtr),
                FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.InitOnly);

            this.generator = il = indirectBuilder.DefineTypeInitializer().GetILGenerator();

            Instructions.Int32Constant.Emit(this, functionElements.Length);
            il.Emit(OpCodes.Newarr, indirectBuilder.AsType());

            for (var i = 0; i < functionElements.Length; i++)
            {
                var fe = functionElements[i];
                il.Emit(OpCodes.Dup);
                Instructions.Int32Constant.Emit(this, i);
                Instructions.Int32Constant.Emit(this, checked ((int)fe.type));
                il.Emit(OpCodes.Ldftn, fe.function);
                il.Emit(OpCodes.Newobj, indirectConstructorBuilder);
                il.Emit(OpCodes.Stelem, indirectBuilder.AsType());
            }

            il.Emit(OpCodes.Stsfld, indirectLocationsFieldBuilder);
            il.Emit(OpCodes.Ret);

            var indirectGetFunctionPointer = indirectBuilder.DefineMethod(
                "☣ Get Function Pointer",
                MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static,
                CallingConventions.Standard,
                typeof(IntPtr),
                new[]
            {
                typeof(uint),
                typeof(uint),
            }
                );

            il = indirectGetFunctionPointer.GetILGenerator();
            var value           = il.DeclareLocal(indirectBuilder.AsType());
            var indexOutOfRange = il.DeclareLocal(typeof(IndexOutOfRangeException));
            var endTry          = il.BeginExceptionBlock();

            il.Emit(OpCodes.Ldsfld, indirectLocationsFieldBuilder);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldelem, indirectBuilder.AsType());
            il.Emit(OpCodes.Stloc_0);
            il.Emit(OpCodes.Leave_S, endTry);

            il.BeginCatchBlock(typeof(IndexOutOfRangeException));
            il.Emit(OpCodes.Stloc_1);
            il.Emit(OpCodes.Ldstr, "index");
            il.Emit(OpCodes.Ldloc_1);
            il.Emit(OpCodes.Newobj, typeof(IndexOutOfRangeException).GetTypeInfo().DeclaredConstructors.First(c =>
            {
                var parms = c.GetParameters();
                return
                (parms.Length == 2 &&
                 parms[0].ParameterType == typeof(string) &&
                 parms[1].ParameterType == typeof(Exception)
                );
            }));
            il.Emit(OpCodes.Throw);
            il.EndExceptionBlock();

            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Ldfld, indirectTypeFieldBuilder);
            var match = il.DefineLabel();

            il.Emit(OpCodes.Beq_S, match);

            il.Emit(OpCodes.Ldstr, "Type mismatch");
            il.Emit(OpCodes.Ldstr, "type");
            il.Emit(OpCodes.Newobj, typeof(ArgumentException).GetTypeInfo().DeclaredConstructors.First(c =>
            {
                var parms = c.GetParameters();
                return
                (parms.Length == 2 &&
                 parms[0].ParameterType == typeof(string) &&
                 parms[1].ParameterType == typeof(string)
                );
            }));
            il.Emit(OpCodes.Throw);

            il.MarkLabel(match);
            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Ldfld, indirectMethodFieldBuilder);
            il.Emit(OpCodes.Ret);

            this.helperMethods.Add(HelperMethod.GetFunctionPointer, indirectGetFunctionPointer);
            indirectBuilder.CreateTypeInfo();
            this.generator = null;
        }