Beispiel #1
0
        public void AddPair(IntPtr keyPtr, IntPtr valuePtr)
        {
            IntPtr localKeyPropForCapture   = keyProp;
            IntPtr localValuePropForCapture = valueProp;

            HashDelegates.GetKeyHash keyHash = delegate(IntPtr elementKey)
            {
                return(Native_UProperty.GetValueTypeHash(localKeyPropForCapture, elementKey));
            };
            HashDelegates.Equality keyEquality = delegate(IntPtr a, IntPtr b)
            {
                return(Native_UProperty.Identical(localKeyPropForCapture, a, b, 0));
            };
            HashDelegates.ConstructAndAssign keyConstructAndAssign = delegate(IntPtr newElementKey)
            {
                if (Native_UProperty.HasAnyPropertyFlags(localKeyPropForCapture, EPropertyFlags.ZeroConstructor))
                {
                    FMemory.Memzero(newElementKey, Native_UProperty.GetSize(localKeyPropForCapture));
                }
                else
                {
                    Native_UProperty.InitializeValue(localKeyPropForCapture, newElementKey);
                }

                Native_UProperty.CopySingleValue(localKeyPropForCapture, newElementKey, keyPtr);
            };
            HashDelegates.ConstructAndAssign valueConstructAndAssign = delegate(IntPtr newElementValue)
            {
                if (Native_UProperty.HasAnyPropertyFlags(localValuePropForCapture, EPropertyFlags.ZeroConstructor))
                {
                    FMemory.Memzero(newElementValue, Native_UProperty.GetSize(localValuePropForCapture));
                }
                else
                {
                    Native_UProperty.InitializeValue(localValuePropForCapture, newElementValue);
                }

                Native_UProperty.CopySingleValue(localValuePropForCapture, newElementValue, valuePtr);
            };
            HashDelegates.Assign valueAssign = delegate(IntPtr existingElementValue)
            {
                Native_UProperty.CopySingleValue(localValuePropForCapture, existingElementValue, valuePtr);
            };
            HashDelegates.Destruct keyDestruct = delegate(IntPtr elementKey)
            {
                if (!Native_UProperty.HasAnyPropertyFlags(localKeyPropForCapture, EPropertyFlags.IsPlainOldData | EPropertyFlags.NoDestructor))
                {
                    Native_UProperty.DestroyValue(localKeyPropForCapture, elementKey);
                }
            };
            HashDelegates.Destruct valueDestruct = delegate(IntPtr elementValue)
            {
                if (!Native_UProperty.HasAnyPropertyFlags(localValuePropForCapture, EPropertyFlags.IsPlainOldData | EPropertyFlags.NoDestructor))
                {
                    Native_UProperty.DestroyValue(localValuePropForCapture, elementValue);
                }
            };
            map->Add(keyPtr, valuePtr, ref mapLayout, keyHash, keyEquality, keyConstructAndAssign, valueConstructAndAssign,
                     valueAssign, keyDestruct, valueDestruct);
        }
Beispiel #2
0
 private FText()
 {
     ownsNativeAddress = true;
     nativeAddress     = FMemory.Malloc(FTextNative.StructSize);
     FMemory.Memzero(nativeAddress, FTextNative.StructSize);
     OwnsReference = true;// This assumes FText is initialized with a reference after this ctor
 }
        /// <summary>
        /// Adds zeroed values to the end of the array (calls FMemory.Memzero on the memory range).
        /// </summary>
        /// <param name="count">The number of items to insert.</param>
        /// <returns>the indnex of the first newly added item</returns>
        public int AddZeroedValues(int count)
        {
            int    oldNum = array->Add(elementSize, count);
            IntPtr dest   = GetRawPtr();

            FMemory.Memzero(dest, count * elementSize);
            return(oldNum);
        }
Beispiel #4
0
        public static unsafe void HackVTable(UObject obj)
        {
            // This will swap out the vtable entry and store the old one in our managed UClass

            if (!Native_UObjectBaseUtility.IsA(obj.Address, Runtime.Classes.UClass))
            {
                UClass unrealClass = obj.GetClass();
                if (unrealClass.VTableOriginalFunctions == null)
                {
                    IntPtr *vtable = *(IntPtr **)obj.Address;

                    unrealClass.VTableOriginalFunctions = new Dictionary <int, UClass.VTableOriginalFunc>();
                    foreach (FunctionRedirect redirect in vtableRedirects)
                    {
                        if (!Native_UObjectBaseUtility.IsA(obj.Address, redirect.Class))
                        {
                            continue;
                        }

                        IntPtr originalFunctionAddress = vtable[redirect.VTableIndex];

                        if (originalFunctionAddress != redirect.NativeCallback)
                        {
                            IntPtr originalOwnerClassAddress = FindOriginalVTableOwner(
                                redirect.Class, unrealClass.Address, originalFunctionAddress, redirect.VTableIndex);

                            if (originalOwnerClassAddress != unrealClass.Address)
                            {
                                UClass originalOwnerClass = GCHelper.Find <UClass>(originalOwnerClassAddress);
                                if (originalOwnerClass.VTableOriginalFunctions == null)
                                {
                                    HackVTable(originalOwnerClass.GetDefaultObject());
                                }
                            }

                            IntPtr pageAlignedPtr = FMemory.PageAlignPointer((IntPtr)(&vtable[redirect.VTableIndex]));
                            FMemory.PageProtect(pageAlignedPtr, (IntPtr)IntPtr.Size, true, true);
                            *(&vtable[redirect.VTableIndex]) = redirect.NativeCallback;
                        }
                        else
                        {
                            // The VTable has already been swapped out. Find the original function address.
                            UClass superClass = unrealClass;
                            while ((superClass = superClass.GetSuperClass()) != null && superClass.VTableOriginalFunctions == null)
                            {
                            }

                            Debug.Assert(superClass != null && superClass.VTableOriginalFunctions != null &&
                                         superClass.VTableOriginalFunctions.ContainsKey(redirect.VTableIndex));

                            originalFunctionAddress = superClass.VTableOriginalFunctions[redirect.VTableIndex].FuncAddress;
                        }

                        unrealClass.VTableOriginalFunctions.Add(redirect.VTableIndex, new UClass.VTableOriginalFunc(originalFunctionAddress));
                    }
                }
            }
        }
Beispiel #5
0
            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.
            }
Beispiel #6
0
        internal void Initialize()
        {
            EnsureNotInitialized();

            if (Address == IntPtr.Zero)
            {
                Address = FMemory.Malloc(NativeReflection.GetStructSize(structAddress));
                Native_UStruct.InitializeStruct(structAddress, Address, 1);
            }

            initialized = true;
        }
Beispiel #7
0
 internal void Destroy()
 {
     if (Address != IntPtr.Zero)
     {
         Native_UStruct.DestroyStruct(structAddress, Address, 1);
         if (selfAllocated)
         {
             FMemory.Free(Address);
         }
         Address       = IntPtr.Zero;
         initialized   = false;
         selfAllocated = false;
     }
 }
        private void ClearItems(int index, int count)
        {
            IntPtr dest = GetRawPtr(index);

            if (Native_UProperty.HasAnyPropertyFlags(innerProperty, EPropertyFlags.ZeroConstructor | EPropertyFlags.NoDestructor))
            {
                FMemory.Memzero(dest, count * elementSize);
            }
            else
            {
                for (int i = 0; i < count; i++, dest += elementSize)
                {
                    Native_UProperty.ClearValue(innerProperty, dest);
                }
            }
        }
Beispiel #9
0
 public void Dispose(bool disposing)
 {
     if (!disposed)
     {
         if (OwnsReference)
         {
             nativeInstance->TextData.ReleaseSharedReference(espMode);
         }
         if (ownsNativeAddress && nativeAddress != IntPtr.Zero)
         {
             FMemory.Free(nativeAddress);
             nativeAddress     = IntPtr.Zero;
             ownsNativeAddress = false;
         }
         disposed = true;
     }
 }
        /// <summary>
        /// Internal function to call into the property system to construct / initialize elements.
        /// </summary>
        /// <param name="index"First item to construct.></param>
        private void ConstructItem(int index)
        {
            bool zeroElement = Native_UProperty.HasAnyPropertyFlags(elementProp, EPropertyFlags.ZeroConstructor);

            IntPtr dest = GetElementPtrWithoutCheck(index);

            if (zeroElement)
            {
                // If any nested property needs zeroing, just pre-zero the whole space
                FMemory.Memzero(dest, setLayout.Size);
            }

            if (!zeroElement)
            {
                Native_UProperty.InitializeValue_InContainer(elementProp, dest);
            }
        }
Beispiel #11
0
        public static unsafe void Unload()
        {
            foreach (FunctionRedirect redirect in vtableRedirects)
            {
                using (FStringUnsafe dummyNameUnsafe = new FStringUnsafe(redirect.DummyName))
                {
                    Native_VTableHacks.Set_VTableCallback(ref dummyNameUnsafe.Array, IntPtr.Zero);
                }
            }

            // Restore the old vtable entry on hotreload. This is important as otherwise we would lose the original function address
            // which is stored in the managed UClass (which gets destroyed on hotreload)
            foreach (IntPtr objAddress in new NativeReflection.NativeObjectIterator(Runtime.Classes.UObject, EObjectFlags.NoFlags))
            {
                foreach (FunctionRedirect redirect in vtableRedirects)
                {
                    if (!Native_UObjectBaseUtility.IsA(objAddress, redirect.Class))
                    {
                        continue;
                    }

                    IntPtr *vtable = *(IntPtr **)objAddress;
                    if (vtable[redirect.VTableIndex] == redirect.NativeCallback)
                    {
                        UObject obj = GCHelper.Find(objAddress);
                        Debug.Assert(obj != null);

                        UClass unrealClass = obj.GetClass();
                        Debug.Assert(unrealClass != null);

                        UClass.VTableOriginalFunc originalFunc;
                        if (unrealClass.VTableOriginalFunctions != null &&
                            unrealClass.VTableOriginalFunctions.TryGetValue(redirect.VTableIndex, out originalFunc))
                        {
                            IntPtr pageAlignedPtr = FMemory.PageAlignPointer((IntPtr)(&vtable[redirect.VTableIndex]));
                            FMemory.PageProtect(pageAlignedPtr, (IntPtr)IntPtr.Size, true, true);
                            *(&vtable[redirect.VTableIndex]) = originalFunc.FuncAddress;
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Adds the element to the set, returning true if the element was added, or false if the element was already present
        /// </summary>
        public void AddElement(IntPtr elementToAdd)
        {
            IntPtr localElementPropForCapture = elementProp;

            HashDelegates.GetKeyHash elementHash = delegate(IntPtr elementKey)
            {
                return(Native_UProperty.GetValueTypeHash(localElementPropForCapture, elementKey));
            };
            HashDelegates.Equality elementEquality = delegate(IntPtr a, IntPtr b)
            {
                return(Native_UProperty.Identical(localElementPropForCapture, a, b, 0));
            };
            HashDelegates.Construct elementConstruct = delegate(IntPtr newElement)
            {
                if (Native_UProperty.HasAnyPropertyFlags(localElementPropForCapture, EPropertyFlags.ZeroConstructor))
                {
                    FMemory.Memzero(newElement, Native_UProperty.GetSize(localElementPropForCapture));
                }
                else
                {
                    Native_UProperty.InitializeValue(localElementPropForCapture, newElement);
                }

                Native_UProperty.CopySingleValue(localElementPropForCapture, newElement, elementToAdd);
            };
            HashDelegates.Destruct elementDestruct = delegate(IntPtr element)
            {
                if (!Native_UProperty.HasAnyPropertyFlags(localElementPropForCapture, EPropertyFlags.IsPlainOldData | EPropertyFlags.NoDestructor))
                {
                    Native_UProperty.DestroyValue(localElementPropForCapture, element);
                }
            };
            set->Add(
                elementToAdd,
                ref setLayout,
                elementHash,
                elementEquality,
                elementConstruct,
                elementDestruct);
        }
Beispiel #13
0
        /// <summary>
        /// Internal function to call into the property system to construct / initialize elements.
        /// </summary>
        /// <param name="index">First item to construct.</param>
        private void ConstructItem(int index)
        {
            bool zeroKey   = Native_UProperty.HasAnyPropertyFlags(keyProp, EPropertyFlags.ZeroConstructor);
            bool zeroValue = Native_UProperty.HasAnyPropertyFlags(valueProp, EPropertyFlags.ZeroConstructor);

            IntPtr dest = GetPairPtrWithoutCheck(index);

            if (zeroKey || zeroValue)
            {
                // If any nested property needs zeroing, just pre-zero the whole space
                FMemory.Memzero(dest, mapLayout.SetLayout.Size);
            }

            if (!zeroKey)
            {
                Native_UProperty.InitializeValue_InContainer(keyProp, dest);
            }

            if (!zeroValue)
            {
                Native_UProperty.InitializeValue_InContainer(valueProp, dest);
            }
        }
Beispiel #14
0
        /// <summary>
        /// Dynamically invokes the function
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public object DynamicInvoke(UObject obj, params object[] parameters)
        {
            if (parameters == null)
            {
                parameters = new object[0];
            }

            bool validParams = true;

            Dictionary <UProperty, Delegate> fromNativeParams = new Dictionary <UProperty, Delegate>();
            Dictionary <UProperty, Delegate> toNativeParams   = new Dictionary <UProperty, Delegate>();

            UProperty        returnValueProp = null;
            List <UProperty> paramProps      = new List <UProperty>();

            foreach (UProperty prop in GetProperties <UProperty>())
            {
                if (prop.HasAnyPropertyFlags(EPropertyFlags.Parm))
                {
                    if (prop.HasAnyPropertyFlags(EPropertyFlags.ReturnParm))
                    {
                        returnValueProp = prop;
                    }
                    else
                    {
                        paramProps.Add(prop);
                    }

                    Type paramType = UProperty.GetTypeFromProperty(prop);
                    if (paramType == null)
                    {
                        validParams = false;
                        break;
                    }

                    Delegate fromNative = MarshalingDelegateResolverSlow.GetFromNative(paramType);
                    Delegate toNative   = MarshalingDelegateResolverSlow.GetToNative(paramType);
                    if (fromNative == null || toNative == null)
                    {
                        validParams = false;
                        break;
                    }

                    fromNativeParams.Add(prop, fromNative);
                    toNativeParams.Add(prop, toNative);
                }
            }

            if (parameters.Length != paramProps.Count)
            {
                validParams = false;
            }

            if (!validParams)
            {
                return(null);
            }

            // Sort the parameters by offset, this is assumingly the correct thing to do?
            // - Otherwise we need to take the param names into this function. Or just not sort at all?
            //paramProps.Sort((x, y) => x.GetOffset_ForUFunction().CompareTo(y.GetOffset_ForUFunction()));

            object result = null;

            unsafe
            {
                int    paramsSize             = ParmsSize;
                byte * paramsBufferAllocation = stackalloc byte[ParmsSize];
                IntPtr paramsBuffer           = new IntPtr(paramsBufferAllocation);
                FMemory.Memzero(paramsBuffer, paramsSize);

                // Initialize default values for all parameters
                foreach (UProperty prop in GetProperties <UProperty>())
                {
                    if (prop.HasAnyPropertyFlags(EPropertyFlags.Parm))
                    {
                        Native.Native_UProperty.InitializeValue_InContainer(prop.Address, paramsBuffer);
                    }
                }

                // Copy the managed parameters to the buffer
                for (int i = 0; i < parameters.Length; i++)
                {
                    UProperty paramProp  = paramProps[i];
                    object    paramValue = parameters[i];
                    if (paramValue != null && (!paramProp.HasAnyPropertyFlags(EPropertyFlags.OutParm) ||
                                               paramProp.HasAnyPropertyFlags(EPropertyFlags.ReferenceParm)))
                    {
                        toNativeParams[paramProp].DynamicInvoke(
                            paramsBuffer + paramProp.GetOffset_ForUFunction(), (int)0, paramProp.Address, paramValue);
                    }
                }

                // Invoke the function
                NativeReflection.InvokeFunction(obj.Address, Address, paramsBuffer, paramsSize);

                // Copy parameters / return value from the buffer
                for (int i = 0; i < parameters.Length; i++)
                {
                    UProperty paramProp = paramProps[i];
                    if (paramProp.HasAnyPropertyFlags(EPropertyFlags.OutParm))
                    {
                        parameters[i] = fromNativeParams[paramProp].DynamicInvoke(
                            paramsBuffer + paramProp.GetOffset_ForUFunction(), (int)0, paramProp.Address);
                    }
                }
                if (returnValueProp != null)
                {
                    result = fromNativeParams[returnValueProp].DynamicInvoke(
                        paramsBuffer + returnValueProp.GetOffset_ForUFunction(), (int)0, returnValueProp.Address);
                }

                // Destroy the memory for all of the parameters
                foreach (UProperty prop in GetProperties <UProperty>())
                {
                    if (prop.HasAnyPropertyFlags(EPropertyFlags.Parm))
                    {
                        Native.Native_UProperty.DestroyValue_InContainer(prop.Address, paramsBuffer);
                    }
                }
            }

            return(result);
        }
            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);
                    }
                }
            }
Beispiel #16
0
        /// <summary>
        /// Checks if the given UScriptStruct address is POD and has a zero constructor (initializes to zero).
        ///
        /// NOTE: A struct could be PlainOldData but unsafe to zero initialize due to having a non-zero constructor / EForceInit constructor.
        /// </summary>
        internal static bool IsPODZeroInit(IntPtr unrealStruct)
        {
            if (unrealStruct != IntPtr.Zero && Native_UObjectBaseUtility.IsA(unrealStruct, Classes.UScriptStruct))
            {
                EStructFlags structFlags = Native_UScriptStruct.Get_StructFlags(unrealStruct);

                IntPtr cppStructOps = Native_UScriptStruct.GetCppStructOps(unrealStruct);
                if (cppStructOps != IntPtr.Zero)
                {
                    bool isPlainOldData     = Native_ICppStructOps.IsPlainOldData(cppStructOps);
                    bool hasZeroConstructor = Native_ICppStructOps.HasZeroConstructor(cppStructOps);
                    bool hasNoopConstructor = Native_ICppStructOps.HasNoopConstructor(cppStructOps);

                    if (!hasZeroConstructor && structFlags.HasFlag(EStructFlags.ZeroConstructor))
                    {
                        // This struct flag could have been set in the zero constructor check in UScriptStruct::PrepareCppStructOps
                        hasZeroConstructor = true;
                    }

                    if (isPlainOldData && hasZeroConstructor && !hasNoopConstructor)
                    {
                        return(true);
                    }

                    if (isPlainOldData && !hasZeroConstructor)
                    {
                        if (hasNoopConstructor)
                        {
                            // The struct has a no-op constructor and takes EForceInit to init
                            return(false);
                        }

                        // This is a copy of a check made in UScriptStruct::PrepareCppStructOps to check if the struct constructs to zero
                        // if (CppStructOps->IsPlainOldData() && !CppStructOps->HasZeroConstructor()) { ... }

                        int    size   = Native_ICppStructOps.GetSize(cppStructOps);
                        IntPtr buffer = FMemory.Malloc(size);
                        FMemory.Memzero(buffer, size);
                        Native_ICppStructOps.Construct(cppStructOps, buffer);
                        Native_ICppStructOps.Construct(cppStructOps, buffer);// slightly more like to catch "internal counters" if we do this twice

                        bool isZeroConstruct = true;
                        unsafe
                        {
                            byte *bufferPtr = (byte *)buffer;
                            for (int i = 0; i < size; i++)
                            {
                                if (bufferPtr[i] != 0)
                                {
                                    isZeroConstruct = false;
                                    break;
                                }
                            }
                        }

                        FMemory.Free(buffer);

                        if (isZeroConstruct)
                        {
                            // "Native struct %s has DISCOVERED zero construction. Size = %d"
                            System.Diagnostics.Debugger.Break();
                            return(true);
                        }
                    }
                    return(false);
                }
                else
                {
                    // Only treat it as blittable if it is POD and has a zero constructor
                    return(structFlags.HasFlag(EStructFlags.IsPlainOldData | EStructFlags.ZeroConstructor));
                }
            }
            return(false);
        }
Beispiel #17
0
 private void ZeroMemory()
 {
     FMemory.Memzero(ref this);
 }
Beispiel #18
0
 internal void ZeroMemory()
 {
     FMemory.Memzero(ref this);
 }