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
19 /* $Id: $ */
20
21 #include "zend.h"
22 #include "zend_globals.h"
23
24 #ifndef ZEND_DEBUG_INTERNED_STRINGS
25 # define ZEND_DEBUG_INTERNED_STRINGS 0
26 #endif
27
28 #if ZEND_DEBUG_INTERNED_STRINGS
29 # include <sys/mman.h>
30 #endif
31
32 ZEND_API const char *(*zend_new_interned_string)(const char *str, int len, int free_src TSRMLS_DC);
33 ZEND_API void (*zend_interned_strings_snapshot)(TSRMLS_D);
34 ZEND_API void (*zend_interned_strings_restore)(TSRMLS_D);
35
36 static const char *zend_new_interned_string_int(const char *str, int len, int free_src TSRMLS_DC);
37 static void zend_interned_strings_snapshot_int(TSRMLS_D);
38 static void zend_interned_strings_restore_int(TSRMLS_D);
39
zend_interned_strings_init(TSRMLS_D)40 void zend_interned_strings_init(TSRMLS_D)
41 {
42 #ifndef ZTS
43 size_t size = 1024 * 1024;
44
45 #if ZEND_DEBUG_INTERNED_STRINGS
46 CG(interned_strings_start) = valloc(size);
47 #else
48 CG(interned_strings_start) = malloc(size);
49 #endif
50
51 CG(interned_strings_top) = CG(interned_strings_start);
52 CG(interned_strings_snapshot_top) = CG(interned_strings_start);
53 CG(interned_strings_end) = CG(interned_strings_start) + size;
54
55 zend_hash_init(&CG(interned_strings), 0, NULL, NULL, 1);
56
57 CG(interned_strings).nTableMask = CG(interned_strings).nTableSize - 1;
58 CG(interned_strings).arBuckets = (Bucket **) pecalloc(CG(interned_strings).nTableSize, sizeof(Bucket *), CG(interned_strings).persistent);
59
60 #if ZEND_DEBUG_INTERNED_STRINGS
61 mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ);
62 #endif
63
64 /* interned empty string */
65 CG(interned_empty_string) = zend_new_interned_string_int("", sizeof(""), 0 TSRMLS_CC);
66 #endif
67
68 zend_new_interned_string = zend_new_interned_string_int;
69 zend_interned_strings_snapshot = zend_interned_strings_snapshot_int;
70 zend_interned_strings_restore = zend_interned_strings_restore_int;
71 }
72
zend_interned_strings_dtor(TSRMLS_D)73 void zend_interned_strings_dtor(TSRMLS_D)
74 {
75 #ifndef ZTS
76 #if ZEND_DEBUG_INTERNED_STRINGS
77 mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_WRITE | PROT_READ);
78 #endif
79 free(CG(interned_strings).arBuckets);
80 free(CG(interned_strings_start));
81 #endif
82 }
83
zend_new_interned_string_int(const char * arKey,int nKeyLength,int free_src TSRMLS_DC)84 static const char *zend_new_interned_string_int(const char *arKey, int nKeyLength, int free_src TSRMLS_DC)
85 {
86 #ifndef ZTS
87 ulong h;
88 uint nIndex;
89 Bucket *p;
90
91 if (IS_INTERNED(arKey)) {
92 return arKey;
93 }
94
95 h = zend_inline_hash_func(arKey, nKeyLength);
96 nIndex = h & CG(interned_strings).nTableMask;
97 p = CG(interned_strings).arBuckets[nIndex];
98 while (p != NULL) {
99 if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
100 if (!memcmp(p->arKey, arKey, nKeyLength)) {
101 if (free_src) {
102 efree((void *)arKey);
103 }
104 return p->arKey;
105 }
106 }
107 p = p->pNext;
108 }
109
110 if (CG(interned_strings_top) + ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength) >=
111 CG(interned_strings_end)) {
112 /* no memory */
113 return arKey;
114 }
115
116 p = (Bucket *) CG(interned_strings_top);
117 CG(interned_strings_top) += ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength);
118
119 #if ZEND_DEBUG_INTERNED_STRINGS
120 mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ | PROT_WRITE);
121 #endif
122
123 p->arKey = (char*)(p+1);
124 memcpy((char*)p->arKey, arKey, nKeyLength);
125 if (free_src) {
126 efree((void *)arKey);
127 }
128 p->nKeyLength = nKeyLength;
129 p->h = h;
130 p->pData = &p->pDataPtr;
131 p->pDataPtr = p;
132
133 p->pNext = CG(interned_strings).arBuckets[nIndex];
134 p->pLast = NULL;
135 if (p->pNext) {
136 p->pNext->pLast = p;
137 }
138
139 HANDLE_BLOCK_INTERRUPTIONS();
140
141 p->pListLast = CG(interned_strings).pListTail;
142 CG(interned_strings).pListTail = p;
143 p->pListNext = NULL;
144 if (p->pListLast != NULL) {
145 p->pListLast->pListNext = p;
146 }
147 if (!CG(interned_strings).pListHead) {
148 CG(interned_strings).pListHead = p;
149 }
150
151 CG(interned_strings).arBuckets[nIndex] = p;
152
153 HANDLE_UNBLOCK_INTERRUPTIONS();
154
155 CG(interned_strings).nNumOfElements++;
156
157 if (CG(interned_strings).nNumOfElements > CG(interned_strings).nTableSize) {
158 if ((CG(interned_strings).nTableSize << 1) > 0) { /* Let's double the table size */
159 Bucket **t = (Bucket **) perealloc_recoverable(CG(interned_strings).arBuckets, (CG(interned_strings).nTableSize << 1) * sizeof(Bucket *), CG(interned_strings).persistent);
160
161 if (t) {
162 HANDLE_BLOCK_INTERRUPTIONS();
163 CG(interned_strings).arBuckets = t;
164 CG(interned_strings).nTableSize = (CG(interned_strings).nTableSize << 1);
165 CG(interned_strings).nTableMask = CG(interned_strings).nTableSize - 1;
166 zend_hash_rehash(&CG(interned_strings));
167 HANDLE_UNBLOCK_INTERRUPTIONS();
168 }
169 }
170 }
171
172 #if ZEND_DEBUG_INTERNED_STRINGS
173 mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ);
174 #endif
175
176 return p->arKey;
177 #else
178 return arKey;
179 #endif
180 }
181
zend_interned_strings_snapshot_int(TSRMLS_D)182 static void zend_interned_strings_snapshot_int(TSRMLS_D)
183 {
184 CG(interned_strings_snapshot_top) = CG(interned_strings_top);
185 }
186
zend_interned_strings_restore_int(TSRMLS_D)187 static void zend_interned_strings_restore_int(TSRMLS_D)
188 {
189 #ifndef ZTS
190 Bucket *p;
191 int i;
192 #endif
193
194 CG(interned_strings_top) = CG(interned_strings_snapshot_top);
195
196 #ifndef ZTS
197 #if ZEND_DEBUG_INTERNED_STRINGS
198 mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_WRITE | PROT_READ);
199 #endif
200
201 for (i = 0; i < CG(interned_strings).nTableSize; i++) {
202 p = CG(interned_strings).arBuckets[i];
203 while (p && p->arKey > CG(interned_strings_top)) {
204 CG(interned_strings).nNumOfElements--;
205 if (p->pListLast != NULL) {
206 p->pListLast->pListNext = p->pListNext;
207 } else {
208 CG(interned_strings).pListHead = p->pListNext;
209 }
210 if (p->pListNext != NULL) {
211 p->pListNext->pListLast = p->pListLast;
212 } else {
213 CG(interned_strings).pListTail = p->pListLast;
214 }
215 p = p->pNext;
216 }
217 if (p) {
218 p->pLast = NULL;
219 }
220 CG(interned_strings).arBuckets[i] = p;
221 }
222
223 #if ZEND_DEBUG_INTERNED_STRINGS
224 mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ);
225 #endif
226 #endif
227 }
228
229 /*
230 * Local variables:
231 * tab-width: 4
232 * c-basic-offset: 4
233 * indent-tabs-mode: t
234 * End:
235 */
236