1 /*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1998-2014 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 #endif
65
66 zend_new_interned_string = zend_new_interned_string_int;
67 zend_interned_strings_snapshot = zend_interned_strings_snapshot_int;
68 zend_interned_strings_restore = zend_interned_strings_restore_int;
69 }
70
zend_interned_strings_dtor(TSRMLS_D)71 void zend_interned_strings_dtor(TSRMLS_D)
72 {
73 #ifndef ZTS
74 #if ZEND_DEBUG_INTERNED_STRINGS
75 mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_WRITE | PROT_READ);
76 #endif
77 free(CG(interned_strings).arBuckets);
78 free(CG(interned_strings_start));
79 #endif
80 }
81
zend_new_interned_string_int(const char * arKey,int nKeyLength,int free_src TSRMLS_DC)82 static const char *zend_new_interned_string_int(const char *arKey, int nKeyLength, int free_src TSRMLS_DC)
83 {
84 #ifndef ZTS
85 ulong h;
86 uint nIndex;
87 Bucket *p;
88
89 if (IS_INTERNED(arKey)) {
90 return arKey;
91 }
92
93 h = zend_inline_hash_func(arKey, nKeyLength);
94 nIndex = h & CG(interned_strings).nTableMask;
95 p = CG(interned_strings).arBuckets[nIndex];
96 while (p != NULL) {
97 if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
98 if (!memcmp(p->arKey, arKey, nKeyLength)) {
99 if (free_src) {
100 efree((void *)arKey);
101 }
102 return p->arKey;
103 }
104 }
105 p = p->pNext;
106 }
107
108 if (CG(interned_strings_top) + ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength) >=
109 CG(interned_strings_end)) {
110 /* no memory */
111 return arKey;
112 }
113
114 p = (Bucket *) CG(interned_strings_top);
115 CG(interned_strings_top) += ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength);
116
117 #if ZEND_DEBUG_INTERNED_STRINGS
118 mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ | PROT_WRITE);
119 #endif
120
121 p->arKey = (char*)(p+1);
122 memcpy((char*)p->arKey, arKey, nKeyLength);
123 if (free_src) {
124 efree((void *)arKey);
125 }
126 p->nKeyLength = nKeyLength;
127 p->h = h;
128 p->pData = &p->pDataPtr;
129 p->pDataPtr = p;
130
131 p->pNext = CG(interned_strings).arBuckets[nIndex];
132 p->pLast = NULL;
133 if (p->pNext) {
134 p->pNext->pLast = p;
135 }
136
137 HANDLE_BLOCK_INTERRUPTIONS();
138
139 p->pListLast = CG(interned_strings).pListTail;
140 CG(interned_strings).pListTail = p;
141 p->pListNext = NULL;
142 if (p->pListLast != NULL) {
143 p->pListLast->pListNext = p;
144 }
145 if (!CG(interned_strings).pListHead) {
146 CG(interned_strings).pListHead = p;
147 }
148
149 CG(interned_strings).arBuckets[nIndex] = p;
150
151 HANDLE_UNBLOCK_INTERRUPTIONS();
152
153 CG(interned_strings).nNumOfElements++;
154
155 if (CG(interned_strings).nNumOfElements > CG(interned_strings).nTableSize) {
156 if ((CG(interned_strings).nTableSize << 1) > 0) { /* Let's double the table size */
157 Bucket **t = (Bucket **) perealloc_recoverable(CG(interned_strings).arBuckets, (CG(interned_strings).nTableSize << 1) * sizeof(Bucket *), CG(interned_strings).persistent);
158
159 if (t) {
160 HANDLE_BLOCK_INTERRUPTIONS();
161 CG(interned_strings).arBuckets = t;
162 CG(interned_strings).nTableSize = (CG(interned_strings).nTableSize << 1);
163 CG(interned_strings).nTableMask = CG(interned_strings).nTableSize - 1;
164 zend_hash_rehash(&CG(interned_strings));
165 HANDLE_UNBLOCK_INTERRUPTIONS();
166 }
167 }
168 }
169
170 #if ZEND_DEBUG_INTERNED_STRINGS
171 mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ);
172 #endif
173
174 return p->arKey;
175 #else
176 return arKey;
177 #endif
178 }
179
zend_interned_strings_snapshot_int(TSRMLS_D)180 static void zend_interned_strings_snapshot_int(TSRMLS_D)
181 {
182 CG(interned_strings_snapshot_top) = CG(interned_strings_top);
183 }
184
zend_interned_strings_restore_int(TSRMLS_D)185 static void zend_interned_strings_restore_int(TSRMLS_D)
186 {
187 #ifndef ZTS
188 Bucket *p;
189 int i;
190 #endif
191
192 CG(interned_strings_top) = CG(interned_strings_snapshot_top);
193
194 #ifndef ZTS
195 #if ZEND_DEBUG_INTERNED_STRINGS
196 mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_WRITE | PROT_READ);
197 #endif
198
199 for (i = 0; i < CG(interned_strings).nTableSize; i++) {
200 p = CG(interned_strings).arBuckets[i];
201 while (p && p->arKey > CG(interned_strings_top)) {
202 CG(interned_strings).nNumOfElements--;
203 if (p->pListLast != NULL) {
204 p->pListLast->pListNext = p->pListNext;
205 } else {
206 CG(interned_strings).pListHead = p->pListNext;
207 }
208 if (p->pListNext != NULL) {
209 p->pListNext->pListLast = p->pListLast;
210 } else {
211 CG(interned_strings).pListTail = p->pListLast;
212 }
213 p = p->pNext;
214 }
215 if (p) {
216 p->pLast = NULL;
217 }
218 CG(interned_strings).arBuckets[i] = p;
219 }
220
221 #if ZEND_DEBUG_INTERNED_STRINGS
222 mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ);
223 #endif
224 #endif
225 }
226
227 /*
228 * Local variables:
229 * tab-width: 4
230 * c-basic-offset: 4
231 * indent-tabs-mode: t
232 * End:
233 */
234