예제 #1
0
        private void WriteFunctionInvoker(TypeDefinition type, ManagedUnrealTypeInfo typeInfo, ManagedUnrealFunctionInfo functionInfo,
                                          MethodDefinition method, InjectedMembers injectedMembers, bool explicitCall)
        {
            string invokerName = functionInfo.Name + codeSettings.VarNames.FunctionInvoker;

            List <MethodDefinition> invokerDefinitions = new List <MethodDefinition>();

            foreach (MethodDefinition methodDef in type.Methods)
            {
                if (methodDef.Name == invokerName)
                {
                    invokerDefinitions.Add(methodDef);
                }
            }
            VerifyNoResults(invokerDefinitions, type, "function invoker " + invokerName);

            MethodReference gchelperFindMethod = MakeGenericMethod(gchelperFindMethodGeneric, type);

            MethodAttributes invokerAttributes = MethodAttributes.Private | MethodAttributes.Static;
            MethodDefinition invoker           = new MethodDefinition(invokerName, invokerAttributes, assembly.MainModule.ImportEx(typeof(void)));

            invoker.Parameters.Add(new ParameterDefinition("buffer", ParameterAttributes.None, intPtrTypeRef));
            invoker.Parameters.Add(new ParameterDefinition("obj", ParameterAttributes.None, intPtrTypeRef));
            AddFunctionInvokerAttribute(invoker, functionInfo);
            type.Methods.Add(invoker);

            ILProcessor processor = invoker.Body.GetILProcessor();

            VariableDefinition objVar = null;

            if (!functionInfo.IsStatic)
            {
                objVar = new VariableDefinition(type);
                processor.Body.Variables.Add(objVar);
                processor.Emit(OpCodes.Ldarg_1);
                processor.Emit(OpCodes.Call, gchelperFindMethod);
                processor.Emit(OpCodes.Stloc, objVar);
            }

            Instruction loadBuffer = processor.Create(OpCodes.Ldarg_0);

            // Parameters including the return prop
            List <ManagedUnrealPropertyInfo> parameters = new List <ManagedUnrealPropertyInfo>();

            if (functionInfo.ReturnProp != null)
            {
                parameters.Add(functionInfo.ReturnProp);
            }
            parameters.AddRange(functionInfo.Params);

            VariableDefinition[] marshalerVariables = new VariableDefinition[parameters.Count];
            VariableDefinition[] paramVariables     = new VariableDefinition[parameters.Count];
            for (int i = 0; i < parameters.Count; i++)
            {
                ManagedUnrealPropertyInfo paramInfo = parameters[i];
                Type paramType = ManagedUnrealTypeInfo.GetTypeFromPropertyInfo(paramInfo);

                VariableDefinition paramVar = paramVariables[i] = new VariableDefinition(assembly.MainModule.ImportEx(paramType));
                processor.Body.Variables.Add(paramVar);

                VariableDefinition marshalerVar = EmitCreateMarshaler(processor, loadBuffer,
                                                                      injectedMembers.GetFunctionParamOffset(functionInfo, paramInfo),
                                                                      injectedMembers.GetFunctionParamPropertyAddress(functionInfo, paramInfo), paramInfo);
                if (marshalerVar != null)
                {
                    invoker.Body.Variables.Add(marshalerVar);
                    marshalerVariables[i] = marshalerVar;
                }

                // Load the parameter from the native buffer (skip return prop and out params)
                if (paramInfo != functionInfo.ReturnProp && (!paramInfo.IsOut || paramInfo.IsCollection))
                {
                    FieldDefinition offsetField         = injectedMembers.GetFunctionParamOffset(functionInfo, paramInfo);
                    FieldDefinition nativePropertyField = injectedMembers.GetFunctionParamPropertyAddress(functionInfo, paramInfo);

                    EmitLoad(processor, loadBuffer, offsetField, nativePropertyField, typeInfo, paramInfo, marshalerVar, paramVar);
                }
            }

            if (!functionInfo.IsStatic)
            {
                processor.Emit(OpCodes.Ldloc, objVar);
            }

            for (int i = 0; i < parameters.Count; i++)
            {
                ManagedUnrealPropertyInfo paramInfo = parameters[i];
                VariableDefinition        paramVar  = paramVariables[i];

                if (paramInfo != functionInfo.ReturnProp)
                {
                    OpCode loadCode = paramInfo.IsByRef || paramInfo.IsOut ? OpCodes.Ldloca : OpCodes.Ldloc;
                    processor.Emit(loadCode, paramVar);
                }
            }

            if (functionInfo.IsStatic || explicitCall)
            {
                processor.Emit(OpCodes.Call, assembly.MainModule.ImportEx(method));
            }
            else
            {
                processor.Emit(OpCodes.Callvirt, assembly.MainModule.ImportEx(method));
            }

            // Store the result (if any) in the result value local
            if (parameters.Count > 0 && functionInfo.ReturnProp != null)
            {
                // This assumes assumes ReturnProp is always the first index in the parameters collection
                Debug.Assert(functionInfo.ReturnProp == parameters[0]);
                processor.Emit(OpCodes.Stloc, paramVariables[0]);
            }

            // Marshal out params back to the native parameter buffer.
            for (int i = 0; i < parameters.Count; i++)
            {
                ManagedUnrealPropertyInfo paramInfo           = parameters[i];
                VariableDefinition        paramVar            = paramVariables[i];
                VariableDefinition        marshalerVar        = marshalerVariables[i];
                FieldDefinition           offsetField         = injectedMembers.GetFunctionParamOffset(functionInfo, paramInfo);
                FieldDefinition           nativePropertyField = injectedMembers.GetFunctionParamPropertyAddress(functionInfo, paramInfo);

                Instruction[]   loadBufferInstructions = GetLoadNativeBufferInstructions(typeInfo, processor, loadBuffer, offsetField);
                MethodReference marshaler = GetToNativeMarshaler(ManagedUnrealMarshalerType.Copy, paramInfo);

                if (paramInfo.IsByRef || paramInfo.IsOut || functionInfo.ReturnProp == paramInfo)
                {
                    if (marshalerVar != null)
                    {
                        // Instanced marshaler which is stored in a local var (e.g. TArrayCopyMarshaler<>)
                        EmitStore(processor, loadBuffer, offsetField, nativePropertyField, typeInfo, paramInfo, marshalerVar, paramVar);
                    }
                    else
                    {
                        Instruction loadLocal = processor.Create(OpCodes.Ldloc, paramVar);
                        WriteMarshalToNative(processor, nativePropertyField, loadBufferInstructions, null, loadLocal, marshaler);
                    }
                }
            }

            processor.Emit(OpCodes.Ret);

            FinalizeMethod(invoker);
        }
예제 #2
0
        private void WriteNativeFunctionInvokerBody(TypeDefinition type, ManagedUnrealTypeInfo typeInfo, ManagedUnrealFunctionInfo functionInfo,
                                                    MethodDefinition method, InjectedMembers injectedMembers, Dictionary <ManagedUnrealPropertyInfo, ParameterDefinition> parameters,
                                                    ILProcessor processor, bool isDelegate, bool perInstanceFunctionAddress)
        {
            FieldDefinition functionAddressField = injectedMembers.GetFunctionAddress(functionInfo);
            FieldDefinition paramsSizeField      = injectedMembers.GetFunctionParamsSize(functionInfo);

            if (perInstanceFunctionAddress && injectedMembers.GetFunctionAddressPerInstance(functionInfo) == null)
            {
                functionAddressField = AddNativeFunctionField(type, functionInfo, false);
                injectedMembers.SetFunctionAddressPerInstance(functionInfo, functionAddressField);
            }

            VariableDefinition bufferAllocation = new VariableDefinition(bytePtrTypeRef);

            method.Body.Variables.Add(bufferAllocation);

            VariableDefinition paramsBuffer = new VariableDefinition(intPtrTypeRef);

            method.Body.Variables.Add(paramsBuffer);

            Instruction loadBuffer = processor.Create(OpCodes.Ldloc, paramsBuffer);
            Instruction loadOwner  = processor.Create(OpCodes.Ldnull);

            // byte* ParamsBufferAllocation = stackalloc byte[XXXX_ParamsSize];
            // IntPtr ParamsBuffer = new IntPtr(ParamsBufferAllocation);
            processor.Emit(OpCodes.Ldsfld, paramsSizeField);
            processor.Emit(OpCodes.Conv_U);
            processor.Emit(OpCodes.Localloc);
            processor.Emit(OpCodes.Stloc, bufferAllocation);
            processor.Emit(OpCodes.Ldloca, paramsBuffer);
            processor.Emit(OpCodes.Ldloc, bufferAllocation);
            processor.Emit(OpCodes.Call, intPtrConstructorMethod);

            if (codeSettings.LazyFunctionParamInitDestroy)
            {
                // NativeReflection.InvokeFunction_InitAll(XXXX_FunctionAddress, ParamsBuffer);
                if (functionAddressField.IsStatic)
                {
                    processor.Emit(OpCodes.Ldsfld, functionAddressField);
                }
                else
                {
                    processor.Emit(OpCodes.Ldarg_0);
                    processor.Emit(OpCodes.Ldfld, functionAddressField);
                }
                processor.Emit(OpCodes.Ldloc, paramsBuffer);
                processor.Emit(OpCodes.Call, reflectionInitAllMethod);
            }
            else if (codeSettings.MemzeroStackalloc || codeSettings.MemzeroStackallocOnlyIfOut)
            {
                bool requiresMemzero = codeSettings.MemzeroStackalloc;

                if (codeSettings.MemzeroStackallocOnlyIfOut)
                {
                    // Memzero only if there is a return value or a (non ref) out param which doesn't have a zero constructor.
                    // (if the param can't be zero initialized it will be initialized with a call to InitializeValue anyway)
                    foreach (KeyValuePair <ManagedUnrealPropertyInfo, ParameterDefinition> param in parameters)
                    {
                        ManagedUnrealPropertyInfo paramInfo = param.Key;

                        if (paramInfo.IsOut && !ManagedUnrealTypeInfo.PropertyRequiresInit(paramInfo))
                        {
                            requiresMemzero = true;
                            break;
                        }
                    }
                    if (functionInfo.ReturnProp != null && !ManagedUnrealTypeInfo.PropertyRequiresInit(functionInfo.ReturnProp))
                    {
                        requiresMemzero = true;
                    }
                }

                if (requiresMemzero)
                {
                    // FMemory.Memzero(ParamsBuffer, XXXX_ParamsSize
                    processor.Emit(OpCodes.Ldloc, paramsBuffer);
                    processor.Emit(OpCodes.Ldsfld, paramsSizeField);
                    processor.Emit(OpCodes.Call, fmemoryMemzero);
                    processor.Emit(OpCodes.Pop);// Memzero returns a value, pop it off the stack
                }
            }

            Instruction loadParamBufferInstruction = processor.Create(OpCodes.Ldloc, paramsBuffer);

            Dictionary <ManagedUnrealPropertyInfo, FieldDefinition>    paramOffsets       = new Dictionary <ManagedUnrealPropertyInfo, FieldDefinition>();
            Dictionary <ManagedUnrealPropertyInfo, VariableDefinition> paramMarshalerVars = new Dictionary <ManagedUnrealPropertyInfo, VariableDefinition>();

            foreach (KeyValuePair <ManagedUnrealPropertyInfo, ParameterDefinition> param in parameters)
            {
                ManagedUnrealPropertyInfo paramInfo = param.Key;

                FieldDefinition offsetField         = injectedMembers.GetFunctionParamOffset(functionInfo, paramInfo);
                FieldDefinition nativePropertyField = injectedMembers.GetFunctionParamPropertyAddress(functionInfo, paramInfo);

                VariableDefinition marshalerVar = EmitCreateMarshaler(processor, loadBuffer, offsetField, nativePropertyField, paramInfo);
                if (marshalerVar != null)
                {
                    method.Body.Variables.Add(marshalerVar);
                    paramMarshalerVars[paramInfo] = marshalerVar;
                }

                // Init the param memory if required
                EmitFunctionParamInit(processor, functionInfo, paramInfo, paramsBuffer, nativePropertyField);

                // Write the parameter to the native buffer if it isn't an "out" parameter
                // XXXXMarshaler.ToNative(IntPtr.Add(ParamsBuffer, XXXX_YYYY_Offset), YYYY);
                if (!paramInfo.IsOut)
                {
                    EmitStore(processor, loadParamBufferInstruction, offsetField, nativePropertyField, typeInfo, param.Key, marshalerVar, param.Value);
                }
            }

            if (functionInfo.ReturnProp != null)
            {
                // Init the return value memory if required
                EmitFunctionParamInit(processor, functionInfo, functionInfo.ReturnProp, paramsBuffer,
                                      injectedMembers.GetFunctionParamPropertyAddress(functionInfo, functionInfo.ReturnProp));
            }

            if (isDelegate)
            {
                // ProcessDelegate(ParamsBuffer);
                MethodReference processDelegateMethod = assembly.MainModule.ImportEx(GetTypeFromTypeDefinition(type).GetMethod("ProcessDelegate"));
                processor.Emit(OpCodes.Ldarg_0);
                processor.Emit(OpCodes.Ldloc, paramsBuffer);
                processor.Emit(OpCodes.Callvirt, processDelegateMethod);
            }
            else
            {
                // NativeReflection.InvokeFunction(Address, XXXX_FunctionAddress, ParamsBuffer, XXXX_ParamsSize);
                processor.Emit(OpCodes.Ldarg_0);
                processor.Emit(OpCodes.Call, typeInfo.IsInterface ? iinterfaceImplAddressGetter : uobjectAddressGetter);
                if (functionAddressField.IsStatic)
                {
                    processor.Emit(OpCodes.Ldsfld, functionAddressField);
                }
                else
                {
                    processor.Emit(OpCodes.Ldarg_0);
                    processor.Emit(OpCodes.Ldfld, functionAddressField);
                }
                processor.Emit(OpCodes.Ldloc, paramsBuffer);
                processor.Emit(OpCodes.Ldsfld, paramsSizeField);
                processor.Emit(OpCodes.Call, reflectionInvokeFunctionMethod);
            }

            VariableDefinition returnVar = null;

            if (functionInfo.ReturnProp != null)
            {
                returnVar = new VariableDefinition(assembly.MainModule.ImportEx(ManagedUnrealTypeInfo.GetTypeFromPropertyInfo(functionInfo.ReturnProp)));
                method.Body.Variables.Add(returnVar);

                VariableDefinition returnVarMarshaler = EmitCreateMarshaler(processor, loadBuffer,
                                                                            injectedMembers.GetFunctionParamOffset(functionInfo, functionInfo.ReturnProp),
                                                                            injectedMembers.GetFunctionParamPropertyAddress(functionInfo, functionInfo.ReturnProp), functionInfo.ReturnProp);
                if (returnVarMarshaler != null)
                {
                    method.Body.Variables.Add(returnVarMarshaler);
                }

                FieldDefinition offsetField         = injectedMembers.GetFunctionParamOffset(functionInfo, functionInfo.ReturnProp);
                FieldDefinition nativePropertyField = injectedMembers.GetFunctionParamPropertyAddress(functionInfo, functionInfo.ReturnProp);

                EmitLoad(processor, loadBuffer, offsetField, nativePropertyField, typeInfo, functionInfo.ReturnProp, returnVarMarshaler, returnVar);

                // Destroy the return value memory if required
                EmitFunctionParamDestroy(processor, functionInfo, functionInfo.ReturnProp, paramsBuffer,
                                         injectedMembers.GetFunctionParamPropertyAddress(functionInfo, functionInfo.ReturnProp));
            }

            foreach (KeyValuePair <ManagedUnrealPropertyInfo, ParameterDefinition> param in parameters)
            {
                ManagedUnrealPropertyInfo paramInfo = param.Key;

                if (paramInfo.IsByRef || paramInfo.IsOut || paramInfo.IsCollection)
                {
                    FieldDefinition    offsetField         = injectedMembers.GetFunctionParamOffset(functionInfo, paramInfo);
                    FieldDefinition    nativePropertyField = injectedMembers.GetFunctionParamPropertyAddress(functionInfo, paramInfo);
                    VariableDefinition marshalerVar;
                    paramMarshalerVars.TryGetValue(paramInfo, out marshalerVar);

                    EmitLoad(processor, loadBuffer, offsetField, nativePropertyField, typeInfo, paramInfo, marshalerVar, param.Value);
                }

                // Destroy the param memory if required
                EmitFunctionParamDestroy(processor, functionInfo, paramInfo, paramsBuffer,
                                         injectedMembers.GetFunctionParamPropertyAddress(functionInfo, paramInfo));
            }

            if (codeSettings.LazyFunctionParamInitDestroy)
            {
                // NativeReflection.InvokeFunction_DestroyAll(XXXX_FunctionAddress, ParamsBuffer);
                if (functionAddressField.IsStatic)
                {
                    processor.Emit(OpCodes.Ldsfld, functionAddressField);
                }
                else
                {
                    processor.Emit(OpCodes.Ldarg_0);
                    processor.Emit(OpCodes.Ldfld, functionAddressField);
                }
                processor.Emit(OpCodes.Ldloc, paramsBuffer);
                processor.Emit(OpCodes.Call, reflectionDestroyAllMethod);
            }

            if (returnVar != null)
            {
                processor.Emit(OpCodes.Ldloc, returnVar);
            }
            processor.Emit(OpCodes.Ret);

            if (!functionAddressField.IsStatic)
            {
                // if (XXXX_FunctionAddress == IntPtr.Zero) { XXXX_FunctionAddress = NativeReflection.GetFunctionFromInstance(Address, "XXXX"); }
                Instruction branchTarget = processor.Body.Instructions[0];
                processor.InsertBefore(branchTarget, processor.Create(OpCodes.Ldarg_0));
                processor.InsertBefore(branchTarget, processor.Create(OpCodes.Ldfld, functionAddressField));
                processor.InsertBefore(branchTarget, processor.Create(OpCodes.Ldsfld, intPtrZeroFieldRef));
                processor.InsertBefore(branchTarget, processor.Create(OpCodes.Call, intPtrEqualsMethod));
                Instruction branchPosition = processor.Create(OpCodes.Ldarg_0);
                processor.InsertBefore(branchTarget, branchPosition);
                processor.InsertBefore(branchTarget, processor.Create(OpCodes.Ldarg_0));
                processor.InsertBefore(branchTarget, processor.Create(OpCodes.Call, typeInfo.IsInterface ? iinterfaceImplAddressGetter : uobjectAddressGetter));
                processor.InsertBefore(branchTarget, processor.Create(OpCodes.Ldstr, method.Name));
                processor.InsertBefore(branchTarget, processor.Create(OpCodes.Call, reflectionGetFunctionFromInstance));
                processor.InsertBefore(branchTarget, processor.Create(OpCodes.Stfld, functionAddressField));
                processor.InsertBefore(branchPosition, processor.Create(OpCodes.Brfalse_S, branchTarget));
            }

            InsertNativeFunctionInvokerIsValidSafeguard(type, functionInfo, method, injectedMembers, processor);

            // Add an object destroyed check if this isn't a delegate
            if (!isDelegate)
            {
                InsertObjectDestroyedCheck(typeInfo, processor);
            }
        }
예제 #3
0
        private void WriteGetterFixedSizeArray(TypeDefinition type, ManagedUnrealTypeInfo typeInfo, ManagedUnrealPropertyInfo propertyInfo,
                                               MethodDefinition getter, FieldDefinition isValidField, FieldDefinition offsetField, FieldDefinition nativePropertyField,
                                               FieldDefinition fixedSizeArrayField)
        {
            ILProcessor processor = BeginGetter(getter);

            processor.Emit(OpCodes.Ldarg_0);
            processor.Emit(OpCodes.Ldfld, fixedSizeArrayField);

            // Save the position of the branch instruction for later, when we have a reference to its target.
            // (will insert Brtrue_S before this instruction as a null check on the wrapper field)
            processor.Emit(OpCodes.Ldarg_0);
            Instruction branchPosition = processor.Body.Instructions[processor.Body.Instructions.Count - 1];

            MethodReference constructor = null;

            foreach (MethodDefinition ctor in fixedSizeArrayField.FieldType.Resolve().GetConstructors())
            {
                if (ctor.Parameters.Count == 3)
                {
                    constructor = ctor;
                    break;
                }
            }
            VerifyNonNull(constructor, type, "constructor for " + fixedSizeArrayField.FieldType.FullName);
            constructor = GetConstrainedGenericTypeCtor(fixedSizeArrayField.FieldType, constructor);

            // new TFixedSizeArray<XXXX>(IntPtr.Add(Address, XXXX_Offset), XXXX_PropertyAddress, this);
            // IntPtr.Add(this.Address, XXXX_Offset)
            processor.Emit(OpCodes.Ldarg_0);
            processor.Emit(OpCodes.Call, uobjectAddressGetter);
            processor.Emit(OpCodes.Ldsfld, offsetField);
            processor.Emit(OpCodes.Call, intPtrAddMethod);
            // XXXX_PropertyAddress
            processor.Emit(OpCodes.Ldsfld, nativePropertyField);
            // this
            processor.Emit(OpCodes.Ldarg_0);

            // Create an instance of the array and store in the member field
            processor.Emit(OpCodes.Newobj, constructor);
            processor.Emit(OpCodes.Stfld, fixedSizeArrayField);

            // return XXXX;
            processor.Emit(OpCodes.Ldarg_0);
            Instruction branchTarget = processor.Body.Instructions[processor.Body.Instructions.Count - 1];

            processor.Emit(OpCodes.Ldfld, fixedSizeArrayField);

            // Insert the branch (before the return statement)
            Instruction branchInstruction = processor.Create(OpCodes.Brtrue_S, branchTarget);

            processor.InsertBefore(branchPosition, branchInstruction);

            EndGetter(typeInfo, propertyInfo, getter, isValidField, processor);
        }