public FScriptArrayHelper(IntPtr arrayProperty, IntPtr array) { innerProperty = Native_UArrayProperty.Get_Inner(arrayProperty); this.arrayProperty = arrayProperty; this.array = (FScriptArray *)array; elementSize = Native_UProperty.Get_ElementSize(innerProperty); }
public static FScriptArrayHelper CreateHelperFormInnerProperty(IntPtr innerProperty, IntPtr array) { FScriptArrayHelper scriptArrayHelper = new FScriptArrayHelper(); scriptArrayHelper.innerProperty = innerProperty; scriptArrayHelper.array = (FScriptArray *)array; scriptArrayHelper.elementSize = Native_UProperty.Get_ElementSize(innerProperty); return(scriptArrayHelper); }
public FScriptSetHelper(IntPtr setProperty, IntPtr set) { this.setProperty = setProperty; this.set = (FScriptSet *)set; setLayout = Native_USetProperty.Get_SetLayout(setProperty); elementProp = Native_USetProperty.Get_ElementProp(setProperty); elementSize = Native_UProperty.Get_ElementSize(elementProp); elementArrayDim = Native_UProperty.Get_ArrayDim(elementProp); }
private unsafe void HandleInvokeFunctionFromNative(IntPtr obj, FFrame stack, IntPtr result, UFunction.FuncInvokerManaged managedFunctionInvoker) { IntPtr function = stack.CurrentNativeFunction; IntPtr paramsBuffer = stack.Locals; if (managedFunctionInvoker != null) { // Call the managed function invoker which will marshal the params from the native params buffer and then call the // target managed function managedFunctionInvoker(paramsBuffer, obj); } // Copy out params back from the locals buffer if (Native_UFunction.HasAnyFunctionFlags(function, EFunctionFlags.HasOutParms)) { // This assumes that UProperty will be itterated in the exact same order as the caller created stack->OutParms // (we could iterate stack->OutParms until nullptr but it isn't null terminated on release builds) FOutParmRec *outParms = stack.OutParmsPtr; foreach (IntPtr paramProp in new NativeReflection.NativeFieldIterator(Runtime.Classes.UProperty, function, false)) { EPropertyFlags paramFlags = Native_UProperty.GetPropertyFlags(paramProp); if ((paramFlags & EPropertyFlags.OutParm) == EPropertyFlags.OutParm && (paramFlags & EPropertyFlags.ConstParm) != EPropertyFlags.ConstParm) { Debug.Assert(outParms->Property == paramProp); // - REMOVING the DestroyValue call. The issue with this DestroyValue call is that PropAddr // and paramsBuffer can (will?) be refering to the same data which we should have set in // managedFunctionInvoker. So a call to DestroyValue would be destroying the data we want! // Though if PropAddr is for some reason still holding onto unknown memory this will leak // memory and we will need to investigate further. // - The "refering to the same data" is because of the params Memcpy in UObject::ProcessEvent. // They wont have the same address but their inital data will be the same and as such // things like FString data pointer would be pointing to the same address. // - We may still need to call DestroyValue in the BP/VM code path above. // Destroy the existing memory (this assumed the existing memory is valid or at least memzerod) //Native_UProperty.DestroyValue(paramProp, outParms->PropAddr); // A raw memcpy should be OK since the managed invoker should have set this memory appropriately. FMemory.Memcpy(outParms->PropAddr, paramsBuffer + Native_UProperty.GetOffset_ForUFunction(paramProp), Native_UProperty.Get_ElementSize(paramProp));// Should be ArrayDim*ElementSize but ArrayDim should always be 1 for params outParms = outParms->NextOutParamPtr; } } } // We assume that the caller will clean up the memory held by stack->Locals so we don't iterate over the // DestructorLink as we do in HandleInvokeFunctionFromBP. HandleInvokeFunctionFromBP needs to as it creates // copies of data when calling stack->Step() which don't occur here as we use the existing stack->Locals buffer. }
public FScriptMapHelper(IntPtr mapProperty, IntPtr map) { this.mapProperty = mapProperty; this.map = (FScriptMap *)map; mapLayout = Native_UMapProperty.Get_MapLayout(mapProperty); keyProp = Native_UMapProperty.Get_KeyProp(mapProperty); keySize = Native_UProperty.Get_ElementSize(keyProp); keyArrayDim = Native_UProperty.Get_ArrayDim(keyProp); valueProp = Native_UMapProperty.Get_ValueProp(mapProperty); valueSize = Native_UProperty.Get_ElementSize(valueProp); valueArrayDim = Native_UProperty.Get_ArrayDim(valueProp); }
private unsafe void HandleInvokeFunctionFromBP(IntPtr obj, FFrame *stack, IntPtr result, UFunction.FuncInvokerManaged managedFunctionInvoker) { // NOTE: ScriptCore.cpp uses PropertiesSize instead of ParamsSize. Is it ever any different? (it says alignment // may make them different) If it is different we should probably use PropertiesSize (including in generated code / // IL) as ScriptCore.cpp uses a memcpy of our memory. Debug.Assert(Native_UStruct.Get_PropertiesSize(stack->CurrentNativeFunction) == Native_UFunction.Get_ParmsSize(stack->CurrentNativeFunction)); IntPtr function = stack->CurrentNativeFunction; int paramsSize = Native_UFunction.Get_ParmsSize(function); int numParams = Native_UFunction.Get_NumParms(function); bool hasOutParams = Native_UFunction.HasAnyFunctionFlags(function, EFunctionFlags.HasOutParms); IntPtr *outParamsBufferPtr = stackalloc IntPtr[numParams]; byte * paramsBufferPtr = stackalloc byte[paramsSize]; IntPtr paramsBuffer = (IntPtr)paramsBufferPtr; // We could skip this memzero as stackalloc will (always?) zero memory even though the spec states // "The content of the newly allocated memory is undefined." // https://github.com/dotnet/coreclr/issues/1279 FMemory.Memzero(paramsBuffer, paramsSize); if (hasOutParams) { int paramIndex = 0; foreach (IntPtr param in new NativeReflection.NativeFieldIterator(Runtime.Classes.UProperty, function, false)) { // Not required but using for Debug.Assert() when getting the value stack->MostRecentPropertyAddress = IntPtr.Zero; stack->Step(stack->Object, paramsBuffer + Native_UProperty.GetOffset_ForUFunction(param)); outParamsBufferPtr[paramIndex] = stack->MostRecentPropertyAddress; if (Native_UProperty.HasAnyPropertyFlags(param, EPropertyFlags.ReturnParm)) { // This should be UObject::execEndFunctionParms which will just do "stack->Code--;" for allowing // the caller to use PFINISH aftwards outParamsBufferPtr[paramIndex] = result; } paramIndex++; } } else { foreach (IntPtr param in new NativeReflection.NativeFieldIterator(Runtime.Classes.UProperty, function, false)) { stack->Step(stack->Object, paramsBuffer + Native_UProperty.GetOffset_ForUFunction(param)); } } stack->PFinish();// Skip EX_EndFunctionParms // Call the managed function invoker which will marshal the params from the native params buffer and then call the // target managed function managedFunctionInvoker(paramsBuffer, obj); // Copy out params from the temp buffer if (hasOutParams) { int paramIndex = 0; foreach (IntPtr paramProp in new NativeReflection.NativeFieldIterator(Runtime.Classes.UProperty, function, false)) { if (Native_UProperty.HasAnyPropertyFlags(paramProp, EPropertyFlags.OutParm)) { Debug.Assert(outParamsBufferPtr[paramIndex] != IntPtr.Zero); // - See "REMOVING the DestroyValue call" below. // Destroy the existing memory (this assumed the existing memory is valid or at least memzerod) //Native_UProperty.DestroyValue(paramProp, outParamsBufferPtr[paramIndex]); // A raw memcpy should be OK since the managed invoker should have set this memory appropriately. FMemory.Memcpy(outParamsBufferPtr[paramIndex], paramsBuffer + Native_UProperty.GetOffset_ForUFunction(paramProp), Native_UProperty.Get_ElementSize(paramProp));// Should be ArrayDim*ElementSize but ArrayDim should always be 1 for params } paramIndex++; } } // Parameters are copied when calling stack->Step(). We are responsible for destroying non-blittable types // which were copied (FString, TArray, etc). For C++ this works out well due to the copy constructors etc. // // Example where an FString is constructed from stack->Step(): // UObject::execStringConst(...) { *(FString*)RESULT_PARAM = (ANSICHAR*)Stack.Code; } // // For C# it might be better if we reimplemented all of the IMPLEMENT_VM_FUNCTION functions to reduce the amount // of copying as we currently need ANOTHER copy to get it from the temp buffer into a C# type (which is done // inside the managedFunctionInvoker function) foreach (IntPtr paramProp in new NativeReflection.NativeFieldIterator(Runtime.Classes.UProperty, function, EFieldIteratorType.Destructor, false)) { // When is this ever false? It seems to be checked in UObject::ProcessEvent() // "Destroy local variables except function parameters." - used for BP locals? Debug.Assert(Native_UProperty.IsInContainer(paramProp, paramsSize)); // Out params are copied to the memory maintained by the caller so only destroy "by value" parameters. if (!Native_UProperty.HasAnyPropertyFlags(paramProp, EPropertyFlags.OutParm)) { Native_UProperty.DestroyValue_InContainer(paramProp, paramsBuffer); } } }
public bool Update(IntPtr address) { if (Address != address) { Address = address; Size = 0; ArrayDim = 0; IsEditConst = false; IsBlueprintReadOnly = false; GenericArg1Address = IntPtr.Zero; GenericArg1Size = 0; GenericArg1ArrayDim = 0; GenericArg2Address = IntPtr.Zero; GenericArg2Size = 0; GenericArg2ArrayDim = 0; PropertyType = EPropertyType.Unknown; if (address == IntPtr.Zero) { return(true); } EPropertyType propertyType = NativeReflection.GetPropertyType(address); if (propertyType != EPropertyType.Unknown) { PropertyType = propertyType; Size = Native_UProperty.Get_ElementSize(address); ArrayDim = Native_UProperty.Get_ArrayDim(address); IsEditConst = Native_UProperty.HasAnyPropertyFlags(address, EPropertyFlags.EditConst); IsBlueprintReadOnly = Native_UProperty.HasAnyPropertyFlags(address, EPropertyFlags.BlueprintReadOnly); switch (propertyType) { case EPropertyType.Array: GenericArg1Address = Native_UArrayProperty.Get_Inner(address); if (GenericArg1Address != IntPtr.Zero) { GenericArg1Size = Native_UProperty.Get_ElementSize(GenericArg1Address); GenericArg1ArrayDim = Native_UProperty.Get_ArrayDim(GenericArg1Address); } break; case EPropertyType.Map: GenericArg1Address = Native_UMapProperty.Get_KeyProp(address); if (GenericArg1Address != IntPtr.Zero) { GenericArg1Size = Native_UProperty.Get_ElementSize(GenericArg1Address); GenericArg1ArrayDim = Native_UProperty.Get_ArrayDim(GenericArg1Address); } GenericArg2Address = Native_UMapProperty.Get_ValueProp(address); if (GenericArg2Address != IntPtr.Zero) { GenericArg2Size = Native_UProperty.Get_ElementSize(GenericArg2Address); GenericArg2ArrayDim = Native_UProperty.Get_ArrayDim(GenericArg2Address); } break; case EPropertyType.Set: GenericArg1Address = Native_USetProperty.Get_ElementProp(address); if (GenericArg1Address != IntPtr.Zero) { GenericArg1Size = Native_UProperty.Get_ElementSize(GenericArg1Address); GenericArg1ArrayDim = Native_UProperty.Get_ArrayDim(GenericArg1Address); } break; } } return(true); } return(false); }