コード例 #1
0
 private void WriteNativeFunctionInvoker(TypeDefinition type, ManagedUnrealTypeInfo typeInfo, ManagedUnrealFunctionInfo functionInfo,
                                         MethodDefinition method, InjectedMembers injectedMembers, bool perInstanceFunctionAddress)
 {
     method.Body = new MethodBody(method);
     WriteNativeFunctionInvokerBody(type, typeInfo, functionInfo, method, injectedMembers, GetParamsFromMethod(type, functionInfo, method),
                                    method.Body.GetILProcessor(), false, perInstanceFunctionAddress);
 }
コード例 #2
0
        private void RewriteInterface(TypeDefinition type, ManagedUnrealTypeInfo interfaceInfo)
        {
            InjectedMembers injectedMembers = new InjectedMembers(interfaceInfo);

            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 interfaceInfo.Functions)
            {
                List <MethodDefinition> methods;
                methodsByName.TryGetValue(functionInfo.Name, out methods);
                VerifySingleResult(methods, type, "Function " + functionInfo.Name + " (the reflection system doesn't support overloads");

                AddPathAttribute(methods[0], functionInfo);
            }

            TypeDefinition interfaceImplType = CreateDefaultInterfaceImpl(type, interfaceInfo, methodsByName);

            AddPathAttribute(type, interfaceInfo, interfaceImplType);
        }
コード例 #3
0
        private void InjectRPCValidation(TypeDefinition type, ManagedUnrealFunctionInfo functionInfo, MethodDefinition method,
                                         InjectedMembers injectedMembers)
        {
            string validationMethodName = functionInfo.Name + codeSettings.VarNames.RPCValidate;

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

            foreach (MethodDefinition methodDef in type.Methods)
            {
                if (methodDef.Name == validationMethodName)
                {
                    validationMethods.Add(methodDef);
                }
            }
            VerifySingleResult(validationMethods, type, "required validation method " + validationMethodName);

            MethodDefinition validationMethod = validationMethods[0];

            ILProcessor processor    = method.Body.GetILProcessor();
            Instruction branchTarget = method.Body.Instructions[0];

            // Roughly compare the function params for the method / validation method
            bool invalidParams = false;

            if (method.Parameters.Count != validationMethod.Parameters.Count)
            {
                invalidParams = true;
            }
            //for (int i = 0; i < method.Parameters.Count; ++i)
            //{
            //    // TODO: Compare the params (allow removal of ref/out?)
            //}

            if (invalidParams)
            {
                throw new RewriteException(type, "RPC validation method signature mismatch " + validationMethodName);
            }

            processor.InsertBefore(branchTarget, processor.Create(OpCodes.Ldarg_0));

            for (int i = 0; i < method.Parameters.Count; ++i)
            {
                processor.InsertBefore(branchTarget, processor.Create(OpCodes.Ldarg, i + 1));
            }
            processor.InsertBefore(branchTarget, processor.Create(OpCodes.Callvirt, validationMethod));
            processor.InsertBefore(branchTarget, processor.Create(OpCodes.Brtrue_S, branchTarget));

            processor.InsertBefore(branchTarget, processor.Create(OpCodes.Ldstr, validationMethodName));
            processor.InsertBefore(branchTarget, processor.Create(OpCodes.Call, rpcValidateFailedMethod));

            // Set out parms / return value to default(XXXX)
            InsertInstructionsBefore(processor, branchTarget, CreateFunctionOutDefaults(processor, functionInfo, method));
            processor.InsertBefore(branchTarget, processor.Create(OpCodes.Ret));

            method.Body.OptimizeMacros();
        }
コード例 #4
0
        /// <summary>
        /// Inserts an IsValid safeguard on the given non-blittable struct marshaling method (ctor (FromNative) / ToNative)
        /// </summary>
        private void InsertStructMarshalerIsValidSafeguard(TypeDefinition type, ManagedUnrealTypeInfo structInfo,
                                                           MethodDefinition method, InjectedMembers injectedMembers, ILProcessor processor, bool isCtor)
        {
            if (!codeSettings.GenerateIsValidSafeguards)
            {
                return;
            }

            FieldDefinition structIsValidField = injectedMembers.StructIsValid;

            if (structIsValidField == null)
            {
                return;
            }

            // If the struct isn't valid create a log and set any out params to default values
            // if (!structName_IsValid)
            // {
            //     NativeReflection.LogInvalidStructAccessed("XXXX");
            //     PropXXX = default(XXXX); (constructor only)
            //     return;
            // }

            List <Instruction> instructions = new List <Instruction>();

            Instruction branchTarget = processor.Body.Instructions[0];

            instructions.Add(processor.Create(OpCodes.Ldsfld, structIsValidField));
            instructions.Add(processor.Create(OpCodes.Brtrue, branchTarget));
            instructions.Add(processor.Create(OpCodes.Ldstr, structInfo.Path));
            instructions.Add(processor.Create(OpCodes.Call, reflectionLogInvalidStructAccessedMethod));

            if (isCtor)
            {
                // Set struct members to default(XXXX)
                instructions.AddRange(CreateStructPropertyDefaults(processor, structInfo, type));
            }

            instructions.Add(processor.Create(OpCodes.Ret));

            // Insert the instructions at the start
            InsertInstructionsAt(processor, 0, instructions.ToArray());
        }
コード例 #5
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);
        }
コード例 #6
0
        private void RewriteStruct(TypeDefinition type, ManagedUnrealTypeInfo structInfo)
        {
            MethodDefinition copyMethod;
            MethodDefinition fromNativeMinStaticMethod;
            MethodDefinition toNativeMinStaticMethod;
            MethodDefinition fromNativeStaticMethod;
            MethodDefinition toNativeStaticMethod;
            MethodDefinition toNativeMethod;
            MethodDefinition intPtrConstructorMethod;

            FindStructMethodsToInject(type, out copyMethod,
                                      out fromNativeMinStaticMethod, out toNativeMinStaticMethod,
                                      out fromNativeStaticMethod, out toNativeStaticMethod,
                                      out toNativeMethod, out intPtrConstructorMethod);

            if (copyMethod == null)
            {
                throw new RewriteException(type, "Struct Copy method is null");
            }

            WriteStructCopyMethodBody(type, structInfo, copyMethod);

            InjectedMembers injectedMembers = new InjectedMembers(structInfo);

            FieldDefinition structSizeField = new FieldDefinition(structInfo.Name + codeSettings.VarNames.StructSize,
                                                                  FieldAttributes.Private | FieldAttributes.Static, int32TypeRef);

            type.Fields.Add(structSizeField);
            injectedMembers.StructSize = structSizeField;

            if (!structInfo.IsBlittable)
            {
                if (fromNativeMinStaticMethod == null || toNativeMinStaticMethod == null ||
                    fromNativeStaticMethod == null || toNativeStaticMethod == null ||
                    toNativeMethod == null || intPtrConstructorMethod == null)
                {
                    throw new RewriteException(type, "Struct marshaling method is null");
                }

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

                ILProcessor processor = fromNativeMinStaticMethod.Body.GetILProcessor();
                processor.Emit(OpCodes.Ldarg_0);
                processor.Emit(OpCodes.Newobj, intPtrConstructorMethod);
                processor.Emit(OpCodes.Ret);
                FinalizeMethod(fromNativeMinStaticMethod);

                processor = toNativeMinStaticMethod.Body.GetILProcessor();
                processor.Emit(OpCodes.Ldarga, toNativeStaticMethod.Parameters[1]);
                processor.Emit(OpCodes.Ldarg_0);
                processor.Emit(OpCodes.Call, toNativeMethod);
                processor.Emit(OpCodes.Ret);
                FinalizeMethod(toNativeMinStaticMethod);

                processor = fromNativeStaticMethod.Body.GetILProcessor();
                processor.Emit(OpCodes.Ldarg_0);
                processor.Emit(OpCodes.Ldarg_1);
                processor.Emit(OpCodes.Ldsfld, structSizeField);
                processor.Emit(OpCodes.Mul);
                processor.Emit(OpCodes.Call, intPtrAddMethod);
                processor.Emit(OpCodes.Newobj, intPtrConstructorMethod);
                processor.Emit(OpCodes.Ret);
                FinalizeMethod(fromNativeStaticMethod);

                processor = toNativeStaticMethod.Body.GetILProcessor();
                processor.Emit(OpCodes.Ldarga, toNativeStaticMethod.Parameters[3]);
                processor.Emit(OpCodes.Ldarg_0);
                processor.Emit(OpCodes.Ldarg_1);
                processor.Emit(OpCodes.Ldsfld, structSizeField);
                processor.Emit(OpCodes.Mul);
                processor.Emit(OpCodes.Call, intPtrAddMethod);
                processor.Emit(OpCodes.Call, toNativeMethod);
                processor.Emit(OpCodes.Ret);
                FinalizeMethod(toNativeStaticMethod);

                ILProcessor ctorProcessor     = intPtrConstructorMethod.Body.GetILProcessor();
                ILProcessor toNativeProcessor = toNativeMethod.Body.GetILProcessor();
                OpCode      loadBufferOp      = OpCodes.Ldarg_1;

                Dictionary <string, FieldDefinition> fieldsByName = new Dictionary <string, FieldDefinition>();
                foreach (FieldDefinition fieldDef in type.Fields)
                {
                    fieldsByName.Add(fieldDef.Name, fieldDef);
                }

                foreach (ManagedUnrealPropertyInfo propertyInfo in structInfo.Properties)
                {
                    // 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);

                    // Find the property
                    FieldDefinition field = null;
                    fieldsByName.TryGetValue(propertyInfo.Name, out field);
                    VerifyNonNull(field, type, "field " + propertyInfo.Name);

                    // FromNative marshaling
                    {
                        VariableDefinition marshalerVar = EmitCreateMarshaler(ctorProcessor, ctorProcessor.Create(loadBufferOp),
                                                                              offsetField, nativePropertyField, propertyInfo);
                        if (marshalerVar != null)
                        {
                            intPtrConstructorMethod.Body.Variables.Add(marshalerVar);
                        }

                        EmitLoad(ctorProcessor, ctorProcessor.Create(loadBufferOp), offsetField, nativePropertyField, structInfo,
                                 propertyInfo, marshalerVar, field);
                    }

                    // ToNative marshaling
                    {
                        VariableDefinition marshalerVar = EmitCreateMarshaler(toNativeProcessor, toNativeProcessor.Create(loadBufferOp),
                                                                              offsetField, nativePropertyField, propertyInfo);
                        if (marshalerVar != null)
                        {
                            toNativeMethod.Body.Variables.Add(marshalerVar);
                        }

                        EmitStore(toNativeProcessor, toNativeProcessor.Create(loadBufferOp), offsetField, nativePropertyField,
                                  structInfo, propertyInfo, marshalerVar, field);
                    }

                    AddPathAttribute(field, propertyInfo);
                }

                ctorProcessor.Emit(OpCodes.Ret);
                toNativeProcessor.Emit(OpCodes.Ret);
                InsertStructMarshalerIsValidSafeguard(type, structInfo, intPtrConstructorMethod, injectedMembers, ctorProcessor, true);
                InsertStructMarshalerIsValidSafeguard(type, structInfo, toNativeMethod, injectedMembers, toNativeProcessor, false);
                FinalizeMethod(intPtrConstructorMethod);
                FinalizeMethod(toNativeMethod);
            }
            else
            {
                foreach (ManagedUnrealPropertyInfo propertyInfo in structInfo.Properties)
                {
                    // Find the property
                    List <FieldDefinition> fieldDefinitions = new List <FieldDefinition>();
                    foreach (FieldDefinition fieldDef in type.Fields)
                    {
                        if (fieldDef.Name == propertyInfo.Name)
                        {
                            fieldDefinitions.Add(fieldDef);
                        }
                    }
                    VerifySingleResult(fieldDefinitions, type, "field " + propertyInfo.Name);

                    AddPathAttribute(fieldDefinitions[0], propertyInfo);
                }
            }

            AddPathAttribute(type, structInfo);

            CreateLoadNativeTypeMethod(type, structInfo, injectedMembers);
        }
コード例 #7
0
        private MethodDefinition WriteDelegateInvoker(TypeDefinition type, MethodDefinition signature, ManagedUnrealTypeInfo typeInfo,
                                                      ManagedUnrealFunctionInfo functionInfo, InjectedMembers injectedMembers)
        {
            MethodDefinition method = CopyMethod(signature, false);

            method.HasThis    = true;
            method.Attributes = MethodAttributes.Private;
            method.Name       = "Invoker";
            type.Methods.Add(method);

            MethodReference isBoundGetter = assembly.MainModule.ImportEx(GetTypeFromTypeDefinition(type).GetMethod("get_IsBound"));

            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);

            ILProcessor processor = method.Body.GetILProcessor();

            processor.Emit(OpCodes.Ldarg_0);
            processor.Emit(OpCodes.Callvirt, isBoundGetter);
            Instruction branchPosition = processor.Body.Instructions[processor.Body.Instructions.Count - 1];

            Dictionary <ManagedUnrealPropertyInfo, ParameterDefinition> parameters = GetParamsFromMethod(type, functionInfo, method, injectedMembers, true);

            WriteNativeFunctionInvokerBody(type, typeInfo, functionInfo, method, injectedMembers, parameters, processor, true, false);

            int branchTargetIndex = processor.Body.Instructions.Count;

            // Set out parms / return value to default(XXXX)
            EmitFunctionOutDefaults(processor, functionInfo, method);
            processor.Emit(OpCodes.Ret);

            processor.InsertAfter(branchPosition, processor.Create(OpCodes.Brfalse, processor.Body.Instructions[branchTargetIndex]));

            FinalizeMethod(method);
            return(method);
        }
コード例 #8
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);
        }
コード例 #9
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);
            }
        }
コード例 #10
0
        /// <summary>
        /// Inserts an IsValid safeguard on the given function
        /// </summary>
        private void InsertNativeFunctionInvokerIsValidSafeguard(TypeDefinition type, ManagedUnrealFunctionInfo functionInfo,
                                                                 MethodDefinition method, InjectedMembers injectedMembers, ILProcessor processor)
        {
            if (!codeSettings.GenerateIsValidSafeguards)
            {
                return;
            }

            FieldDefinition functionIsValidField = injectedMembers.GetFunctionIsValid(functionInfo);

            if (functionIsValidField == null)
            {
                return;
            }

            // If the function isn't valid create a log and set any out params to default values
            // if (!functionName_IsValid)
            // {
            //     NativeReflection.LogInvalidFunctionAccessed("XXXX");
            //     outParams = default(XXXX);
            //     return default(XXXX);
            // }

            List <Instruction> instructions = new List <Instruction>();

            Instruction branchTarget = processor.Body.Instructions[0];

            instructions.Add(processor.Create(OpCodes.Ldsfld, functionIsValidField));
            instructions.Add(processor.Create(OpCodes.Brtrue, branchTarget));
            instructions.Add(processor.Create(OpCodes.Ldstr, functionInfo.Path));
            instructions.Add(processor.Create(OpCodes.Call, reflectionLogInvalidFunctionAccessedMethod));

            // Set out parms / return value to default(XXXX)
            instructions.AddRange(CreateFunctionOutDefaults(processor, functionInfo, method));

            instructions.Add(processor.Create(OpCodes.Ret));

            // Insert the instructions at the start
            InsertInstructionsAt(processor, 0, instructions.ToArray());
        }
コード例 #11
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);
        }
コード例 #12
0
        private void RewriteDelegate(TypeDefinition type, ManagedUnrealTypeInfo delegateInfo)
        {
            InjectedMembers injectedMembers = new InjectedMembers(delegateInfo);

            ManagedUnrealFunctionInfo delegateSignature = delegateInfo.Functions[0];

            string getInvokerName = "GetInvoker";

            TypeDefinition        delegateSignatureType  = null;
            MethodDefinition      delegateConstructor    = null;
            MethodDefinition      delegateInvokeMethod   = null;
            List <TypeDefinition> delegateSignatureTypes = new List <TypeDefinition>();

            foreach (TypeDefinition nestedType in type.NestedTypes)
            {
                foreach (MethodDefinition method in nestedType.Methods)
                {
                    if (method.Name == "Invoke")
                    {
                        delegateSignatureType = nestedType;
                        delegateInvokeMethod  = method;
                        delegateSignatureTypes.Add(nestedType);
                        break;
                    }
                }

                foreach (MethodDefinition ctor in nestedType.GetConstructors())
                {
                    if (ctor.Parameters.Count == 2)
                    {
                        delegateConstructor = ctor;
                    }
                }
            }
            VerifySingleResult(delegateSignatureTypes, type, "Delegate signature");

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

            foreach (MethodDefinition method in type.Methods)
            {
                if (method.Name == getInvokerName)
                {
                    getInvokerFuncs.Add(method);
                }
            }
            VerifyNoResults(getInvokerFuncs, type, getInvokerName + " is already implemented in delegate");

            TypeDefinition   baseType             = type.BaseType.Resolve();
            MethodDefinition baseGetInvokerMethod = FindBaseMethodByName(baseType, getInvokerName);

            VerifyNonNull(baseGetInvokerMethod, type, "base invoker method on delegate type");

            MethodDefinition invokerMethod = WriteDelegateInvoker(type, delegateInvokeMethod, delegateInfo, delegateSignature, injectedMembers);

            MethodDefinition getInvokerMethod = CopyMethod(baseGetInvokerMethod, true, delegateSignatureType);

            type.Methods.Add(getInvokerMethod);

            ILProcessor processor = getInvokerMethod.Body.GetILProcessor();

            processor.Emit(OpCodes.Ldarg_0);
            processor.Emit(OpCodes.Ldftn, invokerMethod);
            processor.Emit(OpCodes.Newobj, delegateConstructor);
            processor.Emit(OpCodes.Ret);
            FinalizeMethod(getInvokerMethod);

            AddPathAttribute(type, delegateInfo);

            CreateLoadNativeTypeMethod(type, delegateInfo, injectedMembers);
        }
コード例 #13
0
        /// <summary>
        /// Replaces the method body with an invoke to the instanced UFunction for the given UObject to call the top-most override.
        /// Also moves the original method body to a new generated "_Implementation" method and redirects all calls to base.FuncName
        /// to base.FuncName_Implementation (if not using explicit "_Implementation" methods).
        /// </summary>
        private void RewriteMethodAsUFunctionInvoke(TypeDefinition type, ManagedUnrealTypeInfo typeInfo, ManagedUnrealFunctionInfo functionInfo,
                                                    MethodDefinition method, InjectedMembers injectedMembers, bool perInstanceFunctionAddress)
        {
            MethodDefinition implementationMethod = null;

            string implementationMethodName = functionInfo.Name + codeSettings.VarNames.ImplementationMethod;
            List <MethodDefinition> implementationMethods = new List <MethodDefinition>();

            foreach (MethodDefinition methodDef in type.Methods)
            {
                if (methodDef.Name == implementationMethodName)
                {
                    implementationMethods.Add(methodDef);
                }
            }

            if (codeSettings.UseExplicitImplementationMethods)
            {
                if (functionInfo.IsImplementation)
                {
                    implementationMethod = method;
                }
                else
                {
                    // The definition method. Replace the body with a call to the correct UFunction for the given UObject.
                    WriteNativeFunctionInvoker(type, typeInfo, functionInfo, method, injectedMembers, perInstanceFunctionAddress);

                    if (implementationMethods.Count == 0 && (functionInfo.IsBlueprintImplemented ||
                                                             codeSettings.UseImplicitBlueprintImplementableEvent))
                    {
                        // The "_Implementation" method is being skipped
                        return;
                    }

                    // Get the "_Implementation" method
                    VerifySingleResult(implementationMethods, type, "implementation method " + implementationMethodName);
                    implementationMethod = implementationMethods[0];
                }
            }
            else
            {
                VerifyNoResults(implementationMethods, type, "implementation method " + implementationMethodName);

                // Move the existing method body to a new method with an _Implementation suffix. We're going to rewrite
                // the body of the original method so that existing managed call sites will instead invoke the UFunction.
                implementationMethod      = CopyMethod(method, false);
                implementationMethod.Name = implementationMethodName;
                implementationMethod.Body = method.Body;
                type.Methods.Add(implementationMethod);

                if (functionInfo.IsOverride)
                {
                    // Redirect all base calls from base.XXXX() to base.XXXX_Implementation()
                    foreach (Instruction instruction in implementationMethod.Body.Instructions)
                    {
                        // OpCodes.Call should be base.XXXX(), OpCodes.Callvirt should be XXXX()
                        if (instruction.OpCode == OpCodes.Call)
                        {
                            MethodReference calledMethod = (MethodReference)instruction.Operand;
                            if (calledMethod.Name == functionInfo.Name)
                            {
                                MethodReference baseImplementationMethod = null;
                                foreach (MethodReference baseTypeMethod in calledMethod.DeclaringType.Resolve().Methods)
                                {
                                    if (baseTypeMethod.Name == implementationMethodName)
                                    {
                                        baseImplementationMethod = baseTypeMethod;
                                        break;
                                    }
                                }
                                VerifyNonNull(baseImplementationMethod, type, "Failed to find the base method " + implementationMethod);

                                instruction.Operand = baseImplementationMethod;
                            }
                        }
                    }
                }

                // Replace the original method's body with one that pinvokes to call the UFunction on the native side.
                // For RPCs, this will allow the engine's ProcessEvent logic to route the call to the correct client or server.
                // For BlueprintImplementableEvents, it will call the correct overriden version of the UFunction.
                WriteNativeFunctionInvoker(type, typeInfo, functionInfo, method, injectedMembers, perInstanceFunctionAddress);
            }

            if (functionInfo.WithValidation)
            {
                // Inject a validation call at the beginning of the implementation method.
                // This is slightly different from how UHT handles things, which is to call both the validation
                // and the implementation method from the generated invoker, but this simplifies the IL generation
                // and doesn't affect the relative timing of the calls.
                InjectRPCValidation(type, functionInfo, implementationMethod, injectedMembers);
            }

            // Create a managed invoker, named to match the UFunction but calls our generated
            // _Implementation method with the user's original method body. This is how the engine will actually invoke
            // the UFunction, when this class's version of it needs to run.
            WriteFunctionInvoker(type, typeInfo, functionInfo, implementationMethod, injectedMembers, functionInfo.IsBlueprintEvent);
        }
コード例 #14
0
        /// <summary>
        /// Creates the default "Impl" class which implements the given interface. That class is then used to call
        /// interface functions on types which aren't defined in C# but implement the C# interface.
        /// </summary>
        private TypeDefinition CreateDefaultInterfaceImpl(TypeDefinition interfaceType, ManagedUnrealTypeInfo interfaceInfo,
                                                          Dictionary <string, List <MethodDefinition> > methodsByName)
        {
            // TODO: Check if this "Impl" type already exists

            // Do we also need to add IInterface in ther Interfaces collection? It seems ILSpy shows IInterface
            // when we view our classes which we create manually.

            TypeAttributes accessModifier = interfaceType.Attributes.HasFlag(TypeAttributes.Public) ?
                                            TypeAttributes.Public : TypeAttributes.NotPublic;
            TypeDefinition type = new TypeDefinition(interfaceType.Namespace, interfaceType.Name + "Impl",
                                                     TypeAttributes.Sealed | TypeAttributes.Class | accessModifier);

            type.BaseType = iinterfaceImplTypeRef;
            type.Interfaces.Add(interfaceType);
            assembly.MainModule.Types.Add(type);

            // Add a default constructor
            MethodDefinition ctor = new MethodDefinition(".ctor",
                                                         MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
                                                         voidTypeRef);

            ctor.Body = new MethodBody(ctor);
            ILProcessor ctorProcessor = ctor.Body.GetILProcessor();

            ctorProcessor.Emit(OpCodes.Ret);
            FinalizeMethod(ctor);
            type.Methods.Add(ctor);

            // Add the ResetInterface method to reset the state of a pooled interface instance
            // Attributes for public override: Public | Virtual | HideBySig
            MethodDefinition resetInterfaceOverride = new MethodDefinition("ResetInterface",
                                                                           MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, voidTypeRef);

            resetInterfaceOverride.HasThis = true;
            type.Methods.Add(resetInterfaceOverride);
            resetInterfaceOverride.Body = new MethodBody(resetInterfaceOverride);
            ILProcessor resetInterfaceProcessor = resetInterfaceOverride.Body.GetILProcessor();

            InjectedMembers injectedMembers = new InjectedMembers(interfaceInfo);

            foreach (ManagedUnrealFunctionInfo functionInfo in interfaceInfo.Functions)
            {
                List <MethodDefinition> methods;
                methodsByName.TryGetValue(functionInfo.Name, out methods);
                MethodDefinition interfaceMethod = methods[0];

                // Attributes for public virtual: Public | Virtual | HideBySig | NewSlot
                // Attributes for public non-virtual: Public | Final | Virtual | HideBySig | NewSlot
                MethodDefinition method = new MethodDefinition(interfaceMethod.Name,
                                                               MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual |
                                                               MethodAttributes.HideBySig | MethodAttributes.NewSlot, interfaceMethod.ReturnType);
                method.HasThis = true;
                type.Methods.Add(method);

                foreach (ParameterDefinition parameter in interfaceMethod.Parameters)
                {
                    method.Parameters.Add(new ParameterDefinition(parameter.Name, parameter.Attributes,
                                                                  assembly.MainModule.ImportEx(parameter.ParameterType)));
                }

                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);

                // Always use a per-instance function address for now. If we change how this works also
                // update the code generator (CodeGenerator.StructExporter.cs)
                WriteNativeFunctionInvoker(type, interfaceInfo, functionInfo, method, injectedMembers, true);

                // Set the per-instance function address to IntPtr.Zero in the ResetInterface method
                FieldDefinition perInstanceFunctionAddressField = injectedMembers.GetFunctionAddressPerInstance(functionInfo);
                resetInterfaceProcessor.Emit(OpCodes.Ldarg_0);
                resetInterfaceProcessor.Emit(OpCodes.Ldsfld, intPtrZeroFieldRef);
                resetInterfaceProcessor.Emit(OpCodes.Stfld, perInstanceFunctionAddressField);

                AddPathAttribute(method, functionInfo);
            }

            resetInterfaceProcessor.Emit(OpCodes.Ret);
            FinalizeMethod(resetInterfaceOverride);

            CreateLoadNativeTypeMethod(type, interfaceInfo, injectedMembers);

            return(type);
        }