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 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); } }
private void WriteGetterFixedSizeArray(TypeDefinition type, ManagedUnrealTypeInfo typeInfo, ManagedUnrealPropertyInfo propertyInfo, MethodDefinition getter, FieldDefinition isValidField, FieldDefinition offsetField, FieldDefinition nativePropertyField, FieldDefinition fixedSizeArrayField) { ILProcessor processor = BeginGetter(getter); processor.Emit(OpCodes.Ldarg_0); processor.Emit(OpCodes.Ldfld, fixedSizeArrayField); // Save the position of the branch instruction for later, when we have a reference to its target. // (will insert Brtrue_S before this instruction as a null check on the wrapper field) processor.Emit(OpCodes.Ldarg_0); Instruction branchPosition = processor.Body.Instructions[processor.Body.Instructions.Count - 1]; MethodReference constructor = null; foreach (MethodDefinition ctor in fixedSizeArrayField.FieldType.Resolve().GetConstructors()) { if (ctor.Parameters.Count == 3) { constructor = ctor; break; } } VerifyNonNull(constructor, type, "constructor for " + fixedSizeArrayField.FieldType.FullName); constructor = GetConstrainedGenericTypeCtor(fixedSizeArrayField.FieldType, constructor); // new TFixedSizeArray<XXXX>(IntPtr.Add(Address, XXXX_Offset), XXXX_PropertyAddress, this); // IntPtr.Add(this.Address, XXXX_Offset) processor.Emit(OpCodes.Ldarg_0); processor.Emit(OpCodes.Call, uobjectAddressGetter); processor.Emit(OpCodes.Ldsfld, offsetField); processor.Emit(OpCodes.Call, intPtrAddMethod); // XXXX_PropertyAddress processor.Emit(OpCodes.Ldsfld, nativePropertyField); // this processor.Emit(OpCodes.Ldarg_0); // Create an instance of the array and store in the member field processor.Emit(OpCodes.Newobj, constructor); processor.Emit(OpCodes.Stfld, fixedSizeArrayField); // return XXXX; processor.Emit(OpCodes.Ldarg_0); Instruction branchTarget = processor.Body.Instructions[processor.Body.Instructions.Count - 1]; processor.Emit(OpCodes.Ldfld, fixedSizeArrayField); // Insert the branch (before the return statement) Instruction branchInstruction = processor.Create(OpCodes.Brtrue_S, branchTarget); processor.InsertBefore(branchPosition, branchInstruction); EndGetter(typeInfo, propertyInfo, getter, isValidField, processor); }