@@ -49,46 +49,64 @@ static PyObjectProxyHandler pyObjectProxyHandler;
49
49
static PyListProxyHandler pyListProxyHandler;
50
50
static PyIterableProxyHandler pyIterableProxyHandler;
51
51
52
- std::unordered_map<const char16_t *, PyObject *> ucs2ToPyObjectMap; // a map of char16_t (UCS-2) buffers to their corresponding PyObjects, used when finalizing JSExternalStrings
53
- std::unordered_map<const JS::Latin1Char *, PyObject *> latin1ToPyObjectMap; // a map of Latin-1 char buffers to their corresponding PyObjects, used when finalizing JSExternalStrings
52
+ std::unordered_map<PyObject *, size_t > jsExternalStringPyObjects;// a map of python string objects to the number of JSExternalStrings that depend on it, used when finalizing JSExternalStrings
54
53
55
54
PyObject *PythonExternalString::getPyString (const char16_t *chars)
56
55
{
57
- return ucs2ToPyObjectMap[chars];
56
+ for (auto it: jsExternalStringPyObjects) {
57
+ if (PyUnicode_DATA (it.first ) == (void *)chars) {
58
+ return it.first ;
59
+ }
60
+ }
61
+
62
+ return NULL ; // this shouldn't be reachable
58
63
}
59
64
60
65
PyObject *PythonExternalString::getPyString (const JS::Latin1Char *chars)
61
66
{
62
- return latin1ToPyObjectMap[chars];
67
+
68
+ return PythonExternalString::getPyString ((const char16_t *)chars);
63
69
}
64
70
65
71
void PythonExternalString::finalize (char16_t *chars) const
66
72
{
67
73
// We cannot call Py_DECREF here when shutting down as the thread state is gone.
68
74
// Then, when shutting down, there is only on reference left, and we don't need
69
75
// to free the object since the entire process memory is being released.
70
- PyObject *object = ucs2ToPyObjectMap[chars];
71
- if (Py_REFCNT (object) > 1 ) {
72
- Py_DECREF (object);
76
+ if (_Py_IsFinalizing ()) { return ; }
77
+
78
+ for (auto it = jsExternalStringPyObjects.cbegin (), next_it = it; it != jsExternalStringPyObjects.cend (); it = next_it) {
79
+ next_it++;
80
+ if (PyUnicode_DATA (it->first ) == (void *)chars) {
81
+ Py_DECREF (it->first );
82
+ jsExternalStringPyObjects[it->first ] = jsExternalStringPyObjects[it->first ] - 1 ;
83
+
84
+ if (jsExternalStringPyObjects[it->first ] == 0 ) {
85
+ jsExternalStringPyObjects.erase (it);
86
+ }
87
+ }
73
88
}
74
89
}
75
90
76
91
void PythonExternalString::finalize (JS::Latin1Char *chars) const
77
92
{
78
- PyObject *object = latin1ToPyObjectMap[chars];
79
- if (Py_REFCNT (object) > 1 ) {
80
- Py_DECREF (object);
81
- }
93
+ PythonExternalString::finalize ((char16_t *)chars);
82
94
}
83
95
84
96
size_t PythonExternalString::sizeOfBuffer (const char16_t *chars, mozilla::MallocSizeOf mallocSizeOf) const
85
97
{
86
- return PyUnicode_GetLength (ucs2ToPyObjectMap[chars]);
98
+ for (auto it: jsExternalStringPyObjects) {
99
+ if (PyUnicode_DATA (it.first ) == (void *)chars) {
100
+ return PyUnicode_GetLength (it.first );
101
+ }
102
+ }
103
+
104
+ return 0 ; // // this shouldn't be reachable
87
105
}
88
106
89
107
size_t PythonExternalString::sizeOfBuffer (const JS::Latin1Char *chars, mozilla::MallocSizeOf mallocSizeOf) const
90
108
{
91
- return PyUnicode_GetLength (latin1ToPyObjectMap[ chars] );
109
+ return PythonExternalString::sizeOfBuffer (( const char16_t *) chars, mallocSizeOf );
92
110
}
93
111
94
112
PythonExternalString PythonExternalStringCallbacks = {};
@@ -151,21 +169,22 @@ JS::Value jsTypeFactory(JSContext *cx, PyObject *object) {
151
169
break ;
152
170
}
153
171
case (PyUnicode_2BYTE_KIND): {
154
- ucs2ToPyObjectMap[(char16_t *)PyUnicode_2BYTE_DATA (object)] = object;
172
+ jsExternalStringPyObjects[object] = jsExternalStringPyObjects[object] + 1 ;
173
+ Py_INCREF (object);
155
174
JSString *str = JS_NewExternalUCString (cx, (char16_t *)PyUnicode_2BYTE_DATA (object), PyUnicode_GET_LENGTH (object), &PythonExternalStringCallbacks);
156
175
returnType.setString (str);
157
176
break ;
158
177
}
159
178
case (PyUnicode_1BYTE_KIND): {
160
- latin1ToPyObjectMap[(JS::Latin1Char *)PyUnicode_1BYTE_DATA (object)] = object;
179
+ jsExternalStringPyObjects[object] = jsExternalStringPyObjects[object] + 1 ;
180
+ Py_INCREF (object);
161
181
JSString *str = JS_NewExternalStringLatin1 (cx, (JS::Latin1Char *)PyUnicode_1BYTE_DATA (object), PyUnicode_GET_LENGTH (object), &PythonExternalStringCallbacks);
162
182
// JSExternalString can now be properly treated as either one-byte or two-byte strings when GCed
163
183
// see https://hg.mozilla.org/releases/mozilla-esr128/file/tip/js/src/vm/StringType-inl.h#l785
164
184
returnType.setString (str);
165
185
break ;
166
186
}
167
187
}
168
- Py_INCREF (object);
169
188
}
170
189
else if (PyMethod_Check (object) || PyFunction_Check (object) || PyCFunction_Check (object)) {
171
190
// can't determine number of arguments for PyCFunctions, so just assume potentially unbounded
0 commit comments