private Instruction[] CreateFunctionOutDefaults(ILProcessor processor, ManagedUnrealFunctionInfo functionInfo, MethodDefinition method)
        {
            List <Instruction> instructions = new List <Instruction>();

            // Set out params to the equivalent of default(XXXX)
            for (int i = 0; i < functionInfo.Params.Count; ++i)
            {
                ManagedUnrealPropertyInfo param = functionInfo.Params[i];

                if (param.IsOut)
                {
                    instructions.AddRange(CreateSetDefaultValue(processor, param.Type.TypeCode, method.Parameters[i]));
                }
            }

            // Add a return var and set it to the equivalent of default(XXXX)
            if (functionInfo.ReturnProp != null)
            {
                TypeReference      returnType = assembly.MainModule.ImportEx(ManagedUnrealTypeInfo.GetTypeFromPropertyInfo(functionInfo.ReturnProp));
                VariableDefinition returnVar  = new VariableDefinition(returnType);
                method.Body.Variables.Add(returnVar);

                instructions.AddRange(CreateSetDefaultValue(processor, functionInfo.ReturnProp.Type.TypeCode, returnVar));
                instructions.Add(processor.Create(OpCodes.Ldloc, returnVar));
            }

            return(instructions.ToArray());
        }
예제 #2
0
        private Dictionary <ManagedUnrealPropertyInfo, ParameterDefinition> GetParamsFromMethod(TypeDefinition type,
                                                                                                ManagedUnrealFunctionInfo functionInfo, MethodDefinition method, InjectedMembers injectedMembers, bool addFields)
        {
            Dictionary <ManagedUnrealPropertyInfo, ParameterDefinition> parameters = new Dictionary <ManagedUnrealPropertyInfo, ParameterDefinition>();

            foreach (ManagedUnrealPropertyInfo param in functionInfo.Params)
            {
                Type paramType = ManagedUnrealTypeInfo.GetTypeFromPropertyInfo(param);

                List <ParameterDefinition> foundParams = new List <ParameterDefinition>();
                foreach (ParameterDefinition paramDef in method.Parameters)
                {
                    if (paramDef.Name == param.Name)
                    {
                        foundParams.Add(paramDef);
                        break;
                    }
                }
                VerifySingleResult(foundParams, type, "Param count mismatch " + param.Name + " in delegate");

                if (addFields)
                {
                    FieldDefinition isValidField        = AddIsValidField(type, functionInfo, param);
                    FieldDefinition offsetField         = AddOffsetField(type, functionInfo, param);
                    FieldDefinition nativePropertyField = AddNativePropertyField(type, functionInfo, param);
                    injectedMembers.SetFunctionParamIsValid(functionInfo, param, isValidField);
                    injectedMembers.SetFunctionParamOffset(functionInfo, param, offsetField);
                    injectedMembers.SetFunctionParamPropertyAddress(functionInfo, param, nativePropertyField);
                }

                parameters.Add(param, foundParams[0]);
            }

            if (addFields && functionInfo.ReturnProp != null)
            {
                FieldDefinition isValidField        = AddIsValidField(type, functionInfo, functionInfo.ReturnProp);
                FieldDefinition offsetField         = AddOffsetField(type, functionInfo, functionInfo.ReturnProp);
                FieldDefinition nativePropertyField = AddNativePropertyField(type, functionInfo, functionInfo.ReturnProp);
                injectedMembers.SetFunctionParamIsValid(functionInfo, functionInfo.ReturnProp, isValidField);
                injectedMembers.SetFunctionParamOffset(functionInfo, functionInfo.ReturnProp, offsetField);
                injectedMembers.SetFunctionParamPropertyAddress(functionInfo, functionInfo.ReturnProp, nativePropertyField);
            }

            return(parameters);
        }
예제 #3
0
        private void WriteGetterDelegate(ManagedUnrealTypeInfo typeInfo, ManagedUnrealPropertyInfo propertyInfo, MethodDefinition getter,
                                         FieldDefinition isValidField, FieldDefinition offsetField, FieldDefinition delegateWrapperField)
        {
            ILProcessor processor = BeginGetter(getter);

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

            // 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];

            Type delegateType = ManagedUnrealTypeInfo.GetTypeFromPropertyInfo(propertyInfo);

            // Find the default constructor / SetAddress method for the delegate
            System.Reflection.ConstructorInfo delegateCtor     = delegateType.GetConstructor(Type.EmptyTypes);
            System.Reflection.MethodInfo      setAddressMethod = delegateType.GetMethod("SetAddress");

            // Create an instance of the delegate and store in the member field
            processor.Emit(OpCodes.Newobj, assembly.MainModule.ImportEx(delegateCtor));
            processor.Emit(OpCodes.Stfld, delegateWrapperField);

            processor.Emit(OpCodes.Ldarg_0);
            processor.Emit(OpCodes.Ldfld, delegateWrapperField);
            processor.Emit(OpCodes.Ldarg_0);
            processor.Emit(OpCodes.Call, uobjectAddressGetter);
            processor.Emit(OpCodes.Ldsfld, offsetField);
            processor.Emit(OpCodes.Call, intPtrAddMethod);
            processor.Emit(OpCodes.Callvirt, assembly.MainModule.ImportEx(setAddressMethod));

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

            processor.Emit(OpCodes.Ldfld, delegateWrapperField);

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

            processor.InsertBefore(branchPosition, branchInstruction);

            EndGetter(typeInfo, propertyInfo, getter, isValidField, processor);
        }
예제 #4
0
        private void RewriteClass(TypeDefinition type, ManagedUnrealTypeInfo classInfo)
        {
            InjectedMembers injectedMembers = new InjectedMembers(classInfo);

            if (classInfo.IsStructAsClass)
            {
                FieldDefinition structAddressField = new FieldDefinition(classInfo.Name + codeSettings.VarNames.StructAddress,
                                                                         FieldAttributes.Public | FieldAttributes.Static, intPtrTypeRef);
                type.Fields.Add(structAddressField);
                injectedMembers.ClassAddress = structAddressField;

                FieldDefinition structIsValidField = new FieldDefinition(classInfo.Name + codeSettings.VarNames.IsValid,
                                                                         FieldAttributes.Private | FieldAttributes.Static, int32TypeRef);
                type.Fields.Add(structIsValidField);
                injectedMembers.StructIsValid = structIsValidField;

                OverrideStructAsClassGetStructAddress(type, structAddressField);
            }

            // Moving default set has to happen before stripping to keep resolvability
            RemoveFieldDefaultSetterFromConstructor(type, classInfo);

            foreach (ManagedUnrealPropertyInfo propertyInfo in classInfo.Properties)
            {
                PropertyDefinition propertyDefinition = FindPropertyByName(type, propertyInfo.Name);

                if (!propertyInfo.IsField && !propertyInfo.IsBackingFieldPreStripped)
                {
                    StripBackingField(type, propertyInfo);
                }

                // Add offset field
                FieldDefinition isValidField        = AddIsValidField(type, propertyInfo);
                FieldDefinition offsetField         = AddOffsetField(type, propertyInfo);
                FieldDefinition nativePropertyField = AddNativePropertyField(type, propertyInfo);

                injectedMembers.SetPropertyIsValid(propertyInfo, isValidField);
                injectedMembers.SetPropertyOffset(propertyInfo, offsetField);
                injectedMembers.SetPropertyAddress(propertyInfo, nativePropertyField);

                FieldDefinition fixedSizeArrayField = null;
                if (propertyInfo.IsFixedSizeArray)
                {
                    // Add a field to store the fixed size array for the getter...technically we already had one of these which was
                    // the backing field that was stripped. Maybe just not strip the backing field rather than adding a new field
                    // of what should already exist.
                    fixedSizeArrayField = new FieldDefinition(
                        propertyInfo.Name + codeSettings.VarNames.FixedSizeArrayCached, FieldAttributes.Private, propertyDefinition.PropertyType);
                    type.Fields.Add(fixedSizeArrayField);
                }

                FieldDefinition collectionWrapperField = null;
                if (propertyInfo.IsCollection)
                {
                    // Add a field to store the collection wrapper for the getter
                    collectionWrapperField = new FieldDefinition(
                        propertyInfo.Name + codeSettings.VarNames.CollectionMarshaler, FieldAttributes.Private,
                        assembly.MainModule.ImportEx(ManagedUnrealTypeInfo.GetCollectionType(propertyInfo, ManagedUnrealMarshalerType.Default)));
                    type.Fields.Add(collectionWrapperField);
                }

                FieldDefinition delegateWrapperField = null;
                if (propertyInfo.IsDelegate)
                {
                    // Add a field to store the delegate wrapper for the getter
                    delegateWrapperField = new FieldDefinition(
                        propertyInfo.Name + codeSettings.VarNames.DelegateCached, FieldAttributes.Private,
                        assembly.MainModule.ImportEx(ManagedUnrealTypeInfo.GetTypeFromPropertyInfo(propertyInfo)));
                    type.Fields.Add(delegateWrapperField);
                }

                FieldDefinition cachedFTextField = null;
                if (propertyInfo.Type.TypeCode == EPropertyType.Text)
                {
                    // Add a field to store the cached FText for the getter / setter
                    cachedFTextField = new FieldDefinition(
                        propertyInfo.Name + codeSettings.VarNames.FTextCached, FieldAttributes.Private, ftextTypeRef);
                    type.Fields.Add(cachedFTextField);
                }

                if (propertyDefinition.GetMethod != null)
                {
                    if (propertyInfo.IsFixedSizeArray)
                    {
                        WriteGetterFixedSizeArray(type, classInfo, propertyInfo, propertyDefinition.GetMethod, isValidField, offsetField,
                                                  nativePropertyField, fixedSizeArrayField);
                    }
                    else if (propertyInfo.IsCollection)
                    {
                        // NOTE: To support type downgrading we would need to update any references - this likely wouldn't work well
                        // Downgrade the collection from List to IList, Dictionarty to IDictionary, HashSet to ISet
                        //Type downgradedCollection = GetDowngradedCollectionType(propertyInfo, ManagedUnrealMarshalerType.Default);
                        //propertyDefinition.PropertyType = assembly.MainModule.ImportEx(downgradedCollection);

                        WriteGetterCollection(classInfo, propertyInfo, propertyDefinition.GetMethod, isValidField, offsetField,
                                              nativePropertyField, collectionWrapperField);
                    }
                    else if (propertyInfo.IsDelegate)
                    {
                        WriteGetterDelegate(classInfo, propertyInfo, propertyDefinition.GetMethod, isValidField, offsetField, delegateWrapperField);
                    }
                    else if (propertyInfo.Type.TypeCode == EPropertyType.Text)
                    {
                        WriteCachedFTextGetter(classInfo, propertyInfo, propertyDefinition.GetMethod, isValidField, offsetField, cachedFTextField);
                    }
                    else
                    {
                        WriteGetter(classInfo, propertyInfo, propertyDefinition.GetMethod, isValidField, offsetField, nativePropertyField);
                    }
                }
                if (propertyDefinition.SetMethod != null)
                {
                    if (propertyInfo.IsFixedSizeArray)
                    {
                        // Setter for fixed sized arrays isn't currently supported (use the indexer / SetValues method)
                        type.Methods.Remove(propertyDefinition.SetMethod);
                        propertyDefinition.SetMethod = null;
                    }
                    else if (propertyInfo.IsCollection)
                    {
                        // Setter for collections isn't currently supported. Use Clear/AddRange instead (this is what the
                        // setter would need to be recoded to if we ever add this support)
                        type.Methods.Remove(propertyDefinition.SetMethod);
                        propertyDefinition.SetMethod = null;
                    }
                    else if (propertyInfo.IsDelegate)
                    {
                        // Setter for delegates isn't currently supported.
                        type.Methods.Remove(propertyDefinition.SetMethod);
                        propertyDefinition.SetMethod = null;
                    }
                    else if (propertyInfo.Type.TypeCode == EPropertyType.Text)
                    {
                        WriteCachedFTextSetter(classInfo, propertyInfo, propertyDefinition.SetMethod, isValidField, offsetField, cachedFTextField);
                    }
                    else
                    {
                        WriteSetter(classInfo, propertyInfo, propertyDefinition.SetMethod, isValidField, offsetField, nativePropertyField);
                    }
                }

                AddPathAttribute(propertyDefinition, propertyInfo);
            }

            if (!classInfo.IsStructAsClass)
            {
                Dictionary <string, List <MethodDefinition> > methodsByName = new Dictionary <string, List <MethodDefinition> >();
                foreach (MethodDefinition method in type.Methods)
                {
                    List <MethodDefinition> methods;
                    if (!methodsByName.TryGetValue(method.Name, out methods))
                    {
                        methodsByName.Add(method.Name, methods = new List <MethodDefinition>());
                    }
                    methods.Add(method);
                }

                foreach (ManagedUnrealFunctionInfo functionInfo in classInfo.Functions)
                {
                    string functionName = functionInfo.Name;
                    if (codeSettings.UseExplicitImplementationMethods && functionInfo.IsBlueprintEvent && functionInfo.IsOverride)
                    {
                        functionName = functionInfo.Name + codeSettings.VarNames.ImplementationMethod;
                    }

                    List <MethodDefinition> methods;
                    methodsByName.TryGetValue(functionName, out methods);
                    VerifySingleResult(methods, type, "Function " + functionName + " (the reflection system doesn't support overloads");

                    FieldDefinition functionIsValid      = AddIsValidField(type, functionInfo);
                    FieldDefinition functionAddressField = AddNativeFunctionField(type, functionInfo);
                    FieldDefinition paramsSizeField      = AddParamsSizeField(type, functionInfo);
                    injectedMembers.SetFunctionIsValid(functionInfo, functionIsValid);
                    injectedMembers.SetFunctionAddress(functionInfo, functionAddressField);
                    injectedMembers.SetFunctionParamsSize(functionInfo, paramsSizeField);

                    // Validate the parameters and add the fields for the parameter offsets / addresses
                    GetParamsFromMethod(type, functionInfo, methods[0], injectedMembers, true);

                    if (functionInfo.IsBlueprintEvent || functionInfo.IsRPC)
                    {
                        bool perInstanceFunctionAddress = functionInfo.IsBlueprintEvent;
                        RewriteMethodAsUFunctionInvoke(type, classInfo, functionInfo, methods[0], injectedMembers, perInstanceFunctionAddress);
                    }
                    else
                    {
                        WriteFunctionInvoker(type, classInfo, functionInfo, methods[0], injectedMembers, false);
                    }

                    AddPathAttribute(methods[0], functionInfo);
                }
            }

            AddPathAttribute(type, classInfo);

            CreateLoadNativeTypeMethod(type, classInfo, injectedMembers);
        }
예제 #5
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);
            }
        }
예제 #6
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);
        }