8000 Intern string by amos402 · Pull Request #1254 · pythonnet/pythonnet · GitHub
[go: up one dir, main page]

Skip to content

Intern string #1254

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 2 commits into from
Nov 6, 2020
Merged
Show file tree
Hide file tree
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
Add intern string
  • Loading branch information
amos402 committed Oct 22, 2020
commit 955ef8dcae1e9e956d3b1c2cb5974c914e7c85d3
4 changes: 2 additions & 2 deletions src/embed_tests/TestDomainReload.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
16 changes: 16 additions & 0 deletions src/runtime/Python.Runtime.15.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,22 @@
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
<None Update="intern_.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>intern_.cs</LastGenOutput>
&l 8000 t;/None>
</ItemGroup>


<ItemGroup>
<Compile Update="intern_.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>intern_.tt</DependentUpon>
</Compile>
</ItemGroup>

<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />

<PropertyGroup>
Expand Down
8 changes: 5 additions & 3 deletions src/runtime/Python.Runtime.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,16 @@
<Compile Include="Codecs\TupleCodecs.cs" />
<Compile Include="converterextensions.cs" />
<Compile Include="finalizer.cs" />
<Compile Include="intern.cs" />
<Compile Include="intern_.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="..\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="arrayobject.cs" />
<Compile Include="assemblymanager.cs" />
<Compile Include="BorrowedReference.cs" />
<Compile Include="bufferinterface.cs" />
<Compile Include="bufferinterface.cs" />
<Compile Include="classderived.cs" />
<Compile Include="classbase.cs" />
<Compile Include="classmanager.cs" />
Expand Down Expand Up @@ -131,7 +133,7 @@
<Compile Include="overload.cs" />
<Compile Include="propertyobject.cs" />
<Compile Include="pyansistring.cs" />
<Compile Include="pybuffer.cs" />
<Compile Include="pybuffer.cs" />
<Compile Include="pydict.cs" />
<Compile Include="PyExportAttribute.cs" />
<Compile Include="pyfloat.cs" />
Expand Down Expand Up @@ -185,4 +187,4 @@
<Copy SourceFiles="$(TargetAssembly)" DestinationFolder="$(PythonBuildDir)" />
<!--Copy SourceFiles="$(TargetAssemblyPdb)" Condition="Exists('$(TargetAssemblyPdb)')" DestinationFolder="$(PythonBuildDir)" /-->
</Target>
</Project>
</Project>
2 changes: 1 addition & 1 deletion src/runtime/classbase.cs
8000
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 4 additions & 4 deletions src/runtime/classmanager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -249,16 +249,16 @@ 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();
}

// don't generate the docstring if one was already set from a DocStringAttribute.
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);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/exceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions src/runtime/importhook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand Down
74 changes: 74 additions & 0 deletions src/runtime/intern.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace Python.Runtime
{
static partial class InternString
{
private static Dictionary<string, IntPtr> _string2interns;
private static Dictionary<IntPtr, string> _intern2strings;

static InternString()
{
var identifierNames = typeof(PyIdentifier).GetFields().Select(fi => fi.Name);
var validNames = new HashSet<string>(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<string, IntPtr>();
_intern2strings = new Dictionary<IntPtr, string>();

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);
}
}
}
48 changes: 48 additions & 0 deletions src/runtime/intern_.cs
Original file line number Diff line number Diff line change
@@ -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",
};
}
}
58 changes: 58 additions & 0 deletions src/runtime/intern_.tt
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<#@ template debug="true" hostSpecific="true" #>
<#@ output extension=".cs" #>
<#
string[] internNames = new string[]
Comment on lines +1 to +4
Copy link
Member

Choose a reason for hiding this comment

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

Why use a template generator, when you can simply get internNames from reflection? It looks like unnecessary complication.

Copy link
Member Author

Choose a reason for hiding this comment

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

Two reasons make this scenario happened.

  1. You need to make sure the string is a c# intern string too to make code like this work without extra checking
const string s = "1";
switch (
    case "1":
        // both "1" point to the same string
       break;
  1. If you need (1), you have to make the internNames set on compile.
    Of course, if you don't (1), internNames can just set by using reflection from reading PyIdentities.

{
"__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 #>",
<#
}
#>
};
}
}
4 changes: 2 additions & 2 deletions src/runtime/metatype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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__");
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/methodbinding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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__":
Expand Down
3 changes: 1 addition & 2 deletions src/runtime/methodobject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 5 additions & 5 deletions src/runtime/moduleobject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/pyscope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading
0