void zend_interned_strings_init(TSRMLS_D) { zend_string *str; #ifndef ZTS zend_hash_init(&CG(interned_strings), 1024, 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), 1); CG(interned_strings).arHash = (zend_uint*) pecalloc(CG(interned_strings).nTableSize, sizeof(zend_uint), 1); 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_HASH_VAL(str); str->gc.u.v.flags |= IS_STR_INTERNED; CG(empty_string) = str; #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; zend_interned_strings_restore = zend_interned_strings_restore_int; }
static zend_always_inline Bucket *zend_hash_find_bucket(const HashTable *ht, zend_string *key) { zend_uint_t h; uint nIndex; uint idx; Bucket *p; h = STR_HASH_VAL(key); nIndex = h & ht->nTableMask; idx = ht->arHash[nIndex]; while (idx != INVALID_IDX) { p = ht->arData + idx; if ((p->key == key) || /* check for the the same interned string */ (p->h == h && p->key && p->key->len == key->len && memcmp(p->key->val, key->val, key->len) == 0)) { return p; } idx = Z_NEXT(p->val); } return NULL; }
static zend_always_inline zval *_zend_hash_add_or_update_i(HashTable *ht, zend_string *key, zval *pData, int flag ZEND_FILE_LINE_DC) { zend_uint_t h; uint nIndex; uint idx; Bucket *p; #ifdef ZEND_SIGNALS TSRMLS_FETCH(); #endif IS_CONSISTENT(ht); CHECK_INIT(ht, 0); if (ht->u.flags & HASH_FLAG_PACKED) { zend_hash_packed_to_hash(ht); } h = STR_HASH_VAL(key); if ((flag & HASH_ADD_NEW) == 0) { p = zend_hash_find_bucket(ht, key); if (p) { zval *data; if (flag & HASH_ADD) { return NULL; } ZEND_ASSERT(&p->val != pData); data = &p->val; if ((flag & HASH_UPDATE_INDIRECT) && Z_TYPE_P(data) == IS_INDIRECT) { data = Z_INDIRECT_P(data); } HANDLE_BLOCK_INTERRUPTIONS(); if (ht->pDestructor) { ht->pDestructor(data); } ZVAL_COPY_VALUE(data, pData); HANDLE_UNBLOCK_INTERRUPTIONS(); return data; } } ZEND_HASH_IF_FULL_DO_RESIZE(ht); /* If the Hash table is full, resize it */ HANDLE_BLOCK_INTERRUPTIONS(); idx = ht->nNumUsed++; ht->nNumOfElements++; if (ht->nInternalPointer == INVALID_IDX) { ht->nInternalPointer = idx; } p = ht->arData + idx; p->h = h; p->key = key; STR_ADDREF(key); ZVAL_COPY_VALUE(&p->val, pData); nIndex = h & ht->nTableMask; Z_NEXT(p->val) = ht->arHash[nIndex]; ht->arHash[nIndex] = idx; HANDLE_UNBLOCK_INTERRUPTIONS(); return &p->val; }