| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 34a042d commit 1680713
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -48,10 +48,6 @@ typedef struct { | |||
| 48 | 48 | */ | |
| 49 | 49 | } PyStringObject; | |
| 50 | 50 | ||
| 51 | - #define SSTATE_NOT_INTERNED 0 | ||
| 52 | - #define SSTATE_INTERNED_MORTAL 1 | ||
| 53 | - #define SSTATE_INTERNED_IMMORTAL 2 | ||
| 54 | - | ||
| 55 | 51 | PyAPI_DATA(PyTypeObject) PyBaseString_Type; | |
| 56 | 52 | PyAPI_DATA(PyTypeObject) PyString_Type; | |
| 57 | 53 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -390,13 +390,20 @@ typedef struct { | |||
| 390 | 390 | Py_ssize_t length; /* Length of raw Unicode data in buffer */ | |
| 391 | 391 | Py_UNICODE *str; /* Raw Unicode buffer */ | |
| 392 | 392 | long hash; /* Hash value; -1 if not set */ | |
| 393 | + int state; /* != 0 if interned. In this case the two | ||
| 394 | + * references from the dictionary to this object | ||
| 395 | + * are *not* counted in ob_refcnt. */ | ||
| 393 | 396 | PyObject *defenc; /* (Default) Encoded version as Python | |
| 394 | 397 | string, or NULL; this is used for | |
| 395 | 398 | implementing the buffer protocol */ | |
| 396 | 399 | } PyUnicodeObject; | |
| 397 | 400 | ||
| 398 | 401 | PyAPI_DATA(PyTypeObject) PyUnicode_Type; | |
| 399 | 402 | ||
| 403 | + #define SSTATE_NOT_INTERNED 0 | ||
| 404 | + #define SSTATE_INTERNED_MORTAL 1 | ||
| 405 | + #define SSTATE_INTERNED_IMMORTAL 2 | ||
| 406 | + | ||
| 400 | 407 | #define PyUnicode_Check(op) \ | |
| 401 | 408 | PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_UNICODE_SUBCLASS) | |
| 402 | 409 | #define PyUnicode_CheckExact(op) ((op)->ob_type == &PyUnicode_Type) | |
@@ -529,6 +536,14 @@ PyAPI_FUNC(PyObject*) PyUnicode_FromObject( | |||
| 529 | 536 | PyAPI_FUNC(PyObject *) PyUnicode_FromFormatV(const char*, va_list); | |
| 530 | 537 | PyAPI_FUNC(PyObject *) PyUnicode_FromFormat(const char*, ...); | |
| 531 | 538 | ||
| 539 | + PyAPI_FUNC(void) PyUnicode_InternInPlace(PyObject **); | ||
| 540 | + PyAPI_FUNC(void) PyUnicode_InternImmortal(PyObject **); | ||
| 541 | + PyAPI_FUNC(PyObject *) PyUnicode_InternFromString(const char *); | ||
| 542 | + PyAPI_FUNC(void) _Py_ReleaseInternedUnicodeStrings(void); | ||
| 543 | + | ||
| 544 | + /* Use only if you know it's a string */ | ||
| 545 | + #define PyUnicode_CHECK_INTERNED(op) (((PyUnicodeObject *)(op))->state) | ||
| 546 | + | ||
| 532 | 547 | /* --- wchar_t support for platforms which support it --------------------- */ | |
| 533 | 548 | ||
| 534 | 549 | #ifdef HAVE_WCHAR_H | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -521,14 +521,15 @@ Py_Main(int argc, char **argv) | |||
| 521 | 521 | #ifdef __INSURE__ | |
| 522 | 522 | /* Insure++ is a memory analysis tool that aids in discovering | |
| 523 | 523 | * memory leaks and other memory problems. On Python exit, the | |
| 524 | - * interned string dictionary is flagged as being in use at exit | ||
| 524 | + * interned string dictionaries are flagged as being in use at exit | ||
| 525 | 525 | * (which it is). Under normal circumstances, this is fine because | |
| 526 | 526 | * the memory will be automatically reclaimed by the system. Under | |
| 527 | 527 | * memory debugging, it's a huge source of useless noise, so we | |
| 528 | 528 | * trade off slower shutdown for less distraction in the memory | |
| 529 | 529 | * reports. -baw | |
| 530 | 530 | */ | |
| 531 | 531 | _Py_ReleaseInternedStrings(); | |
| 532 | + _Py_ReleaseInternedUnicodeStrings(); | ||
| 532 | 533 | #endif /* __INSURE__ */ | |
| 533 | 534 | ||
| 534 | 535 | return sts; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -24,10 +24,10 @@ bool_repr(PyObject *self) | |||
| 24 | 24 | ||
| 25 | 25 | if (self == Py_True) | |
| 26 | 26 | s = true_str ? true_str : | |
| 27 | - (true_str = PyUnicode_FromString("True")); | ||
| 27 | + (true_str = PyUnicode_InternFromString("True")); | ||
| 28 | 28 | else | |
| 29 | 29 | s = false_str ? false_str : | |
| 30 | - (false_str = PyUnicode_FromString("False")); | ||
| 30 | + (false_str = PyUnicode_InternFromString("False")); | ||
| 31 | 31 | Py_XINCREF(s); | |
| 32 | 32 | return s; | |
| 33 | 33 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -92,6 +92,16 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| 92 | 92 | extern "C" { | |
| 93 | 93 | #endif | |
| 94 | 94 | ||
| 95 | + /* This dictionary holds all interned unicode strings. Note that references | ||
| 96 | + to strings in this dictionary are *not* counted in the string's ob_refcnt. | ||
| 97 | + When the interned string reaches a refcnt of 0 the string deallocation | ||
| 98 | + function will delete the reference from this dictionary. | ||
| 99 | + | ||
| 100 | + Another way to look at this is that to say that the actual reference | ||
| 101 | + count of a string is: s->ob_refcnt + (s->ob_sstate?2:0) | ||
| 102 | + */ | ||
| 103 | + static PyObject *interned; | ||
| 104 | + | ||
| 95 | 105 | /* Free list for Unicode objects */ | |
| 96 | 106 | static PyUnicodeObject *unicode_freelist; | |
| 97 | 107 | static int unicode_freelist_size; | |
@@ -276,6 +286,7 @@ PyUnicodeObject *_PyUnicode_New(Py_ssize_t length) | |||
| 276 | 286 | unicode->str[length] = 0; | |
| 277 | 287 | unicode->length = length; | |
| 278 | 288 | unicode->hash = -1; | |
| 289 | + unicode->state = 0; | ||
| 279 | 290 | unicode->defenc = NULL; | |
| 280 | 291 | return unicode; | |
| 281 | 292 | ||
@@ -288,6 +299,25 @@ PyUnicodeObject *_PyUnicode_New(Py_ssize_t length) | |||
| 288 | 299 | static | |
| 289 | 300 | void unicode_dealloc(register PyUnicodeObject *unicode) | |
| 290 | 301 | { | |
| 302 | + switch (PyUnicode_CHECK_INTERNED(unicode)) { | ||
| 303 | + case SSTATE_NOT_INTERNED: | ||
| 304 | + break; | ||
| 305 | + | ||
| 306 | + case SSTATE_INTERNED_MORTAL: | ||
| 307 | + /* revive dead object temporarily for DelItem */ | ||
| 308 | + unicode->ob_refcnt = 3; | ||
| 309 | + if (PyDict_DelItem(interned, (PyObject *)unicode) != 0) | ||
| 310 | + Py_FatalError( | ||
| 311 | + "deletion of interned unicode string failed"); | ||
| 312 | + break; | ||
| 313 | + | ||
| 314 | + case SSTATE_INTERNED_IMMORTAL: | ||
| 315 | + Py_FatalError("Immortal interned unicode string died."); | ||
| 316 | + | ||
| 317 | + default: | ||
| 318 | + Py_FatalError("Inconsistent interned unicode string state."); | ||
| 319 | + } | ||
| 320 | + | ||
| 291 | 321 | if (PyUnicode_CheckExact(unicode) && | |
| 292 | 322 | unicode_freelist_size < MAX_UNICODE_FREELIST_SIZE) { | |
| 293 | 323 | /* Keep-Alive optimization */ | |
@@ -8564,6 +8594,115 @@ _PyUnicode_Fini(void) | |||
| 8564 | 8594 | unicode_freelist_size = 0; | |
| 8565 | 8595 | } | |
| 8566 | 8596 | ||
| 8597 | + void | ||
| 8598 | + PyUnicode_InternInPlace(PyObject **p) | ||
| 8599 | + { | ||
| 8600 | + register PyUnicodeObject *s = (PyUnicodeObject *)(*p); | ||
| 8601 | + PyObject *t; | ||
| 8602 | + if (s == NULL || !PyUnicode_Check(s)) | ||
| 8603 | + Py_FatalError( | ||
| 8604 | + "PyUnicode_InternInPlace: unicode strings only please!"); | ||
| 8605 | + /* If it's a subclass, we don't really know what putting | ||
| 8606 | + it in the interned dict might do. */ | ||
| 8607 | + if (!PyUnicode_CheckExact(s)) | ||
| 8608 | + return; | ||
| 8609 | + if (PyUnicode_CHECK_INTERNED(s)) | ||
| 8610 | + return; | ||
| 8611 | + if (interned == NULL) { | ||
| 8612 | + interned = PyDict_New(); | ||
| 8613 | + if (interned == NULL) { | ||
| 8614 | + PyErr_Clear(); /* Don't leave an exception */ | ||
| 8615 | + return; | ||
| 8616 | + } | ||
| 8617 | + } | ||
| 8618 | + t = PyDict_GetItem(interned, (PyObject *)s); | ||
| 8619 | + if (t) { | ||
| 8620 | + Py_INCREF(t); | ||
| 8621 | + Py_DECREF(*p); | ||
| 8622 | + *p = t; | ||
| 8623 | + return; | ||
| 8624 | + } | ||
| 8625 | + | ||
| 8626 | + if (PyDict_SetItem(interned, (PyObject *)s, (PyObject *)s) < 0) { | ||
| 8627 | + PyErr_Clear(); | ||
| 8628 | + return; | ||
| 8629 | + } | ||
| 8630 | + /* The two references in interned are not counted by refcnt. | ||
| 8631 | + The deallocator will take care of this */ | ||
| 8632 | + s->ob_refcnt -= 2; | ||
| 8633 | + PyUnicode_CHECK_INTERNED(s) = SSTATE_INTERNED_MORTAL; | ||
| 8634 | + } | ||
| 8635 | + | ||
| 8636 | + void | ||
| 8637 | + PyUnicode_InternImmortal(PyObject **p) | ||
| 8638 | + { | ||
| 8639 | + PyUnicode_InternInPlace(p); | ||
| 8640 | + if (PyUnicode_CHECK_INTERNED(*p) != SSTATE_INTERNED_IMMORTAL) { | ||
| 8641 | + PyUnicode_CHECK_INTERNED(*p) = SSTATE_INTERNED_IMMORTAL; | ||
| 8642 | + Py_INCREF(*p); | ||
| 8643 | + } | ||
| 8644 | + } | ||
| 8645 | + | ||
| 8646 | + PyObject * | ||
| 8647 | + PyUnicode_InternFromString(const char *cp) | ||
| 8648 | + { | ||
| 8649 | + PyObject *s = PyUnicode_FromString(cp); | ||
| 8650 | + if (s == NULL) | ||
| 8651 | + return NULL; | ||
| 8652 | + PyUnicode_InternInPlace(&s); | ||
| 8653 | + return s; | ||
| 8654 | + } | ||
| 8655 | + | ||
| 8656 | + void _Py_ReleaseInternedUnicodeStrings(void) | ||
| 8657 | + { | ||
| 8658 | + PyObject *keys; | ||
| 8659 | + PyUnicodeObject *s; | ||
| 8660 | + Py_ssize_t i, n; | ||
| 8661 | + Py_ssize_t immortal_size = 0, mortal_size = 0; | ||
| 8662 | + | ||
| 8663 | + if (interned == NULL || !PyDict_Check(interned)) | ||
| 8664 | + return; | ||
| 8665 | + keys = PyDict_Keys(interned); | ||
| 8666 | + if (keys == NULL || !PyList_Check(keys)) { | ||
| 8667 | + PyErr_Clear(); | ||
| 8668 | + return; | ||
| 8669 | + } | ||
| 8670 | + | ||
| 8671 | + /* Since _Py_ReleaseInternedUnicodeStrings() is intended to help a leak | ||
| 8672 | + detector, interned unicode strings are not forcibly deallocated; | ||
| 8673 | + rather, we give them their stolen references back, and then clear | ||
| 8674 | + and DECREF the interned dict. */ | ||
| 8675 | + | ||
| 8676 | + n = PyList_GET_SIZE(keys); | ||
| 8677 | + fprintf(stderr, "releasing %" PY_FORMAT_SIZE_T "d interned strings\n", | ||
| 8678 | + n); | ||
| 8679 | + for (i = 0; i < n; i++) { | ||
| 8680 | + s = (PyUnicodeObject *) PyList_GET_ITEM(keys, i); | ||
| 8681 | + switch (s->state) { | ||
| 8682 | + case SSTATE_NOT_INTERNED: | ||
| 8683 | + /* XXX Shouldn't happen */ | ||
| 8684 | + break; | ||
| 8685 | + case SSTATE_INTERNED_IMMORTAL: | ||
| 8686 | + s->ob_refcnt += 1; | ||
| 8687 | + immortal_size += s->length; | ||
| 8688 | + break; | ||
| 8689 | + case SSTATE_INTERNED_MORTAL: | ||
| 8690 | + s->ob_refcnt += 2; | ||
| 8691 | + mortal_size += s->length; | ||
| 8692 | + break; | ||
| 8693 | + default: | ||
| 8694 | + Py_FatalError("Inconsistent interned string state."); | ||
| 8695 | + } | ||
| 8696 | + s->state = SSTATE_NOT_INTERNED; | ||
| 8697 | + } | ||
| 8698 | + fprintf(stderr, "total size of all interned strings: " | ||
| 8699 | + "%" PY_FORMAT_SIZE_T "d/%" PY_FORMAT_SIZE_T "d " | ||
| 8700 | + "mortal/immortal\n", mortal_size, immortal_size); | ||
| 8701 | + Py_DECREF(keys); | ||
| 8702 | + PyDict_Clear(interned); | ||
| 8703 | + Py_DECREF(interned); | ||
| 8704 | + interned = NULL; | ||
| 8705 | + } | ||
| 8567 | 8706 | ||
| 8568 | 8707 | ||
| 8569 | 8708 | /********************* Unicode Iterator **************************/ | |
| Back | FazBrowse Home | New Git URL |
0 commit comments