mirror of
https://github.com/php/php-src.git
synced 2024-11-24 10:24:11 +08:00
221 lines
6.8 KiB
C
221 lines
6.8 KiB
C
/*
|
|
+----------------------------------------------------------------------+
|
|
| Zend Engine |
|
|
+----------------------------------------------------------------------+
|
|
| 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 |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.zend.com/license/2_00.txt. |
|
|
| If you did not receive a copy of the Zend license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@zend.com so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Authors: Dmitry Stogov <dmitry@zend.com> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
/* $Id: $ */
|
|
|
|
#include "zend.h"
|
|
#include "zend_globals.h"
|
|
|
|
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 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);
|
|
|
|
ZEND_API zend_ulong zend_hash_func(const char *str, uint len)
|
|
{
|
|
return zend_inline_hash_func(str, len);
|
|
}
|
|
|
|
static void _str_dtor(zval *zv)
|
|
{
|
|
zend_string *str = Z_STR_P(zv);
|
|
str->gc.u.v.flags &= ~IS_STR_INTERNED;
|
|
str->gc.refcount = 1;
|
|
}
|
|
|
|
void zend_interned_strings_init(TSRMLS_D)
|
|
{
|
|
#ifndef ZTS
|
|
zend_string *str;
|
|
|
|
zend_hash_init(&CG(interned_strings), 0, NULL, _str_dtor, 1);
|
|
|
|
CG(interned_strings).nTableMask = CG(interned_strings).nTableSize - 1;
|
|
CG(interned_strings).arData = (Bucket*) pecalloc(CG(interned_strings).nTableSize, sizeof(Bucket), CG(interned_strings).flags & HASH_FLAG_PERSISTENT);
|
|
CG(interned_strings).arHash = (zend_uint*) pecalloc(CG(interned_strings).nTableSize, sizeof(zend_uint), CG(interned_strings).flags & HASH_FLAG_PERSISTENT);
|
|
memset(CG(interned_strings).arHash, INVALID_IDX, CG(interned_strings).nTableSize * sizeof(zend_uint));
|
|
|
|
/* interned empty string */
|
|
str = STR_ALLOC(sizeof("")-1, 1);
|
|
str->val[0] = '\000';
|
|
CG(empty_string) = zend_new_interned_string_int(str TSRMLS_CC);
|
|
#else
|
|
str = STR_ALLOC(sizeof("")-1, 1);
|
|
str->val[0] = '\000';
|
|
str->gc.u.v.flags |= IS_STR_INTERNED;
|
|
CG(empty_string) = str;
|
|
#endif
|
|
|
|
zend_new_interned_string = zend_new_interned_string_int;
|
|
zend_interned_strings_snapshot = zend_interned_strings_snapshot_int;
|
|
zend_interned_strings_restore = zend_interned_strings_restore_int;
|
|
}
|
|
|
|
void zend_interned_strings_dtor(TSRMLS_D)
|
|
{
|
|
#ifndef ZTS
|
|
zend_hash_destroy(&CG(interned_strings));
|
|
//??? free(CG(interned_strings).arData);
|
|
//??? free(CG(interned_strings).arHash);
|
|
#endif
|
|
}
|
|
|
|
static zend_string *zend_new_interned_string_int(zend_string *str TSRMLS_DC)
|
|
{
|
|
#ifndef ZTS
|
|
ulong h;
|
|
uint nIndex;
|
|
uint idx;
|
|
Bucket *p;
|
|
|
|
if (IS_INTERNED(str)) {
|
|
return str;
|
|
}
|
|
|
|
h = STR_HASH_VAL(str);
|
|
nIndex = h & CG(interned_strings).nTableMask;
|
|
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)) {
|
|
STR_RELEASE(str);
|
|
return p->key;
|
|
}
|
|
}
|
|
idx = p->val.u.next;
|
|
}
|
|
|
|
str->gc.refcount = 1;
|
|
// str->gc.u.v.type = IS_INTERNED_STRING;
|
|
str->gc.u.v.flags |= IS_STR_INTERNED;
|
|
|
|
//??? if (CG(interned_strings_top) + ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength) >=
|
|
//??? CG(interned_strings_end)) {
|
|
//??? /* no memory */
|
|
//??? return arKey;
|
|
//??? }
|
|
|
|
//??? info = (zend_string_info*) CG(interned_strings_top);
|
|
//??? CG(interned_strings_top) += ZEND_MM_ALIGNED_SIZE(sizeof(zend_string_info) + nKeyLength);
|
|
|
|
//??? memcpy((char*)(info+1), arKey, nKeyLength);
|
|
//??? if (free_src) {
|
|
//??? efree((void *)arKey);
|
|
//??? }
|
|
//??? info->nKeyLength = nKeyLength;
|
|
//??? info->h = h;
|
|
|
|
if (CG(interned_strings).nNumUsed >= CG(interned_strings).nTableSize) {
|
|
if ((CG(interned_strings).nTableSize << 1) > 0) { /* Let's double the table size */
|
|
Bucket *d = (Bucket *) perealloc_recoverable(CG(interned_strings).arData, (CG(interned_strings).nTableSize << 1) * sizeof(Bucket), CG(interned_strings).flags & HASH_FLAG_PERSISTENT);
|
|
zend_uint *h = (zend_uint *) perealloc_recoverable(CG(interned_strings).arHash, (CG(interned_strings).nTableSize << 1) * sizeof(zend_uint), CG(interned_strings).flags & HASH_FLAG_PERSISTENT);
|
|
|
|
if (d && h) {
|
|
HANDLE_BLOCK_INTERRUPTIONS();
|
|
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));
|
|
HANDLE_UNBLOCK_INTERRUPTIONS();
|
|
}
|
|
}
|
|
}
|
|
|
|
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(p->val) = IS_STRING;
|
|
nIndex = h & CG(interned_strings).nTableMask;
|
|
p->val.u.next = CG(interned_strings).arHash[nIndex];
|
|
CG(interned_strings).arHash[nIndex] = idx;
|
|
|
|
HANDLE_UNBLOCK_INTERRUPTIONS();
|
|
|
|
return str;
|
|
#else
|
|
return str;
|
|
#endif
|
|
}
|
|
|
|
static void zend_interned_strings_snapshot_int(TSRMLS_D)
|
|
{
|
|
#ifndef ZTS
|
|
uint idx;
|
|
Bucket *p;
|
|
|
|
idx = CG(interned_strings).nNumUsed;
|
|
while (idx > 0) {
|
|
idx--;
|
|
p = CG(interned_strings).arData + idx;
|
|
ZEND_ASSERT(p->key->gc.u.v.flags & IS_STR_PERSISTENT);
|
|
p->key->gc.u.v.flags |= IS_STR_PERMANENT;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void zend_interned_strings_restore_int(TSRMLS_D)
|
|
{
|
|
#ifndef ZTS
|
|
uint nIndex;
|
|
uint idx;
|
|
Bucket *p;
|
|
|
|
idx = CG(interned_strings).nNumUsed;
|
|
while (idx > 0) {
|
|
idx--;
|
|
p = CG(interned_strings).arData + idx;
|
|
if (p->key->gc.u.v.flags & IS_STR_PERMANENT) break;
|
|
CG(interned_strings).nNumUsed--;
|
|
CG(interned_strings).nNumOfElements--;
|
|
|
|
p->key->gc.u.v.flags &= ~IS_STR_INTERNED;
|
|
p->key->gc.refcount = 1;
|
|
STR_FREE(p->key);
|
|
|
|
nIndex = p->h & CG(interned_strings).nTableMask;
|
|
if (CG(interned_strings).arHash[nIndex] == idx) {
|
|
CG(interned_strings).arHash[nIndex] = p->val.u.next;
|
|
} else {
|
|
uint prev = CG(interned_strings).arHash[nIndex];
|
|
while (CG(interned_strings).arData[prev].val.u.next != idx) {
|
|
prev = CG(interned_strings).arData[prev].val.u.next;
|
|
}
|
|
CG(interned_strings).arData[prev].val.u.next = p->val.u.next;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* tab-width: 4
|
|
* c-basic-offset: 4
|
|
* indent-tabs-mode: t
|
|
* End:
|
|
*/
|