Skip to content

Refactoring of MethodBinder.Bind #829

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 6 commits into from
Mar 19, 2019
Merged
Changes from 1 commit
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
Next Next commit
cleaned up MethodBinder.Bind a bit
  • Loading branch information
lostmsu committed Mar 12, 2019
commit a19b51bfbfd06b56306c5d573d37906cc078cf38
271 changes: 136 additions & 135 deletions src/runtime/methodbinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,6 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
var pynargs = (int)Runtime.PyTuple_Size(args);
object arg;
var isGeneric = false;
ArrayList defaultArgList = null;
if (info != null)
{
_methods = new MethodBase[1];
Expand All @@ -301,180 +300,151 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
isGeneric = true;
}
ParameterInfo[] pi = mi.GetParameters();
var clrnargs = pi.Length;
var match = false;
var arrayStart = -1;
var outs = 0;
ArrayList defaultArgList;
int arrayStart;

if (pynargs == clrnargs)
{
match = true;
if (!MatchArgumentCount(pynargs, pi, out arrayStart, out defaultArgList)) {
continue;
}
else if (pynargs < clrnargs)
var outs = 0;
var margs = new object[pi.Length];

for (int paramIndex = 0; paramIndex < pi.Length; paramIndex++)
{
match = true;
defaultArgList = new ArrayList();
for (var v = pynargs; v < clrnargs; v++)
IntPtr op;
if (paramIndex >= pynargs)
{
if (pi[v].DefaultValue == DBNull.Value)
if (defaultArgList != null)
{
match = false;
}
else
{
defaultArgList.Add(pi[v].DefaultValue);
margs[paramIndex] = defaultArgList[paramIndex - pynargs];
}

continue;
}
}
else if (pynargs > clrnargs && clrnargs > 0 &&
Attribute.IsDefined(pi[clrnargs - 1], typeof(ParamArrayAttribute)))
{
// This is a `foo(params object[] bar)` style method
match = true;
arrayStart = clrnargs - 1;
}

if (match)
{
var margs = new object[clrnargs];
if (arrayStart == paramIndex)
{
// map remaining Python arguments to a tuple since
// the managed function accepts it - hopefully :]
op = Runtime.PyTuple_GetSlice(args, arrayStart, pynargs);
}
else
{
op = Runtime.PyTuple_GetItem(args, paramIndex);
}

for (int n = 0; n < clrnargs; n++)
// this logic below handles cases when multiple overloading methods
// are ambiguous, hence comparison between Python and CLR types
// is necessary
clrtype = null;
IntPtr pyoptype;
if (_methods.Length > 1)
{
IntPtr op;
if (n < pynargs)
pyoptype = IntPtr.Zero;
pyoptype = Runtime.PyObject_Type(op);
Exceptions.Clear();
if (pyoptype != IntPtr.Zero)
{
if (arrayStart == n)
{
// map remaining Python arguments to a tuple since
// the managed function accepts it - hopefully :]
op = Runtime.PyTuple_GetSlice(args, arrayStart, pynargs);
}
else
{
op = Runtime.PyTuple_GetItem(args, n);
}

// this logic below handles cases when multiple overloading methods
// are ambiguous, hence comparison between Python and CLR types
// is necessary
clrtype = null;
IntPtr pyoptype;
if (_methods.Length > 1)
{
pyoptype = IntPtr.Zero;
pyoptype = Runtime.PyObject_Type(op);
Exceptions.Clear();
if (pyoptype != IntPtr.Zero)
{
clrtype = Converter.GetTypeByAlias(pyoptype);
}
Runtime.XDecref(pyoptype);
}
clrtype = Converter.GetTypeByAlias(pyoptype);
}
Runtime.XDecref(pyoptype);
}


if (clrtype != null)
if (clrtype != null)
{
var typematch = false;
if ((pi[paramIndex].ParameterType != typeof(object)) && (pi[paramIndex].ParameterType != clrtype))
{
IntPtr pytype = Converter.GetPythonTypeByAlias(pi[paramIndex].ParameterType);
pyoptype = Runtime.PyObject_Type(op);
Exceptions.Clear();
if (pyoptype != IntPtr.Zero)
{
var typematch = false;
if ((pi[n].ParameterType != typeof(object)) && (pi[n].ParameterType != clrtype))
if (pytype != pyoptype)
{
IntPtr pytype = Converter.GetPythonTypeByAlias(pi[n].ParameterType);
pyoptype = Runtime.PyObject_Type(op);
Exceptions.Clear();
if (pyoptype != IntPtr.Zero)
{
if (pytype != pyoptype)
{
typematch = false;
}
else
{
typematch = true;
clrtype = pi[n].ParameterType;
}
}
if (!typematch)
{
// this takes care of enum values
TypeCode argtypecode = Type.GetTypeCode(pi[n].ParameterType);
TypeCode paramtypecode = Type.GetTypeCode(clrtype);
if (argtypecode == paramtypecode)
{
typematch = true;
clrtype = pi[n].ParameterType;
}
}
Runtime.XDecref(pyoptype);
if (!typematch)
{
margs = null;
break;
}
typematch = false;
}
else
{
typematch = true;
clrtype = pi[n].ParameterType;
clrtype = pi[paramIndex].ParameterType;
}
}
else
if (!typematch)
{
clrtype = pi[n].ParameterType;
}

if (pi[n].IsOut || clrtype.IsByRef)
{
outs++;
// this takes care of enum values
TypeCode argtypecode = Type.GetTypeCode(pi[paramIndex].ParameterType);
TypeCode paramtypecode = Type.GetTypeCode(clrtype);
if (argtypecode == paramtypecode)
{
typematch = true;
clrtype = pi[paramIndex].ParameterType;
}
}

if (!Converter.ToManaged(op, clrtype, out arg, false))
Runtime.XDecref(pyoptype);
if (!typematch)
{
Exceptions.Clear();
margs = null;
break;
}
if (arrayStart == n)
{
// GetSlice() creates a new reference but GetItem()
// returns only a borrow reference.
Runtime.XDecref(op);
}
margs[n] = arg;
}
else
{
if (defaultArgList != null)
{
margs[n] = defaultArgList[n - pynargs];
}
typematch = true;
clrtype = pi[paramIndex].ParameterType;
}
}
else
{
clrtype = pi[paramIndex].ParameterType;
}

if (margs == null)
if (pi[paramIndex].IsOut || clrtype.IsByRef)
{
continue;
outs++;
}

object target = null;
if (!mi.IsStatic && inst != IntPtr.Zero)
if (!Converter.ToManaged(op, clrtype, out arg, false))
{
//CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst);
// InvalidCastException: Unable to cast object of type
// 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject'
var co = ManagedType.GetManagedObject(inst) as CLRObject;

// Sanity check: this ensures a graceful exit if someone does
// something intentionally wrong like call a non-static method
// on the class rather than on an instance of the class.
// XXX maybe better to do this before all the other rigmarole.
if (co == null)
{
return null;
}
target = co.inst;
Exceptions.Clear();
margs = null;
break;
}
if (arrayStart == paramIndex)
{
// GetSlice() creates a new reference but GetItem()
// returns only a borrow reference.
Runtime.XDecref(op);
}
margs[paramIndex] = arg;
}

return new Binding(mi, target, margs, outs);
if (margs == null)
{
continue;
}

object target = null;
if (!mi.IsStatic && inst != IntPtr.Zero)
{
//CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst);
// InvalidCastException: Unable to cast object of type
// 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment confuses me more than it helps ;). It's clear after reading the next one, but here not so much.

var co = ManagedType.GetManagedObject(inst) as CLRObject;

// Sanity check: this ensures a graceful exit if someone does
// something intentionally wrong like call a non-static method
// on the class rather than on an instance of the class.
// XXX maybe better to do this before all the other rigmarole.
if (co == null)
{
return null;
}
target = co.inst;
}

return new Binding(mi, target, margs, outs);
}
// We weren't able to find a matching method but at least one
// is a generic method and info is null. That happens when a generic
Expand All @@ -489,6 +459,37 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
return null;
}

static bool MatchArgumentCount(int pynargs, ParameterInfo[] pi, out int paramsArrayStart, out ArrayList defaultArgList)
{
defaultArgList = null;
var match = false;
paramsArrayStart = -1;

if (pynargs == pi.Length)
{
match = true;
} else if (pynargs < pi.Length)
{
match = true;
defaultArgList = new ArrayList();
for (var v = pynargs; v < pi.Length; v++) {
if (pi[v].DefaultValue == DBNull.Value) {
match = false;
} else {
defaultArgList.Add(pi[v].DefaultValue);
}
}
} else if (pynargs > pi.Length && pi.Length > 0 &&
Attribute.IsDefined(pi[pi.Length - 1], typeof(ParamArrayAttribute)))
{
// This is a `foo(params object[] bar)` style method
match = true;
paramsArrayStart = pi.Length - 1;
}

return match;
}

internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw)
{
return Invoke(inst, args, kw, null, null);
Expand Down