Handling for caching pointers to userdata objects

This commit is contained in:
Deukhoofd 2019-09-12 16:57:41 +02:00
parent ae2080f145
commit e44432c068
Signed by: Deukhoofd
GPG Key ID: ADF2E9256009EDCE
4 changed files with 52 additions and 12 deletions

View File

@ -16,8 +16,8 @@ namespace PorygonSharp.EvalValues
if (type.IsEnum && !type.IsGenericParameter) if (type.IsEnum && !type.IsGenericParameter)
{ {
var typeHash = UserDataHandler.GetTypeId(type); var typeHash = UserDataHandler.GetTypeId(type);
var handle = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection); var ptr = ObjectEvalValueHandler.GetObjectPtr(o);
return new EvalValue(CreateUserDataEvalValue(typeHash, GCHandle.ToIntPtr(handle))); return new EvalValue(CreateUserDataEvalValue(typeHash, ptr));
} }
var typeCode = Type.GetTypeCode(type); var typeCode = Type.GetTypeCode(type);
switch (typeCode) switch (typeCode)
@ -48,8 +48,8 @@ namespace PorygonSharp.EvalValues
throw new Exception($"Type is not registered for use: {type.FullName}"); throw new Exception($"Type is not registered for use: {type.FullName}");
} }
var typeHash = UserDataHandler.GetTypeId(type); var typeHash = UserDataHandler.GetTypeId(type);
var handle = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection); var ptr = ObjectEvalValueHandler.GetObjectPtr(o);
return new EvalValue(CreateUserDataEvalValue(typeHash, GCHandle.ToIntPtr(handle))); return new EvalValue(CreateUserDataEvalValue(typeHash, ptr));
default: default:
throw new Exception($"Type {type} is not currently available as EvalValue"); throw new Exception($"Type {type} is not currently available as EvalValue");
} }

View File

@ -1,6 +1,5 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Diagnostics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace PorygonSharp.EvalValues namespace PorygonSharp.EvalValues
@ -22,8 +21,7 @@ namespace PorygonSharp.EvalValues
if (valueType == null) if (valueType == null)
throw new ArgumentNullException(); throw new ArgumentNullException();
var parentHandle = GCHandle.Alloc(list, GCHandleType.WeakTrackResurrection); ParentCollection = ObjectEvalValueHandler.GetObjectPtr(list);
ParentCollection = GCHandle.ToIntPtr(parentHandle);
Getter = Marshal.GetFunctionPointerForDelegate(new GetterDelegate((parent, index) => Getter = Marshal.GetFunctionPointerForDelegate(new GetterDelegate((parent, index) =>
{ {
var val = new EvalValue(index).EvaluateInteger(); var val = new EvalValue(index).EvaluateInteger();

View File

@ -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<object> WeakReference;
public PtrObject(IntPtr pointer, WeakReference<object> weakReference)
{
Pointer = pointer;
WeakReference = weakReference;
}
}
private static readonly Dictionary<int, PtrObject> CreatedPointers = new Dictionary<int, PtrObject>();
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<object>(o));
CreatedPointers.Add(o.GetHashCode(), ptrObject);
return ptrObject.Pointer;
}
}
}

View File

@ -160,14 +160,12 @@ namespace PorygonSharp.UserData
if (_implicitCasts.TryGetValue(expectedType, out var func)) if (_implicitCasts.TryGetValue(expectedType, out var func))
{ {
var castVal = func.Invoke(null, new[] {obj}); var castVal = func.Invoke(null, new[] {obj});
var handle = GCHandle.Alloc(castVal, GCHandleType.WeakTrackResurrection); return EvalValueCreator.CreateValue(castVal).GetPointer();
return GCHandle.ToIntPtr(handle);
} }
if (_explicitCasts.TryGetValue(expectedType, out func)) if (_explicitCasts.TryGetValue(expectedType, out func))
{ {
var castVal = func.Invoke(null, new[] {obj}); var castVal = func.Invoke(null, new[] {obj});
var handle = GCHandle.Alloc(castVal, GCHandleType.WeakTrackResurrection); return EvalValueCreator.CreateValue(castVal).GetPointer();
return GCHandle.ToIntPtr(handle);
} }
throw new Exception("Invalid cast kind"); throw new Exception("Invalid cast kind");
} }