Ejemplo n.º 1
0
 public Instruction(InstructionActions action, double value)
 {
     Action = action;
     Value  = value;
 }
Ejemplo n.º 2
0
        private MethodBody GenerateDelegateMethod(MethodDefinition method, Class declaringClass)
        {
            // Delegate type
            var delegateType = corlib.MainModule.GetType(typeof(Delegate).FullName);

            // Delegate fields
            var targetField       = delegateType.Fields.First(x => x.Name == "_target");
            var methodPtrField    = delegateType.Fields.First(x => x.Name == "_methodPtr");
            var methodPtrAuxField = delegateType.Fields.First(x => x.Name == "_methodPtrAux");

            var body = new MethodBody(method);
            var il   = body.GetILProcessor();

            if (method.Name == ".ctor")
            {
                // Mark
                //GenerateMulticastInvokeThunk(declaringClass);

                // Two main cases:
                // - Instance method:
                //    this._methodPtr = fnptr;
                //    this._target = target;
                //    Result: this._methodPtr(this._target, arg1, ..) will directly work
                // - Static method:
                //    this._target = this;
                //    this._methodPtrAux = fnptr;
                //    this._methodPtr = (delegate, arg1, ...) => { delegate->_methodPtrAux(arg1, ...); }
                //    Result: this._methodPtr(this._target, arg1, ...) will call thunk,
                //            which will call fnptr (from this._target._methodPtr) without the first argument
                var target = Instruction.Create(OpCodes.Ldarg_0);

                // if (target == null)
                // {
                il.Append(Instruction.Create(OpCodes.Ldarg, method.Parameters[0]));
                il.Append(Instruction.Create(OpCodes.Brtrue, target));

                //     Generate thunk (for now, done using direct LLVM, not sure weither LLVM or IL is better)
                //      this._methodPtr = (delegate, arg1, ...) => { delegate->_methodPtrAux(arg1, ...); }
                var invokeMethodHelper = GenerateStaticInvokeThunk(declaringClass);

                //      Fake Nop to push this thunk on stack (TODO: Better way to do this? i.e. store it in some static field?)
                il.Append(Instruction.Create(OpCodes.Ldarg_0));
                var loadFunctionPointerInstruction = Instruction.Create(OpCodes.Nop);
                InstructionActions.Add(loadFunctionPointerInstruction, (stack) =>
                {
                    // Push the generated method pointer on the stack
                    stack.Add(new StackValue(StackValueType.NativeInt, intPtr,
                                             LLVM.BuildPointerCast(builder, invokeMethodHelper, intPtrLLVM, string.Empty)));
                });
                il.Append(loadFunctionPointerInstruction);
                il.Append(Instruction.Create(OpCodes.Stfld, methodPtrField));

                //     this._methodPtrAux = method;
                il.Append(Instruction.Create(OpCodes.Ldarg_0));
                il.Append(Instruction.Create(OpCodes.Ldarg, method.Parameters[1]));
                il.Append(Instruction.Create(OpCodes.Stfld, methodPtrAuxField));

                //     this._target = this;
                il.Append(Instruction.Create(OpCodes.Ldarg_0));
                il.Append(Instruction.Create(OpCodes.Ldarg_0));
                il.Append(Instruction.Create(OpCodes.Stfld, targetField));

                //     return;
                // }
                il.Append(Instruction.Create(OpCodes.Ret));


                // this._target = target;
                il.Append(target);
                il.Append(Instruction.Create(OpCodes.Ldarg, method.Parameters[0]));
                il.Append(Instruction.Create(OpCodes.Stfld, targetField));

                // this._methodPtr = method;
                il.Append(Instruction.Create(OpCodes.Ldarg_0));
                il.Append(Instruction.Create(OpCodes.Ldarg, method.Parameters[1]));
                il.Append(Instruction.Create(OpCodes.Stfld, methodPtrField));

                // return;
                il.Append(Instruction.Create(OpCodes.Ret));
            }
            else if (method.Name == "GetMulticastDispatchMethod")
            {
                var invokeMethodHelper = GenerateMulticastInvokeThunk(declaringClass);

                var loadFunctionPointerInstruction = Instruction.Create(OpCodes.Nop);
                InstructionActions.Add(loadFunctionPointerInstruction, (stack) =>
                {
                    // Push the generated method pointer on the stack
                    stack.Add(new StackValue(StackValueType.NativeInt, intPtr,
                                             LLVM.BuildPointerCast(builder, invokeMethodHelper, intPtrLLVM, string.Empty)));
                });
                il.Append(loadFunctionPointerInstruction);

                il.Append(Instruction.Create(OpCodes.Ret));
            }
            else if (method.Name == "Invoke")
            {
                // For now, generate IL
                // Note that we could probably optimize at callsite too,
                // but probably not necessary if LLVM and sealed class are optimized/inlined well enough

                // ldarg_0
                // ldfld _target
                il.Append(Instruction.Create(OpCodes.Ldarg_0));
                il.Append(Instruction.Create(OpCodes.Ldfld, targetField));

                var callsite = new CallSite(method.ReturnType);
                callsite.Parameters.Add(new ParameterDefinition(targetField.FieldType));

                foreach (var parameter in method.Parameters)
                {
                    callsite.Parameters.Add(new ParameterDefinition(parameter.Name, parameter.Attributes, parameter.ParameterType));

                    // ldarg
                    il.Append(Instruction.Create(OpCodes.Ldarg, parameter));
                }

                // ldarg_0
                // ldfld _methodPtr
                il.Append(Instruction.Create(OpCodes.Ldarg_0));
                il.Append(Instruction.Create(OpCodes.Ldfld, methodPtrField));

                // calli
                il.Append(Instruction.Create(OpCodes.Calli, callsite));

                // ret
                il.Append(Instruction.Create(OpCodes.Ret));
            }
            else
            {
                LLVM.BuildUnreachable(builder);
                return(null);
            }
            return(body);
        }