zend_string.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend Engine |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1998-2016 Zend Technologies Ltd. (http://www.zend.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 2.00 of the Zend license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.zend.com/license/2_00.txt. |
  11. | If you did not receive a copy of the Zend license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@zend.com so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Dmitry Stogov <dmitry@zend.com> |
  16. +----------------------------------------------------------------------+
  17. */
  18. /* $Id: $ */
  19. #include "zend.h"
  20. #include "zend_globals.h"
  21. #ifndef ZEND_DEBUG_INTERNED_STRINGS
  22. # define ZEND_DEBUG_INTERNED_STRINGS 0
  23. #endif
  24. #if ZEND_DEBUG_INTERNED_STRINGS
  25. # include <sys/mman.h>
  26. #endif
  27. ZEND_API const char *(*zend_new_interned_string)(const char *str, int len, int free_src TSRMLS_DC);
  28. ZEND_API void (*zend_interned_strings_snapshot)(TSRMLS_D);
  29. ZEND_API void (*zend_interned_strings_restore)(TSRMLS_D);
  30. static const char *zend_new_interned_string_int(const char *str, int len, int free_src TSRMLS_DC);
  31. static void zend_interned_strings_snapshot_int(TSRMLS_D);
  32. static void zend_interned_strings_restore_int(TSRMLS_D);
  33. void zend_interned_strings_init(TSRMLS_D)
  34. {
  35. #ifndef ZTS
  36. size_t size = 1024 * 1024;
  37. #if ZEND_DEBUG_INTERNED_STRINGS
  38. CG(interned_strings_start) = valloc(size);
  39. #else
  40. CG(interned_strings_start) = malloc(size);
  41. #endif
  42. CG(interned_strings_top) = CG(interned_strings_start);
  43. CG(interned_strings_snapshot_top) = CG(interned_strings_start);
  44. CG(interned_strings_end) = CG(interned_strings_start) + size;
  45. zend_hash_init(&CG(interned_strings), 0, NULL, NULL, 1);
  46. CG(interned_strings).nTableMask = CG(interned_strings).nTableSize - 1;
  47. CG(interned_strings).arBuckets = (Bucket **) pecalloc(CG(interned_strings).nTableSize, sizeof(Bucket *), CG(interned_strings).persistent);
  48. #if ZEND_DEBUG_INTERNED_STRINGS
  49. mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ);
  50. #endif
  51. /* interned empty string */
  52. CG(interned_empty_string) = zend_new_interned_string_int("", sizeof(""), 0 TSRMLS_CC);
  53. #endif
  54. zend_new_interned_string = zend_new_interned_string_int;
  55. zend_interned_strings_snapshot = zend_interned_strings_snapshot_int;
  56. zend_interned_strings_restore = zend_interned_strings_restore_int;
  57. }
  58. void zend_interned_strings_dtor(TSRMLS_D)
  59. {
  60. #ifndef ZTS
  61. #if ZEND_DEBUG_INTERNED_STRINGS
  62. mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_WRITE | PROT_READ);
  63. #endif
  64. free(CG(interned_strings).arBuckets);
  65. free(CG(interned_strings_start));
  66. #endif
  67. }
  68. static const char *zend_new_interned_string_int(const char *arKey, int nKeyLength, int free_src TSRMLS_DC)
  69. {
  70. #ifndef ZTS
  71. ulong h;
  72. uint nIndex;
  73. Bucket *p;
  74. if (IS_INTERNED(arKey)) {
  75. return arKey;
  76. }
  77. h = zend_inline_hash_func(arKey, nKeyLength);
  78. nIndex = h & CG(interned_strings).nTableMask;
  79. p = CG(interned_strings).arBuckets[nIndex];
  80. while (p != NULL) {
  81. if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
  82. if (!memcmp(p->arKey, arKey, nKeyLength)) {
  83. if (free_src) {
  84. efree((void *)arKey);
  85. }
  86. return p->arKey;
  87. }
  88. }
  89. p = p->pNext;
  90. }
  91. if (CG(interned_strings_top) + ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength) >=
  92. CG(interned_strings_end)) {
  93. /* no memory */
  94. return arKey;
  95. }
  96. p = (Bucket *) CG(interned_strings_top);
  97. CG(interned_strings_top) += ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength);
  98. #if ZEND_DEBUG_INTERNED_STRINGS
  99. mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ | PROT_WRITE);
  100. #endif
  101. p->arKey = (char*)(p+1);
  102. memcpy((char*)p->arKey, arKey, nKeyLength);
  103. if (free_src) {
  104. efree((void *)arKey);
  105. }
  106. p->nKeyLength = nKeyLength;
  107. p->h = h;
  108. p->pData = &p->pDataPtr;
  109. p->pDataPtr = p;
  110. p->pNext = CG(interned_strings).arBuckets[nIndex];
  111. p->pLast = NULL;
  112. if (p->pNext) {
  113. p->pNext->pLast = p;
  114. }
  115. HANDLE_BLOCK_INTERRUPTIONS();
  116. p->pListLast = CG(interned_strings).pListTail;
  117. CG(interned_strings).pListTail = p;
  118. p->pListNext = NULL;
  119. if (p->pListLast != NULL) {
  120. p->pListLast->pListNext = p;
  121. }
  122. if (!CG(interned_strings).pListHead) {
  123. CG(interned_strings).pListHead = p;
  124. }
  125. CG(interned_strings).arBuckets[nIndex] = p;
  126. HANDLE_UNBLOCK_INTERRUPTIONS();
  127. CG(interned_strings).nNumOfElements++;
  128. if (CG(interned_strings).nNumOfElements > CG(interned_strings).nTableSize) {
  129. if ((CG(interned_strings).nTableSize << 1) > 0) { /* Let's double the table size */
  130. Bucket **t = (Bucket **) perealloc_recoverable(CG(interned_strings).arBuckets, (CG(interned_strings).nTableSize << 1) * sizeof(Bucket *), CG(interned_strings).persistent);
  131. if (t) {
  132. HANDLE_BLOCK_INTERRUPTIONS();
  133. CG(interned_strings).arBuckets = t;
  134. CG(interned_strings).nTableSize = (CG(interned_strings).nTableSize << 1);
  135. CG(interned_strings).nTableMask = CG(interned_strings).nTableSize - 1;
  136. zend_hash_rehash(&CG(interned_strings));
  137. HANDLE_UNBLOCK_INTERRUPTIONS();
  138. }
  139. }
  140. }
  141. #if ZEND_DEBUG_INTERNED_STRINGS
  142. mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ);
  143. #endif
  144. return p->arKey;
  145. #else
  146. return arKey;
  147. #endif
  148. }
  149. static void zend_interned_strings_snapshot_int(TSRMLS_D)
  150. {
  151. CG(interned_strings_snapshot_top) = CG(interned_strings_top);
  152. }
  153. static void zend_interned_strings_restore_int(TSRMLS_D)
  154. {
  155. #ifndef ZTS
  156. Bucket *p;
  157. int i;
  158. #endif
  159. CG(interned_strings_top) = CG(interned_strings_snapshot_top);
  160. #ifndef ZTS
  161. #if ZEND_DEBUG_INTERNED_STRINGS
  162. mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_WRITE | PROT_READ);
  163. #endif
  164. for (i = 0; i < CG(interned_strings).nTableSize; i++) {
  165. p = CG(interned_strings).arBuckets[i];
  166. while (p && p->arKey > CG(interned_strings_top)) {
  167. CG(interned_strings).nNumOfElements--;
  168. if (p->pListLast != NULL) {
  169. p->pListLast->pListNext = p->pListNext;
  170. } else {
  171. CG(interned_strings).pListHead = p->pListNext;
  172. }
  173. if (p->pListNext != NULL) {
  174. p->pListNext->pListLast = p->pListLast;
  175. } else {
  176. CG(interned_strings).pListTail = p->pListLast;
  177. }
  178. p = p->pNext;
  179. }
  180. if (p) {
  181. p->pLast = NULL;
  182. }
  183. CG(interned_strings).arBuckets[i] = p;
  184. }
  185. #if ZEND_DEBUG_INTERNED_STRINGS
  186. mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ);
  187. #endif
  188. #endif
  189. }
  190. /*
  191. * Local variables:
  192. * tab-width: 4
  193. * c-basic-offset: 4
  194. * indent-tabs-mode: t
  195. * End:
  196. */