summaryrefslogtreecommitdiff
path: root/Zend/zend_string.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_string.c')
-rw-r--r--Zend/zend_string.c240
1 files changed, 104 insertions, 136 deletions
diff --git a/Zend/zend_string.c b/Zend/zend_string.c
index ff7ee3fd81..1833bbd241 100644
--- a/Zend/zend_string.c
+++ b/Zend/zend_string.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2013 Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright (c) 1998-2014 Zend Technologies Ltd. (http://www.zend.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 2.00 of the Zend license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -21,47 +21,48 @@
#include "zend.h"
#include "zend_globals.h"
-#ifndef ZEND_DEBUG_INTERNED_STRINGS
-# define ZEND_DEBUG_INTERNED_STRINGS 0
-#endif
-
-#if ZEND_DEBUG_INTERNED_STRINGS
-# include <sys/mman.h>
-#endif
-
-ZEND_API const char *(*zend_new_interned_string)(const char *str, int len, int free_src TSRMLS_DC);
+ZEND_API zend_string *(*zend_new_interned_string)(zend_string *str TSRMLS_DC);
ZEND_API void (*zend_interned_strings_snapshot)(TSRMLS_D);
ZEND_API void (*zend_interned_strings_restore)(TSRMLS_D);
-static const char *zend_new_interned_string_int(const char *str, int len, int free_src TSRMLS_DC);
+static zend_string *zend_new_interned_string_int(zend_string *str TSRMLS_DC);
static void zend_interned_strings_snapshot_int(TSRMLS_D);
static void zend_interned_strings_restore_int(TSRMLS_D);
-void zend_interned_strings_init(TSRMLS_D)
+ZEND_API zend_ulong zend_hash_func(const char *str, size_t len)
{
-#ifndef ZTS
- size_t size = 1024 * 1024;
+ return zend_inline_hash_func(str, len);
+}
-#if ZEND_DEBUG_INTERNED_STRINGS
- CG(interned_strings_start) = valloc(size);
-#else
- CG(interned_strings_start) = malloc(size);
+#ifndef ZTS
+static void _str_dtor(zval *zv)
+{
+ zend_string *str = Z_STR_P(zv);
+ GC_FLAGS(str) &= ~IS_STR_INTERNED;
+ GC_REFCOUNT(str) = 1;
+}
#endif
- CG(interned_strings_top) = CG(interned_strings_start);
- CG(interned_strings_snapshot_top) = CG(interned_strings_start);
- CG(interned_strings_end) = CG(interned_strings_start) + size;
+void zend_interned_strings_init(TSRMLS_D)
+{
+#ifndef ZTS
+ zend_string *str;
- zend_hash_init(&CG(interned_strings), 0, NULL, NULL, 1);
+ zend_hash_init(&CG(interned_strings), 1024, NULL, _str_dtor, 1);
CG(interned_strings).nTableMask = CG(interned_strings).nTableSize - 1;
- CG(interned_strings).arBuckets = (Bucket **) pecalloc(CG(interned_strings).nTableSize, sizeof(Bucket *), CG(interned_strings).persistent);
-
-#if ZEND_DEBUG_INTERNED_STRINGS
- mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ);
+ CG(interned_strings).arData = (Bucket*) pecalloc(CG(interned_strings).nTableSize, sizeof(Bucket), 1);
+ CG(interned_strings).arHash = (uint32_t*) pecalloc(CG(interned_strings).nTableSize, sizeof(uint32_t), 1);
+ memset(CG(interned_strings).arHash, INVALID_IDX, CG(interned_strings).nTableSize * sizeof(uint32_t));
+
+ /* interned empty string */
+ str = zend_string_alloc(sizeof("")-1, 1);
+ str->val[0] = '\000';
+ CG(empty_string) = zend_new_interned_string_int(str TSRMLS_CC);
#endif
-#endif
+ /* one char strings (the actual interned strings are going to be created by ext/opcache) */
+ memset(CG(one_char_string), 0, sizeof(CG(one_char_string)));
zend_new_interned_string = zend_new_interned_string_int;
zend_interned_strings_snapshot = zend_interned_strings_snapshot_int;
@@ -71,94 +72,48 @@ void zend_interned_strings_init(TSRMLS_D)
void zend_interned_strings_dtor(TSRMLS_D)
{
#ifndef ZTS
-#if ZEND_DEBUG_INTERNED_STRINGS
- mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_WRITE | PROT_READ);
-#endif
- free(CG(interned_strings).arBuckets);
- free(CG(interned_strings_start));
+ zend_hash_destroy(&CG(interned_strings));
#endif
}
-static const char *zend_new_interned_string_int(const char *arKey, int nKeyLength, int free_src TSRMLS_DC)
+static zend_string *zend_new_interned_string_int(zend_string *str TSRMLS_DC)
{
#ifndef ZTS
- ulong h;
+ zend_ulong h;
uint nIndex;
+ uint idx;
Bucket *p;
- if (IS_INTERNED(arKey)) {
- return arKey;
+ if (IS_INTERNED(str)) {
+ return str;
}
- h = zend_inline_hash_func(arKey, nKeyLength);
+ h = zend_string_hash_val(str);
nIndex = h & CG(interned_strings).nTableMask;
- p = CG(interned_strings).arBuckets[nIndex];
- while (p != NULL) {
- if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
- if (!memcmp(p->arKey, arKey, nKeyLength)) {
- if (free_src) {
- efree((void *)arKey);
- }
- return p->arKey;
+ idx = CG(interned_strings).arHash[nIndex];
+ while (idx != INVALID_IDX) {
+ p = CG(interned_strings).arData + idx;
+ if ((p->h == h) && (p->key->len == str->len)) {
+ if (!memcmp(p->key->val, str->val, str->len)) {
+ zend_string_release(str);
+ return p->key;
}
}
- p = p->pNext;
- }
-
- if (CG(interned_strings_top) + ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength) >=
- CG(interned_strings_end)) {
- /* no memory */
- return arKey;
+ idx = Z_NEXT(p->val);
}
-
- p = (Bucket *) CG(interned_strings_top);
- CG(interned_strings_top) += ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength);
-
-#if ZEND_DEBUG_INTERNED_STRINGS
- mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ | PROT_WRITE);
-#endif
- p->arKey = (char*)(p+1);
- memcpy((char*)p->arKey, arKey, nKeyLength);
- if (free_src) {
- efree((void *)arKey);
- }
- p->nKeyLength = nKeyLength;
- p->h = h;
- p->pData = &p->pDataPtr;
- p->pDataPtr = p;
-
- p->pNext = CG(interned_strings).arBuckets[nIndex];
- p->pLast = NULL;
- if (p->pNext) {
- p->pNext->pLast = p;
- }
-
- HANDLE_BLOCK_INTERRUPTIONS();
-
- p->pListLast = CG(interned_strings).pListTail;
- CG(interned_strings).pListTail = p;
- p->pListNext = NULL;
- if (p->pListLast != NULL) {
- p->pListLast->pListNext = p;
- }
- if (!CG(interned_strings).pListHead) {
- CG(interned_strings).pListHead = p;
- }
+ GC_REFCOUNT(str) = 1;
+ GC_FLAGS(str) |= IS_STR_INTERNED;
- CG(interned_strings).arBuckets[nIndex] = p;
-
- HANDLE_UNBLOCK_INTERRUPTIONS();
-
- CG(interned_strings).nNumOfElements++;
-
- if (CG(interned_strings).nNumOfElements > CG(interned_strings).nTableSize) {
+ if (CG(interned_strings).nNumUsed >= CG(interned_strings).nTableSize) {
if ((CG(interned_strings).nTableSize << 1) > 0) { /* Let's double the table size */
- Bucket **t = (Bucket **) perealloc_recoverable(CG(interned_strings).arBuckets, (CG(interned_strings).nTableSize << 1) * sizeof(Bucket *), CG(interned_strings).persistent);
+ Bucket *d = (Bucket *) perealloc_recoverable(CG(interned_strings).arData, (CG(interned_strings).nTableSize << 1) * sizeof(Bucket), 1);
+ uint32_t *h = (uint32_t *) perealloc_recoverable(CG(interned_strings).arHash, (CG(interned_strings).nTableSize << 1) * sizeof(uint32_t), 1);
- if (t) {
+ if (d && h) {
HANDLE_BLOCK_INTERRUPTIONS();
- CG(interned_strings).arBuckets = t;
+ CG(interned_strings).arData = d;
+ CG(interned_strings).arHash = h;
CG(interned_strings).nTableSize = (CG(interned_strings).nTableSize << 1);
CG(interned_strings).nTableMask = CG(interned_strings).nTableSize - 1;
zend_hash_rehash(&CG(interned_strings));
@@ -167,60 +122,73 @@ static const char *zend_new_interned_string_int(const char *arKey, int nKeyLengt
}
}
-#if ZEND_DEBUG_INTERNED_STRINGS
- mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ);
-#endif
+ HANDLE_BLOCK_INTERRUPTIONS();
+
+ idx = CG(interned_strings).nNumUsed++;
+ CG(interned_strings).nNumOfElements++;
+ p = CG(interned_strings).arData + idx;
+ p->h = h;
+ p->key = str;
+ Z_STR(p->val) = str;
+ Z_TYPE_INFO(p->val) = IS_INTERNED_STRING_EX;
+ nIndex = h & CG(interned_strings).nTableMask;
+ Z_NEXT(p->val) = CG(interned_strings).arHash[nIndex];
+ CG(interned_strings).arHash[nIndex] = idx;
+
+ HANDLE_UNBLOCK_INTERRUPTIONS();
- return p->arKey;
+ return str;
#else
- return arKey;
+ return str;
#endif
}
static void zend_interned_strings_snapshot_int(TSRMLS_D)
{
- CG(interned_strings_snapshot_top) = CG(interned_strings_top);
+#ifndef ZTS
+ uint idx;
+ Bucket *p;
+
+ idx = CG(interned_strings).nNumUsed;
+ while (idx > 0) {
+ idx--;
+ p = CG(interned_strings).arData + idx;
+ ZEND_ASSERT(GC_FLAGS(p->key) & IS_STR_PERSISTENT);
+ GC_FLAGS(p->key) |= IS_STR_PERMANENT;
+ }
+#endif
}
static void zend_interned_strings_restore_int(TSRMLS_D)
{
#ifndef ZTS
+ uint nIndex;
+ uint idx;
Bucket *p;
- int i;
-#endif
-
- CG(interned_strings_top) = CG(interned_strings_snapshot_top);
-
-#ifndef ZTS
-#if ZEND_DEBUG_INTERNED_STRINGS
- mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_WRITE | PROT_READ);
-#endif
- for (i = 0; i < CG(interned_strings).nTableSize; i++) {
- p = CG(interned_strings).arBuckets[i];
- while (p && p->arKey > CG(interned_strings_top)) {
- CG(interned_strings).nNumOfElements--;
- if (p->pListLast != NULL) {
- p->pListLast->pListNext = p->pListNext;
- } else {
- CG(interned_strings).pListHead = p->pListNext;
- }
- if (p->pListNext != NULL) {
- p->pListNext->pListLast = p->pListLast;
- } else {
- CG(interned_strings).pListTail = p->pListLast;
- }
- p = p->pNext;
- }
- if (p) {
- p->pLast = NULL;
- }
- CG(interned_strings).arBuckets[i] = p;
- }
-
-#if ZEND_DEBUG_INTERNED_STRINGS
- mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ);
-#endif
+ idx = CG(interned_strings).nNumUsed;
+ while (idx > 0) {
+ idx--;
+ p = CG(interned_strings).arData + idx;
+ if (GC_FLAGS(p->key) & IS_STR_PERMANENT) break;
+ CG(interned_strings).nNumUsed--;
+ CG(interned_strings).nNumOfElements--;
+
+ GC_FLAGS(p->key) &= ~IS_STR_INTERNED;
+ GC_REFCOUNT(p->key) = 1;
+ zend_string_free(p->key);
+
+ nIndex = p->h & CG(interned_strings).nTableMask;
+ if (CG(interned_strings).arHash[nIndex] == idx) {
+ CG(interned_strings).arHash[nIndex] = Z_NEXT(p->val);
+ } else {
+ uint prev = CG(interned_strings).arHash[nIndex];
+ while (Z_NEXT(CG(interned_strings).arData[prev].val) != idx) {
+ prev = Z_NEXT(CG(interned_strings).arData[prev].val);
+ }
+ Z_NEXT(CG(interned_strings).arData[prev].val) = Z_NEXT(p->val);
+ }
+ }
#endif
}