Exemplo n.º 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);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Internal function to call into the property system to destruct elements.
        /// </summary>
        private void DestructItems(int index, int count)
        {
            if (count <= 0)
            {
                return;
            }

            bool destroyElements = !Native_UProperty.HasAnyPropertyFlags(elementProp, EPropertyFlags.IsPlainOldData | EPropertyFlags.NoDestructor);

            if (destroyElements)
            {
                int    stride     = setLayout.Size;
                IntPtr elementPtr = GetElementPtrWithoutCheck(index);

                for (; count != 0; ++index)
                {
                    if (IsValidIndex(index))
                    {
                        Native_UProperty.DestroyValue_InContainer(elementProp, elementPtr);
                        --count;
                    }
                    elementPtr += stride;
                }
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Internal function to call into the property system to destruct elements.
        /// </summary>
        private void DestructItems(int index, int count)
        {
            if (count <= 0)
            {
                return;
            }

            bool destroyKeys   = !Native_UProperty.HasAnyPropertyFlags(keyProp, EPropertyFlags.IsPlainOldData | EPropertyFlags.NoDestructor);
            bool destroyValues = !Native_UProperty.HasAnyPropertyFlags(valueProp, EPropertyFlags.IsPlainOldData | EPropertyFlags.NoDestructor);

            if (destroyKeys || destroyValues)
            {
                int    stride  = mapLayout.SetLayout.Size;
                IntPtr pairPtr = GetPairPtr(index);
                if (destroyKeys)
                {
                    if (destroyValues)
                    {
                        for (; count != 0; ++index)
                        {
                            if (IsValidIndex(index))
                            {
                                Native_UProperty.DestroyValue_InContainer(keyProp, pairPtr);
                                Native_UProperty.DestroyValue_InContainer(valueProp, pairPtr);
                                --count;
                            }
                            pairPtr += stride;
                        }
                    }
                    else
                    {
                        for (; count != 0; ++index)
                        {
                            if (IsValidIndex(index))
                            {
                                Native_UProperty.DestroyValue_InContainer(keyProp, pairPtr);
                                --count;
                            }
                            pairPtr += stride;
                        }
                    }
                }
                else
                {
                    for (; count != 0; ++index)
                    {
                        if (IsValidIndex(index))
                        {
                            Native_UProperty.DestroyValue_InContainer(valueProp, pairPtr);
                            --count;
                        }
                        pairPtr += stride;
                    }
                }
            }
        }
Exemplo n.º 4
0
 /// <summary>
 /// Internal function to call into the property system to destruct elements.
 /// </summary>
 /// <param name="index">first item to .</param>
 /// <param name="count">number of items to .</param>
 private void DestructItems(int index, int count)
 {
     if (!Native_UProperty.HasAnyPropertyFlags(innerProperty, EPropertyFlags.IsPlainOldData | EPropertyFlags.NoDestructor))
     {
         IntPtr dest = GetRawPtr(index);
         for (int i = 0; i < count; i++, dest += elementSize)
         {
             Native_UProperty.DestroyValue(innerProperty, dest);
         }
     }
 }
Exemplo n.º 5
0
            private unsafe void HandleInvokeFunctionFromNative(IntPtr obj, FFrame *stack, IntPtr result,
                                                               UFunction.FuncInvokerManaged managedFunctionInvoker)
            {
                IntPtr function     = stack->CurrentNativeFunction;
                IntPtr paramsBuffer = stack->Locals;

                // 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))
                    {
                        if (Native_UProperty.HasAnyPropertyFlags(paramProp, EPropertyFlags.OutParm))
                        {
                            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.
            }
Exemplo n.º 6
0
        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);
                }
            }
        }
Exemplo n.º 7
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 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);
            }
        }
Exemplo n.º 8
0
        private IntPtr FindProperty(string propertyName)
        {
            FName  fname    = new FName(propertyName);
            IntPtr property = Native_UStruct.FindPropertyByName(nativeClass, ref fname);

            if (!(FBuild.BuildShipping || FBuild.BuildTest))
            {
                if (property == IntPtr.Zero)
                {
                    FMessage.Log(FMessage.LogNet, ELogVerbosity.Fatal, $"Attempt to replicate property '{propertyName}' which does not exist.");
                }
                else if (!Native_UProperty.HasAnyPropertyFlags(property, EPropertyFlags.Net))
                {
                    FMessage.Log(FMessage.LogNet, ELogVerbosity.Fatal, $"Attempt to replicate property '{propertyName}' that was not tagged to replicate! Please use 'Replicated' or 'ReplicatedUsing' keyword in the UProperty() declaration.");
                }
            }

            return(property);
        }
Exemplo n.º 9
0
        /// <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);
        }
Exemplo n.º 10
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);
            }
        }
Exemplo n.º 11
0
            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);
                    }
                }
            }
Exemplo n.º 12
0
 /// <summary>
 /// Used to safely check whether any of the passed in flags are set. This is required
 /// as PropertyFlags currently is a 64 bit data type and bool is a 32 bit data type so
 /// simply using PropertyFlags&amp;CPF_MyFlagBiggerThanMaxInt won't work correctly when
 /// assigned directly to an bool.
 /// </summary>
 /// <param name="flagsToCheck">Object flags to check for.</param>
 /// <returns>true if any of the passed in flags are set, false otherwise  (including no flags passed in).</returns>
 public bool HasAnyPropertyFlags(EPropertyFlags flagsToCheck)
 {
     return(Native_UProperty.HasAnyPropertyFlags(Address, flagsToCheck));
 }
Exemplo n.º 13
0
        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);
        }