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); }
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); }
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(); }
/// <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()); }
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); }
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); }
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); }
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); }
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); } }
/// <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()); }
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); }
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); }
/// <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); }
/// <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); }