diff --git a/src/embed_tests/TestDomainReload.cs b/src/embed_tests/TestDomainReload.cs index 3556df0f6..4c9de1461 100644 --- a/src/embed_tests/TestDomainReload.cs +++ b/src/embed_tests/TestDomainReload.cs @@ -203,13 +203,13 @@ def test_obj_call(): // Create a new module IntPtr module = PyRuntime.PyModule_New(name); Assert.That(module != IntPtr.Zero); - IntPtr globals = PyRuntime.PyObject_GetAttrString(module, "__dict__"); + IntPtr globals = PyRuntime.PyObject_GetAttr(module, PyIdentifier.__dict__); Assert.That(globals != IntPtr.Zero); try { // import builtins // module.__dict__[__builtins__] = builtins - int res = PyRuntime.PyDict_SetItemString(globals, "__builtins__", + int res = PyRuntime.PyDict_SetItem(globals, PyIdentifier.__builtins__, PyRuntime.PyEval_GetBuiltins()); PythonException.ThrowIfIsNotZero(res); diff --git a/src/runtime/Python.Runtime.15.csproj b/src/runtime/Python.Runtime.15.csproj index d1e959196..4ca8140e9 100644 --- a/src/runtime/Python.Runtime.15.csproj +++ b/src/runtime/Python.Runtime.15.csproj @@ -143,6 +143,22 @@ + + + TextTemplatingFileGenerator + intern_.cs + + + + + + + True + True + intern_.tt + + + diff --git a/src/runtime/Python.Runtime.csproj b/src/runtime/Python.Runtime.csproj index a448e2bbd..a11a4b852 100644 --- a/src/runtime/Python.Runtime.csproj +++ b/src/runtime/Python.Runtime.csproj @@ -82,6 +82,8 @@ + + Properties\SharedAssemblyInfo.cs @@ -89,7 +91,7 @@ - + @@ -131,7 +133,7 @@ - + @@ -185,4 +187,4 @@ - + diff --git a/src/runtime/classbase.cs b/src/runtime/classbase.cs index 09adf5afe..a62e76050 100644 --- a/src/runtime/classbase.cs +++ b/src/runtime/classbase.cs @@ -279,7 +279,7 @@ public static IntPtr tp_repr(IntPtr ob) IntPtr args = Runtime.PyTuple_New(1); Runtime.XIncref(ob); Runtime.PyTuple_SetItem(args, 0, ob); - IntPtr reprFunc = Runtime.PyObject_GetAttrString(Runtime.PyBaseObjectType, "__repr__"); + IntPtr reprFunc = Runtime.PyObject_GetAttr(Runtime.PyBaseObjectType, PyIdentifier.__repr__); var output = Runtime.PyObject_Call(reprFunc, args, IntPtr.Zero); Runtime.XDecref(args); Runtime.XDecref(reprFunc); diff --git a/src/runtime/classmanager.cs b/src/runtime/classmanager.cs index 15f3d821d..26d0536ab 100644 --- a/src/runtime/classmanager.cs +++ b/src/runtime/classmanager.cs @@ -232,7 +232,7 @@ private static void InitClassBase(Type type, ClassBase impl) var attr = (DocStringAttribute)attrs[0]; string docStr = attr.DocString; doc = Runtime.PyString_FromString(docStr); - Runtime.PyDict_SetItemString(dict, "__doc__", doc); + Runtime.PyDict_SetItem(dict, PyIdentifier.__doc__, doc); Runtime.XDecref(doc); } @@ -249,8 +249,8 @@ private static void InitClassBase(Type type, ClassBase impl) var ctors = new ConstructorBinding(type, tp, co.binder); // ExtensionType types are untracked, so don't Incref() them. // TODO: deprecate __overloads__ soon... - Runtime.PyDict_SetItemString(dict, "__overloads__", ctors.pyHandle); - Runtime.PyDict_SetItemString(dict, "Overloads", ctors.pyHandle); + Runtime.PyDict_SetItem(dict, PyIdentifier.__overloads__, ctors.pyHandle); + Runtime.PyDict_SetItem(dict, PyIdentifier.Overloads, ctors.pyHandle); ctors.DecrRefCount(); } @@ -258,7 +258,7 @@ private static void InitClassBase(Type type, ClassBase impl) if (!CLRModule._SuppressDocs && doc == IntPtr.Zero) { doc = co.GetDocString(); - Runtime.PyDict_SetItemString(dict, "__doc__", doc); + Runtime.PyDict_SetItem(dict, PyIdentifier.__doc__, doc); Runtime.XDecref(doc); } } diff --git a/src/runtime/exceptions.cs b/src/runtime/exceptions.cs index 58506bfbb..ab28905d2 100644 --- a/src/runtime/exceptions.cs +++ b/src/runtime/exceptions.cs @@ -284,7 +284,7 @@ public static void SetError(Exception e) } IntPtr op = CLRObject.GetInstHandle(e); - IntPtr etype = Runtime.PyObject_GetAttrString(op, "__class__"); + IntPtr etype = Runtime.PyObject_GetAttr(op, PyIdentifier.__class__); Runtime.PyErr_SetObject(new BorrowedReference(etype), new BorrowedReference(op)); Runtime.XDecref(etype); Runtime.XDecref(op); diff --git a/src/runtime/importhook.cs b/src/runtime/importhook.cs index 8cf57c85d..e2795e4e3 100644 --- a/src/runtime/importhook.cs +++ b/src/runtime/importhook.cs @@ -43,11 +43,11 @@ static void InitImport() // look in CLR modules, then if we don't find any call the default // Python __import__. IntPtr builtins = Runtime.GetBuiltins(); - py_import = Runtime.PyObject_GetAttrString(builtins, "__import__"); + py_import = Runtime.PyObject_GetAttr(builtins, PyIdentifier.__import__); PythonException.ThrowIfIsNull(py_import); hook = new MethodWrapper(typeof(ImportHook), "__import__", "TernaryFunc"); - int res = Runtime.PyObject_SetAttrString(builtins, "__import__", hook.ptr); + int res = Runtime.PyObject_SetAttr(builtins, PyIdentifier.__import__, hook.ptr); PythonException.ThrowIfIsNotZero(res); Runtime.XDecref(builtins); @@ -60,7 +60,7 @@ static void RestoreImport() { IntPtr builtins = Runtime.GetBuiltins(); - int res = Runtime.PyObject_SetAttrString(builtins, "__import__", py_import); + int res = Runtime.PyObject_SetAttr(builtins, PyIdentifier.__import__, py_import); PythonException.ThrowIfIsNotZero(res); Runtime.XDecref(py_import); py_import = IntPtr.Zero; diff --git a/src/runtime/intern.cs b/src/runtime/intern.cs new file mode 100644 index 000000000..d8bdf863e --- /dev/null +++ b/src/runtime/intern.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Python.Runtime +{ + static partial class InternString + { + private static Dictionary _string2interns; + private static Dictionary _intern2strings; + + static InternString() + { + var identifierNames = typeof(PyIdentifier).GetFields().Select(fi => fi.Name); + var validNames = new HashSet(identifierNames); + if (validNames.Count != _builtinNames.Length) + { + throw new InvalidOperationException("Identifiers args not matching"); + } + foreach (var name in _builtinNames) + { + if (!validNames.Contains(name)) + { + throw new InvalidOperationException($"{name} is not declared"); + } + } + } + + public static void Initialize() + { + _string2interns = new Dictionary(); + _intern2strings = new Dictionary(); + + Type type = typeof(PyIdentifier); + foreach (string name in _builtinNames) + { + IntPtr op = Runtime.PyUnicode_InternFromString(name); + SetIntern(name, op); + type.GetField(name).SetValue(null, op); + } + } + + public static void Shutdown() + { + foreach (var ptr in _intern2strings.Keys) + { + Runtime.XDecref(ptr); + } + _string2interns = null; + _intern2strings = null; + } + + public static string GetManagedString(IntPtr op) + { + string s; + if (TryGetInterned(op, out s)) + { + return s; + } + return Runtime.GetManagedString(op); + } + + public static bool TryGetInterned(IntPtr op, out string s) + { + return _intern2strings.TryGetValue(op, out s); + } + + private static void SetIntern(string s, IntPtr op) + { + _string2interns.Add(s, op); + _intern2strings.Add(op, s); + } + } +} diff --git a/src/runtime/intern_.cs b/src/runtime/intern_.cs new file mode 100644 index 000000000..f9b3f43ec --- /dev/null +++ b/src/runtime/intern_.cs @@ -0,0 +1,48 @@ +using System; + +namespace Python.Runtime +{ + static class PyIdentifier + { + public static IntPtr __name__; + public static IntPtr __dict__; + public static IntPtr __doc__; + public static IntPtr __class__; + public static IntPtr __module__; + public static IntPtr __file__; + public static IntPtr __slots__; + public static IntPtr __self__; + public static IntPtr __annotations__; + public static IntPtr __init__; + public static IntPtr __repr__; + public static IntPtr __import__; + public static IntPtr __builtins__; + public static IntPtr builtins; + public static IntPtr __overloads__; + public static IntPtr Overloads; + } + + + static partial class InternString + { + private static readonly string[] _builtinNames = new string[] + { + "__name__", + "__dict__", + "__doc__", + "__class__", + "__module__", + "__file__", + "__slots__", + "__self__", + "__annotations__", + "__init__", + "__repr__", + "__import__", + "__builtins__", + "builtins", + "__overloads__", + "Overloads", + }; + } +} diff --git a/src/runtime/intern_.tt b/src/runtime/intern_.tt new file mode 100644 index 000000000..c7142ec9f --- /dev/null +++ b/src/runtime/intern_.tt @@ -0,0 +1,58 @@ +<#@ template debug="true" hostSpecific="true" #> +<#@ output extension=".cs" #> +<# + string[] internNames = new string[] + { + "__name__", + "__dict__", + "__doc__", + "__class__", + "__module__", + "__file__", + "__slots__", + "__self__", + "__annotations__", + + "__init__", + "__repr__", + "__import__", + "__builtins__", + + "builtins", + + "__overloads__", + "Overloads", + }; +#> +using System; + +namespace Python.Runtime +{ + static class PyIdentifier + { +<# + foreach (var name in internNames) + { +#> + public static IntPtr <#= name #>; +<# + } +#> + } + + + static partial class InternString + { + private static readonly string[] _builtinNames = new string[] + { +<# + foreach (var name in internNames) + { +#> + "<#= name #>", +<# + } +#> + }; + } +} diff --git a/src/runtime/metatype.cs b/src/runtime/metatype.cs index f7afd5d6d..84abe28b9 100644 --- a/src/runtime/metatype.cs +++ b/src/runtime/metatype.cs @@ -109,7 +109,7 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) } } - IntPtr slots = Runtime.PyDict_GetItemString(dict, "__slots__"); + IntPtr slots = Runtime.PyDict_GetItem(dict, PyIdentifier.__slots__); if (slots != IntPtr.Zero) { return Exceptions.RaiseTypeError("subclasses of managed classes do not support __slots__"); @@ -197,7 +197,7 @@ public static IntPtr tp_call(IntPtr tp, IntPtr args, IntPtr kw) return IntPtr.Zero; } - var init = Runtime.PyObject_GetAttrString(obj, "__init__"); + var init = Runtime.PyObject_GetAttr(obj, PyIdentifier.__init__); Runtime.PyErr_Clear(); if (init != IntPtr.Zero) diff --git a/src/runtime/methodbinding.cs b/src/runtime/methodbinding.cs index 011d8217d..7a10fcdef 100644 --- a/src/runtime/methodbinding.cs +++ b/src/runtime/methodbinding.cs @@ -84,7 +84,7 @@ public static IntPtr tp_getattro(IntPtr ob, IntPtr key) return IntPtr.Zero; } - string name = Runtime.GetManagedString(key); + string name = InternString.GetManagedString(key); switch (name) { case "__doc__": diff --git a/src/runtime/methodobject.cs b/src/runtime/methodobject.cs index eb3ce8a18..dc23e3ce5 100644 --- a/src/runtime/methodobject.cs +++ b/src/runtime/methodobject.cs @@ -133,8 +133,7 @@ public static IntPtr tp_getattro(IntPtr ob, IntPtr key) return Exceptions.RaiseTypeError("string expected"); } - string name = Runtime.GetManagedString(key); - if (name == "__doc__") + if (Runtime.PyUnicode_Compare(key, PyIdentifier.__doc__) == 0) { IntPtr doc = self.GetDocString(); Runtime.XIncref(doc); diff --git a/src/runtime/moduleobject.cs b/src/runtime/moduleobject.cs index 6313975da..c7085d18a 100644 --- a/src/runtime/moduleobject.cs +++ b/src/runtime/moduleobject.cs @@ -48,10 +48,10 @@ public ModuleObject(string name) IntPtr pyfilename = Runtime.PyString_FromString(filename); IntPtr pydocstring = Runtime.PyString_FromString(docstring); IntPtr pycls = TypeManager.GetTypeHandle(GetType()); - Runtime.PyDict_SetItemString(dict, "__name__", pyname); - Runtime.PyDict_SetItemString(dict, "__file__", pyfilename); - Runtime.PyDict_SetItemString(dict, "__doc__", pydocstring); - Runtime.PyDict_SetItemString(dict, "__class__", pycls); + Runtime.PyDict_SetItem(dict, PyIdentifier.__name__, pyname); + Runtime.PyDict_SetItem(dict, PyIdentifier.__file__, pyfilename); + Runtime.PyDict_SetItem(dict, PyIdentifier.__doc__, pydocstring); + Runtime.PyDict_SetItem(dict, PyIdentifier.__class__, pycls); Runtime.XDecref(pyname); Runtime.XDecref(pyfilename); Runtime.XDecref(pydocstring); @@ -282,7 +282,7 @@ public static IntPtr tp_getattro(IntPtr ob, IntPtr key) return op; } - string name = Runtime.GetManagedString(key); + string name = InternString.GetManagedString(key); if (name == "__dict__") { Runtime.XIncref(self.dict); diff --git a/src/runtime/pyscope.cs b/src/runtime/pyscope.cs index fee78b40a..20c933ad2 100644 --- a/src/runtime/pyscope.cs +++ b/src/runtime/pyscope.cs @@ -68,8 +68,8 @@ internal PyScope(IntPtr ptr, PyScopeManager manager) variables = Runtime.PyModule_GetDict(obj); PythonException.ThrowIfIsNull(variables); - int res = Runtime.PyDict_SetItemString( - variables, "__builtins__", + int res = Runtime.PyDict_SetItem( + variables, PyIdentifier.__builtins__, Runtime.PyEval_GetBuiltins() ); PythonException.ThrowIfIsNotZero(res); diff --git a/src/runtime/pythonengine.cs b/src/runtime/pythonengine.cs index 1d688ef9a..df6cf7101 100644 --- a/src/runtime/pythonengine.cs +++ b/src/runtime/pythonengine.cs @@ -595,8 +595,8 @@ internal static PyObject RunString(string code, IntPtr? globals, IntPtr? locals, if (globals == IntPtr.Zero) { globals = Runtime.PyDict_New(); - Runtime.PyDict_SetItemString( - globals.Value, "__builtins__", + Runtime.PyDict_SetItem( + globals.Value, PyIdentifier.__builtins__, Runtime.PyEval_GetBuiltins() ); borrowedGlobals = false; diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index 915e1db00..b9f471339 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -163,7 +163,7 @@ internal static void Initialize(bool initSigs = false, ShutdownMode mode = Shutd MainManagedThreadId = Thread.CurrentThread.ManagedThreadId; IsFinalizing = false; - + InternString.Initialize(); GenericUtil.Reset(); PyScopeManager.Reset(); ClassManager.Reset(); @@ -237,7 +237,7 @@ private static void InitPyMembers() // a wrapper_descriptor, even though dict.__setitem__ is. // // object.__init__ seems safe, though. - op = PyObject_GetAttrString(PyBaseObjectType, "__init__"); + op = PyObject_GetAttr(PyBaseObjectType, PyIdentifier.__init__); SetPyMember(ref PyWrapperDescriptorType, PyObject_Type(op), () => PyWrapperDescriptorType = IntPtr.Zero); XDecref(op); @@ -378,6 +378,7 @@ internal static void Shutdown(ShutdownMode mode) Exceptions.Shutdown(); Finalizer.Shutdown(); + InternString.Shutdown(); if (mode != ShutdownMode.Normal) { @@ -1598,6 +1599,12 @@ internal static IntPtr PyUnicode_FromString(string s) return PyUnicode_FromUnicode(s, s.Length); } + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyUnicode_InternFromString(string s); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyUnicode_Compare(IntPtr left, IntPtr right); + internal static string GetManagedString(in BorrowedReference borrowedReference) => GetManagedString(borrowedReference.DangerousGetAddress()); /// @@ -2183,7 +2190,7 @@ internal static void SetNoSiteFlag() /// internal static IntPtr GetBuiltins() { - return PyImport_ImportModule("builtins"); + return PyImport_Import(PyIdentifier.builtins); } } diff --git a/src/runtime/typemanager.cs b/src/runtime/typemanager.cs index 78c34a027..43c160bc3 100644 --- a/src/runtime/typemanager.cs +++ b/src/runtime/typemanager.cs @@ -165,7 +165,7 @@ internal static IntPtr CreateType(Type impl) IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); IntPtr mod = Runtime.PyString_FromString("CLR"); - Runtime.PyDict_SetItemString(dict, "__module__", mod); + Runtime.PyDict_SetItem(dict, PyIdentifier.__module__, mod); Runtime.XDecref(mod); InitMethods(type, impl); @@ -284,7 +284,7 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType) IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); string mn = clrType.Namespace ?? ""; IntPtr mod = Runtime.PyString_FromString(mn); - Runtime.PyDict_SetItemString(dict, "__module__", mod); + Runtime.PyDict_SetItem(dict, PyIdentifier.__module__, mod); Runtime.XDecref(mod); // Hide the gchandle of the implementation in a magic type slot. @@ -564,7 +564,7 @@ internal static IntPtr BasicSubType(string name, IntPtr base_, Type impl) IntPtr tp_dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); IntPtr mod = Runtime.PyString_FromString("CLR"); - Runtime.PyDict_SetItemString(tp_dict, "__module__", mod); + Runtime.PyDict_SetItem(tp_dict, PyIdentifier.__module__, mod); return type; } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy