Skip to content

Simplify Dispatcher #1559

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/runtime/converter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ internal static IntPtr ToPython<T>(T value)

internal static NewReference ToPythonReference<T>(T value)
=> NewReference.DangerousFromPointer(ToPython(value, typeof(T)));
internal static NewReference ToPythonReference(object value, Type type)
=> NewReference.DangerousFromPointer(ToPython(value, type));

private static readonly Func<object, bool> IsTransparentProxy = GetIsTransparentProxy();

Expand Down
87 changes: 26 additions & 61 deletions src/runtime/delegatemanager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,6 @@ public DelegateManager()
dispatch = basetype.GetMethod("Dispatch");
}

/// <summary>
/// Given a true delegate instance, return the PyObject handle of the
/// Python object implementing the delegate (or IntPtr.Zero if the
/// delegate is not implemented in Python code.
/// </summary>
public IntPtr GetPythonHandle(Delegate d)
{
if (d?.Target is Dispatcher)
{
var disp = (Dispatcher)d.Target;
return disp.target;
}
return IntPtr.Zero;
}

/// <summary>
/// GetDispatcher is responsible for creating a class that provides
/// an appropriate managed callback method for a given delegate type.
Expand Down Expand Up @@ -224,41 +209,15 @@ A possible alternate strategy would be to create custom subclasses

public class Dispatcher
{
public IntPtr target;
public Type dtype;
private bool _disposed = false;
private bool _finalized = false;
readonly PyObject target;
readonly Type dtype;

public Dispatcher(IntPtr target, Type dtype)
{
Runtime.XIncref(target);
this.target = target;
this.target = new PyObject(new BorrowedReference(target));
this.dtype = dtype;
}

~Dispatcher()
{
if (_finalized || _disposed)
{
return;
}
_finalized = true;
Finalizer.Instance.AddFinalizedObject(ref target);
}

public void Dispose()
{
if (_disposed)
{
return;
}
_disposed = true;
Runtime.XDecref(target);
target = IntPtr.Zero;
dtype = null;
GC.SuppressFinalize(this);
}

public object Dispatch(object[] args)
{
IntPtr gs = PythonEngine.AcquireLock();
Expand All @@ -280,26 +239,36 @@ private object TrueDispatch(object[] args)
{
MethodInfo method = dtype.GetMethod("Invoke");
ParameterInfo[] pi = method.GetParameters();
IntPtr pyargs = Runtime.PyTuple_New(pi.Length);
Type rtype = method.ReturnType;

for (var i = 0; i < pi.Length; i++)
NewReference op;
using (var pyargs = NewReference.DangerousFromPointer(Runtime.PyTuple_New(pi.Length)))
{
// Here we own the reference to the Python value, and we
// give the ownership to the arg tuple.
IntPtr arg = Converter.ToPython(args[i], pi[i].ParameterType);
Runtime.PyTuple_SetItem(pyargs, i, arg);
}
for (var i = 0; i < pi.Length; i++)
{
// Here we own the reference to the Python value, and we
// give the ownership to the arg tuple.
var arg = Converter.ToPythonReference(args[i], pi[i].ParameterType);
if (arg.IsNull())
{
throw PythonException.ThrowLastAsClrException();
}
int res = Runtime.PyTuple_SetItem(pyargs, i, arg.Steal());
if (res != 0)
{
throw PythonException.ThrowLastAsClrException();
}
}

IntPtr op = Runtime.PyObject_Call(target, pyargs, IntPtr.Zero);
Runtime.XDecref(pyargs);
op = Runtime.PyObject_Call(target.Reference, pyargs, BorrowedReference.Null);
}

if (op == IntPtr.Zero)
if (op.IsNull())
{
throw PythonException.ThrowLastAsClrException();
}

try
using (op)
{
int byRefCount = pi.Count(parameterInfo => parameterInfo.ParameterType.IsByRef);
if (byRefCount > 0)
Expand Down Expand Up @@ -339,7 +308,7 @@ private object TrueDispatch(object[] args)
Type t = pi[i].ParameterType;
if (t.IsByRef)
{
IntPtr item = Runtime.PyTuple_GetItem(op, index++);
BorrowedReference item = Runtime.PyTuple_GetItem(op, index++);
if (!Converter.ToManaged(item, t, out object newArg, true))
{
Exceptions.RaiseTypeError($"The Python function returned a tuple where element {i} was not {t.GetElementType()} (the out parameter type)");
Expand All @@ -352,7 +321,7 @@ private object TrueDispatch(object[] args)
{
return null;
}
IntPtr item0 = Runtime.PyTuple_GetItem(op, 0);
BorrowedReference item0 = Runtime.PyTuple_GetItem(op, 0);
if (!Converter.ToManaged(item0, rtype, out object result0, true))
{
Exceptions.RaiseTypeError($"The Python function returned a tuple where element 0 was not {rtype} (the return type)");
Expand Down Expand Up @@ -397,10 +366,6 @@ private object TrueDispatch(object[] args)

return result;
}
finally
{
Runtime.XDecref(op);
}
}
}
}
2 changes: 1 addition & 1 deletion src/runtime/importhook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ static void SetupImportHook()
var mod_dict = Runtime.PyModule_GetDict(import_hook_module);
// reference not stolen due to overload incref'ing for us.
Runtime.PyTuple_SetItem(args, 1, mod_dict);
Runtime.PyObject_Call(exec, args, default);
Runtime.PyObject_Call(exec, args, default).Dispose();
// Set as a sub-module of clr.
if(Runtime.PyModule_AddObject(ClrModuleReference, "loader", import_hook_module.DangerousGetAddress()) != 0)
{
Expand Down
6 changes: 4 additions & 2 deletions src/runtime/runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,8 @@ internal static IntPtr PyObject_Type(IntPtr op)
internal static NewReference PyObject_Type(BorrowedReference o)
=> Delegates.PyObject_Type(o);

internal static string PyObject_GetTypeName(BorrowedReference op)
=> PyObject_GetTypeName(op.DangerousGetAddress());
internal static string PyObject_GetTypeName(IntPtr op)
{
IntPtr pyType = PyObject_TYPE(op);
Expand Down Expand Up @@ -1097,8 +1099,8 @@ internal static IntPtr PyObject_GetAttr(IntPtr pointer, IntPtr name)


internal static IntPtr PyObject_Call(IntPtr pointer, IntPtr args, IntPtr kw) => Delegates.PyObject_Call(pointer, args, kw);
internal static IntPtr PyObject_Call(BorrowedReference pointer, BorrowedReference args, BorrowedReference kw)
=> Delegates.PyObject_Call(pointer.DangerousGetAddress(), args.DangerousGetAddress(), kw.DangerousGetAddressOrNull());
internal static NewReference PyObject_Call(BorrowedReference pointer, BorrowedReference args, BorrowedReference kw)
=> NewReference.DangerousFromPointer(Delegates.PyObject_Call(pointer.DangerousGetAddress(), args.DangerousGetAddress(), kw.DangerousGetAddressOrNull()));


internal static NewReference PyObject_CallObject(BorrowedReference callable, BorrowedReference args) => Delegates.PyObject_CallObject(callable, args);
Expand Down