Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
- Added argument types information to "No method matches given arguments" message
- Moved wheel import in setup.py inside of a try/except to prevent pip collection failures
- Removes PyLong_GetMax and PyClass_New when targetting Python3
- Improved performance of calls from Python to C#
- Added support for converting python iterators to C# arrays
- Changed usage of obselete function GetDelegateForFunctionPointer(IntPtr, Type) to GetDelegateForFunctionPointer<TDelegate>(IntPtr)
- Added support for kwarg parameters when calling .NET methods from Python
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/classbase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ public static IntPtr tp_repr(IntPtr ob)
public static void tp_dealloc(IntPtr ob)
{
ManagedType self = GetManagedObject(ob);
IntPtr dict = Marshal.ReadIntPtr(ob, ObjectOffset.DictOffset(ob));
IntPtr dict = Marshal.ReadIntPtr(ob, ObjectOffset.TypeDictOffset(self.tpHandle));
if (dict != IntPtr.Zero)
{
Runtime.XDecref(dict);
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/classderived.cs
Original file line number Diff line number Diff line change
Expand Up @@ -877,7 +877,7 @@ public static void Finalize(IPythonDerivedType obj)
// the C# object is being destroyed which must mean there are no more
// references to the Python object as well so now we can dealloc the
// python object.
IntPtr dict = Marshal.ReadIntPtr(self.pyHandle, ObjectOffset.DictOffset(self.pyHandle));
IntPtr dict = Marshal.ReadIntPtr(self.pyHandle, ObjectOffset.TypeDictOffset(self.tpHandle));
if (dict != IntPtr.Zero)
{
Runtime.XDecref(dict);
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/clrobject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ internal CLRObject(object ob, IntPtr tp)
long flags = Util.ReadCLong(tp, TypeOffset.tp_flags);
if ((flags & TypeFlags.Subclass) != 0)
{
IntPtr dict = Marshal.ReadIntPtr(py, ObjectOffset.DictOffset(tp));
IntPtr dict = Marshal.ReadIntPtr(py, ObjectOffset.TypeDictOffset(tp));
if (dict == IntPtr.Zero)
{
dict = Runtime.PyDict_New();
Marshal.WriteIntPtr(py, ObjectOffset.DictOffset(tp), dict);
Marshal.WriteIntPtr(py, ObjectOffset.TypeDictOffset(tp), dict);
}
}

Expand Down
136 changes: 96 additions & 40 deletions src/runtime/interop.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Text;
Expand Down Expand Up @@ -68,11 +69,47 @@ public ModulePropertyAttribute()
}
}

internal static class ManagedDataOffsets
{
static ManagedDataOffsets()
{
FieldInfo[] fi = typeof(ManagedDataOffsets).GetFields(BindingFlags.Static | BindingFlags.Public);
for (int i = 0; i < fi.Length; i++)
{
fi[i].SetValue(null, -(i * IntPtr.Size) - IntPtr.Size);
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal class ObjectOffset
size = fi.Length * IntPtr.Size;
}

public static readonly int ob_data;
public static readonly int ob_dict;

private static int BaseOffset(IntPtr type)
{
Debug.Assert(type != IntPtr.Zero);
int typeSize = Marshal.ReadInt32(type, TypeOffset.tp_basicsize);
Debug.Assert(typeSize > 0 && typeSize <= ExceptionOffset.Size());
return typeSize;
}
public static int DataOffset(IntPtr type)
{
return BaseOffset(type) + ob_data;
}

public static int DictOffset(IntPtr type)
{
return BaseOffset(type) + ob_dict;
}

public static int Size { get { return size; } }

private static readonly int size;
}

internal static class OriginalObjectOffsets
{
static ObjectOffset()
static OriginalObjectOffsets()
{
int size = IntPtr.Size;
var n = 0; // Py_TRACE_REFS add two pointers to PyObject_HEAD
Expand All @@ -83,42 +120,58 @@ static ObjectOffset()
#endif
ob_refcnt = (n + 0) * size;
ob_type = (n + 1) * size;
ob_dict = (n + 2) * size;
ob_data = (n + 3) * size;
}

public static int magic(IntPtr ob)
public static int Size { get { return size; } }

private static readonly int size =
#if PYTHON_WITH_PYDEBUG
4 * IntPtr.Size;
#else
2 * IntPtr.Size;
#endif

#if PYTHON_WITH_PYDEBUG
public static int _ob_next;
public static int _ob_prev;
#endif
public static int ob_refcnt;
public static int ob_type;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal class ObjectOffset
{
static ObjectOffset()
{
#if PYTHON_WITH_PYDEBUG
_ob_next = OriginalObjectOffsets._ob_next;
_ob_prev = OriginalObjectOffsets._ob_prev;
#endif
ob_refcnt = OriginalObjectOffsets.ob_refcnt;
ob_type = OriginalObjectOffsets.ob_type;

size = OriginalObjectOffsets.Size + ManagedDataOffsets.Size;
}

public static int magic(IntPtr type)
{
if ((Runtime.PyObject_TypeCheck(ob, Exceptions.BaseException) ||
(Runtime.PyType_Check(ob) && Runtime.PyType_IsSubtype(ob, Exceptions.BaseException))))
{
return ExceptionOffset.ob_data;
}
return ob_data;
return ManagedDataOffsets.DataOffset(type);
}

public static int DictOffset(IntPtr ob)
public static int TypeDictOffset(IntPtr type)
{
if ((Runtime.PyObject_TypeCheck(ob, Exceptions.BaseException) ||
(Runtime.PyType_Check(ob) && Runtime.PyType_IsSubtype(ob, Exceptions.BaseException))))
{
return ExceptionOffset.ob_dict;
}
return ob_dict;
return ManagedDataOffsets.DictOffset(type);
}

public static int Size(IntPtr ob)
public static int Size(IntPtr pyType)
{
if ((Runtime.PyObject_TypeCheck(ob, Exceptions.BaseException) ||
(Runtime.PyType_Check(ob) && Runtime.PyType_IsSubtype(ob, Exceptions.BaseException))))
if (IsException(pyType))
{
return ExceptionOffset.Size();
}
#if PYTHON_WITH_PYDEBUG
return 6 * IntPtr.Size;
#else
return 4 * IntPtr.Size;
#endif

return size;
}

#if PYTHON_WITH_PYDEBUG
Expand All @@ -127,8 +180,15 @@ public static int Size(IntPtr ob)
#endif
public static int ob_refcnt;
public static int ob_type;
private static int ob_dict;
private static int ob_data;
private static readonly int size;

private static bool IsException(IntPtr pyObject)
{
var type = Runtime.PyObject_TYPE(pyObject);
return Runtime.PyType_IsSameAsOrSubtype(type, ofType: Exceptions.BaseException)
|| Runtime.PyType_IsSameAsOrSubtype(type, ofType: Runtime.PyTypeType)
&& Runtime.PyType_IsSubtype(pyObject, Exceptions.BaseException);
}
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
Expand All @@ -137,19 +197,17 @@ internal class ExceptionOffset
static ExceptionOffset()
{
Type type = typeof(ExceptionOffset);
FieldInfo[] fi = type.GetFields();
int size = IntPtr.Size;
FieldInfo[] fi = type.GetFields(BindingFlags.Static | BindingFlags.Public);
for (int i = 0; i < fi.Length; i++)
{
fi[i].SetValue(null, (i * size) + ObjectOffset.ob_type + size);
fi[i].SetValue(null, (i * IntPtr.Size) + OriginalObjectOffsets.Size);
}
}

public static int Size()
{
return ob_data + IntPtr.Size;
size = fi.Length * IntPtr.Size + OriginalObjectOffsets.Size + ManagedDataOffsets.Size;
}

public static int Size() { return size; }

// PyException_HEAD
// (start after PyObject_HEAD)
public static int dict = 0;
Expand All @@ -163,9 +221,7 @@ public static int Size()
public static int suppress_context = 0;
#endif

// extra c# data
public static int ob_dict;
public static int ob_data;
private static readonly int size;
}


Expand Down
2 changes: 1 addition & 1 deletion src/runtime/managedtype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ internal static ManagedType GetManagedObject(IntPtr ob)
{
IntPtr op = tp == ob
? Marshal.ReadIntPtr(tp, TypeOffset.magic())
: Marshal.ReadIntPtr(ob, ObjectOffset.magic(ob));
: Marshal.ReadIntPtr(ob, ObjectOffset.magic(tp));
if (op == IntPtr.Zero)
{
return null;
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/moduleobject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public ModuleObject(string name)
Runtime.XDecref(pyfilename);
Runtime.XDecref(pydocstring);

Marshal.WriteIntPtr(pyHandle, ObjectOffset.DictOffset(pyHandle), dict);
Marshal.WriteIntPtr(pyHandle, ObjectOffset.TypeDictOffset(tpHandle), dict);

InitializeModuleMembers();
}
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1843,6 +1843,11 @@ internal static bool PyObject_TypeCheck(IntPtr ob, IntPtr tp)
return (t == tp) || PyType_IsSubtype(t, tp);
}

internal static bool PyType_IsSameAsOrSubtype(IntPtr type, IntPtr ofType)
{
return (type == ofType) || PyType_IsSubtype(type, ofType);
}

[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyType_GenericNew(IntPtr type, IntPtr args, IntPtr kw);

Expand Down
6 changes: 3 additions & 3 deletions src/runtime/typemanager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ internal static IntPtr CreateType(Type impl)
// Set tp_basicsize to the size of our managed instance objects.
Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size);

var offset = (IntPtr)ObjectOffset.DictOffset(type);
var offset = (IntPtr)ObjectOffset.TypeDictOffset(type);
Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset);

InitializeSlots(type, impl);
Expand Down Expand Up @@ -125,17 +125,17 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType)

IntPtr base_ = IntPtr.Zero;
int ob_size = ObjectOffset.Size(Runtime.PyTypeType);
int tp_dictoffset = ObjectOffset.DictOffset(Runtime.PyTypeType);

// XXX Hack, use a different base class for System.Exception
// Python 2.5+ allows new style class exceptions but they *must*
// subclass BaseException (or better Exception).
if (typeof(Exception).IsAssignableFrom(clrType))
{
ob_size = ObjectOffset.Size(Exceptions.Exception);
tp_dictoffset = ObjectOffset.DictOffset(Exceptions.Exception);
}

int tp_dictoffset = ob_size + ManagedDataOffsets.ob_dict;

if (clrType == typeof(Exception))
{
base_ = Exceptions.Exception;
Expand Down