diff --git a/PorygonSharp/EvalValues/EvalValueCreator.cs b/PorygonSharp/EvalValues/EvalValueCreator.cs index 50821f8..41edf71 100644 --- a/PorygonSharp/EvalValues/EvalValueCreator.cs +++ b/PorygonSharp/EvalValues/EvalValueCreator.cs @@ -16,8 +16,8 @@ namespace PorygonSharp.EvalValues if (type.IsEnum && !type.IsGenericParameter) { var typeHash = UserDataHandler.GetTypeId(type); - var handle = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection); - return new EvalValue(CreateUserDataEvalValue(typeHash, GCHandle.ToIntPtr(handle))); + var ptr = ObjectEvalValueHandler.GetObjectPtr(o); + return new EvalValue(CreateUserDataEvalValue(typeHash, ptr)); } var typeCode = Type.GetTypeCode(type); switch (typeCode) @@ -48,8 +48,8 @@ namespace PorygonSharp.EvalValues throw new Exception($"Type is not registered for use: {type.FullName}"); } var typeHash = UserDataHandler.GetTypeId(type); - var handle = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection); - return new EvalValue(CreateUserDataEvalValue(typeHash, GCHandle.ToIntPtr(handle))); + var ptr = ObjectEvalValueHandler.GetObjectPtr(o); + return new EvalValue(CreateUserDataEvalValue(typeHash, ptr)); default: throw new Exception($"Type {type} is not currently available as EvalValue"); } diff --git a/PorygonSharp/EvalValues/ListEvalValue.cs b/PorygonSharp/EvalValues/ListEvalValue.cs index 419847d..50905f6 100644 --- a/PorygonSharp/EvalValues/ListEvalValue.cs +++ b/PorygonSharp/EvalValues/ListEvalValue.cs @@ -1,6 +1,5 @@ using System; using System.Collections; -using System.Diagnostics; using System.Runtime.InteropServices; namespace PorygonSharp.EvalValues @@ -21,9 +20,8 @@ namespace PorygonSharp.EvalValues var valueType = type.IsArray ? type.GetElementType() : type.GetGenericArguments()[0]; if (valueType == null) throw new ArgumentNullException(); - - var parentHandle = GCHandle.Alloc(list, GCHandleType.WeakTrackResurrection); - ParentCollection = GCHandle.ToIntPtr(parentHandle); + + ParentCollection = ObjectEvalValueHandler.GetObjectPtr(list); Getter = Marshal.GetFunctionPointerForDelegate(new GetterDelegate((parent, index) => { var val = new EvalValue(index).EvaluateInteger(); diff --git a/PorygonSharp/EvalValues/ObjectEvalValueHandler.cs b/PorygonSharp/EvalValues/ObjectEvalValueHandler.cs new file mode 100644 index 0000000..1e5f359 --- /dev/null +++ b/PorygonSharp/EvalValues/ObjectEvalValueHandler.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace PorygonSharp.EvalValues +{ + internal static class ObjectEvalValueHandler + { + private struct PtrObject + { + public readonly IntPtr Pointer; + public readonly WeakReference WeakReference; + + public PtrObject(IntPtr pointer, WeakReference weakReference) + { + Pointer = pointer; + WeakReference = weakReference; + } + } + + private static readonly Dictionary CreatedPointers = new Dictionary(); + + public static IntPtr GetObjectPtr(object o) + { + var hash = o.GetHashCode(); + if (CreatedPointers.TryGetValue(hash, out var ptrObject)) + { + if (ptrObject.WeakReference.TryGetTarget(out _)) + { + return ptrObject.Pointer; + } + else + { + CreatedPointers.Remove(hash); + } + } + var handle = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection); + var ptr = GCHandle.ToIntPtr(handle); + ptrObject = new PtrObject(ptr, new WeakReference(o)); + CreatedPointers.Add(o.GetHashCode(), ptrObject); + return ptrObject.Pointer; + } + } +} \ No newline at end of file diff --git a/PorygonSharp/UserData/UserData.cs b/PorygonSharp/UserData/UserData.cs index 2b8242b..875753d 100644 --- a/PorygonSharp/UserData/UserData.cs +++ b/PorygonSharp/UserData/UserData.cs @@ -160,14 +160,12 @@ namespace PorygonSharp.UserData if (_implicitCasts.TryGetValue(expectedType, out var func)) { var castVal = func.Invoke(null, new[] {obj}); - var handle = GCHandle.Alloc(castVal, GCHandleType.WeakTrackResurrection); - return GCHandle.ToIntPtr(handle); + return EvalValueCreator.CreateValue(castVal).GetPointer(); } if (_explicitCasts.TryGetValue(expectedType, out func)) { var castVal = func.Invoke(null, new[] {obj}); - var handle = GCHandle.Alloc(castVal, GCHandleType.WeakTrackResurrection); - return GCHandle.ToIntPtr(handle); + return EvalValueCreator.CreateValue(castVal).GetPointer(); } throw new Exception("Invalid cast kind"); }