Example #1
0
static void zend_hash_persist(HashTable *ht, zend_persist_func_t pPersistElement)
{
	uint32_t idx, nIndex;
	Bucket *p;

	if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
		HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
		return;
	}
	if (ht->nNumUsed == 0) {
		efree(HT_GET_DATA_ADDR(ht));
		ht->nTableMask = HT_MIN_MASK;
		HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
		ht->u.flags &= ~HASH_FLAG_INITIALIZED;
		return;
	}
	if (ht->u.flags & HASH_FLAG_PACKED) {
		void *data = HT_GET_DATA_ADDR(ht);
		zend_accel_store(data, HT_USED_SIZE(ht));
		HT_SET_DATA_ADDR(ht, data);
	} else if (ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 2) {
		/* compact table */
		void *old_data = HT_GET_DATA_ADDR(ht);
		Bucket *old_buckets = ht->arData;
		uint32_t hash_size;

		if (ht->nNumUsed <= HT_MIN_SIZE) {
			hash_size = HT_MIN_SIZE;
		} else {
			hash_size = (uint32_t)(-(int32_t)ht->nTableMask);
			while (hash_size >> 1 > ht->nNumUsed) {
				hash_size >>= 1;
			}
		}
		ht->nTableMask = (uint32_t)(-(int32_t)hash_size);
		ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
		HT_SET_DATA_ADDR(ht, ZCG(mem));
		ZCG(mem) = (void*)((char*)ZCG(mem) + ZEND_ALIGNED_SIZE((hash_size * sizeof(uint32_t)) + (ht->nNumUsed * sizeof(Bucket))));
		HT_HASH_RESET(ht);
		memcpy(ht->arData, old_buckets, ht->nNumUsed * sizeof(Bucket));
		efree(old_data);

		for (idx = 0; idx < ht->nNumUsed; idx++) {
			p = ht->arData + idx;
			if (Z_TYPE(p->val) == IS_UNDEF) continue;

			/* persist bucket and key */
			if (p->key) {
				zend_accel_store_interned_string(p->key);
			}

			/* persist the data itself */
			pPersistElement(&p->val);

			nIndex = p->h | ht->nTableMask;
			Z_NEXT(p->val) = HT_HASH(ht, nIndex);
			HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
		}
		return;
	} else {
Example #2
0
static zend_always_inline zval *_zend_hash_add_or_update_i(HashTable *ht, zend_string *key, zval *pData, uint32_t flag ZEND_FILE_LINE_DC)
{
	zend_ulong h;
	uint32_t nIndex;
	uint32_t idx;
	Bucket *p;

	IS_CONSISTENT(ht);

	if (UNEXPECTED(ht->nTableMask == 0)) {
		CHECK_INIT(ht, 0);
		goto add_to_hash; 
	} else if (ht->u.flags & HASH_FLAG_PACKED) {
		zend_hash_packed_to_hash(ht);
	} else 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 */

add_to_hash:
	HANDLE_BLOCK_INTERRUPTIONS();
	idx = ht->nNumUsed++;
	ht->nNumOfElements++;
	if (ht->nInternalPointer == INVALID_IDX) {
		ht->nInternalPointer = idx;
	}
	p = ht->arData + idx; 
	p->h = h = zend_string_hash_val(key);
	p->key = key;
	zend_string_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;
}
static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class_entry *old_ce, zend_class_entry *ce)
{
	uint idx;
	Bucket *p, *q;
	zend_ulong nIndex;
	zend_op_array *new_entry;

	ht->nTableSize = source->nTableSize;
	ht->nTableMask = source->nTableMask;
	ht->nNumUsed = 0;
	ht->nNumOfElements = source->nNumOfElements;
	ht->nNextFreeElement = source->nNextFreeElement;
	ht->pDestructor = ZEND_FUNCTION_DTOR;
	ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED);
	ht->nInternalPointer = source->nNumOfElements ? 0 : INVALID_IDX;

	if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
		ht->arHash = (uint32_t*)&uninitialized_bucket;
		return;
	}

	ZEND_ASSERT(!(source->u.flags & HASH_FLAG_PACKED));
	ht->arData = (Bucket *) emalloc(ht->nTableSize * (sizeof(Bucket) + sizeof(uint32_t)));
	ht->arHash = (uint32_t *)(ht->arData + ht->nTableSize);
	memset(ht->arHash, INVALID_IDX, sizeof(uint32_t) * ht->nTableSize);

	for (idx = 0; idx < source->nNumUsed; idx++) {
		p = source->arData + idx;
		if (Z_TYPE(p->val) == IS_UNDEF) continue;

		nIndex = p->h & ht->nTableMask;

		/* Insert into hash collision list */
		q = ht->arData + ht->nNumUsed;
		Z_NEXT(q->val) = ht->arHash[nIndex];
		ht->arHash[nIndex] = ht->nNumUsed++;

		/* Initialize key */
		q->h = p->h;
		ZEND_ASSERT(p->key != NULL);
		q->key = zend_clone_str(p->key);

		/* Copy data */
		ZVAL_PTR(&q->val, ARENA_REALLOC(Z_PTR(p->val)));
		new_entry = (zend_op_array*)Z_PTR(q->val);

		if ((void*)new_entry->scope >= ZCG(current_persistent_script)->arena_mem &&
		    (void*)new_entry->scope < (void*)((char*)ZCG(current_persistent_script)->arena_mem + ZCG(current_persistent_script)->arena_size)) {

			new_entry->scope = ARENA_REALLOC(new_entry->scope);

			/* update prototype */
			if (new_entry->prototype) {
				new_entry->prototype = ARENA_REALLOC(new_entry->prototype);
			}
		}
	}
}
Example #4
0
static zend_always_inline int apc_array_dup_element(apc_context_t *ctxt, HashTable *source, HashTable *target, uint32_t idx, Bucket *p, Bucket *q, int packed, int static_keys, int with_holes)
{
	zval *data = &p->val;

	if (with_holes) {
		if (!packed && Z_TYPE_INFO_P(data) == IS_INDIRECT) {
			data = Z_INDIRECT_P(data);
		}
		if (UNEXPECTED(Z_TYPE_INFO_P(data) == IS_UNDEF)) {
			return 0;
		}
	} else if (!packed) {
		/* INDIRECT element may point to UNDEF-ined slots */
		if (Z_TYPE_INFO_P(data) == IS_INDIRECT) {
			data = Z_INDIRECT_P(data);
			if (UNEXPECTED(Z_TYPE_INFO_P(data) == IS_UNDEF)) {
				return 0;
			}
		}
	}

	do {
		if (Z_OPT_REFCOUNTED_P(data)) {
			if (Z_ISREF_P(data) && Z_REFCOUNT_P(data) == 1 &&
				(Z_TYPE_P(Z_REFVAL_P(data)) != IS_ARRAY ||
				  Z_ARRVAL_P(Z_REFVAL_P(data)) != source)) {
				data = Z_REFVAL_P(data);
				if (!Z_OPT_REFCOUNTED_P(data)) {
					break;
				}
			}
		}
	} while (0);

	my_copy_zval(&q->val, data, ctxt);

	q->h = p->h;
	if (packed) {
		q->key = NULL;
	} else {
		uint32_t nIndex;

		q->key = p->key;
		if (!static_keys && q->key) {
			if (ctxt->copy == APC_COPY_IN) {
				q->key = apc_pstrcpy(q->key, ctxt->pool);
			} else q->key = p->key;
		}

		nIndex = q->h | target->nTableMask;
		Z_NEXT(q->val) = HT_HASH(target, nIndex);
		HT_HASH(target, nIndex) = HT_IDX_TO_HASH(idx);
	}
	return 1;
}
Example #5
0
static zend_always_inline Bucket *zend_hash_index_find_bucket(const HashTable *ht, zend_uint_t h)
{
	uint nIndex;
	uint idx;
	Bucket *p;

	nIndex = h & ht->nTableMask;
	idx = ht->arHash[nIndex];
	while (idx != INVALID_IDX) {
		ZEND_ASSERT(idx < ht->nTableSize);
		p = ht->arData + idx;
		if (p->h == h && !p->key) {
			return p;
		}
		idx = Z_NEXT(p->val);
	}
	return NULL;
}
Example #6
0
static zend_always_inline zend_string *zend_interned_string_ht_lookup_ex(zend_ulong h, const char *str, size_t size, HashTable *interned_strings)
{
	uint32_t nIndex;
	uint32_t idx;
	Bucket *p;

	nIndex = h | interned_strings->nTableMask;
	idx = HT_HASH(interned_strings, nIndex);
	while (idx != HT_INVALID_IDX) {
		p = HT_HASH_TO_BUCKET(interned_strings, idx);
		if ((p->h == h) && (ZSTR_LEN(p->key) == size)) {
			if (!memcmp(ZSTR_VAL(p->key), str, size)) {
				return p->key;
			}
		}
		idx = Z_NEXT(p->val);
	}

	return NULL;
}
Example #7
0
static zend_always_inline Bucket *zend_hash_str_find_bucket(const HashTable *ht, const char *str, int len, zend_uint_t h)
{
	uint nIndex;
	uint idx;
	Bucket *p;

	nIndex = h & ht->nTableMask;
	idx = ht->arHash[nIndex];
	while (idx != INVALID_IDX) {
		ZEND_ASSERT(idx < ht->nTableSize);
		p = ht->arData + idx;
		if ((p->h == h) 
			 && p->key
			 && (p->key->len == len)
			 && !memcmp(p->key->val, str, len)) {
			return p;
		}
		idx = Z_NEXT(p->val);
	}
	return NULL;
}
Example #8
0
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 void zend_hash_clone_prop_info(HashTable *ht, HashTable *source, zend_class_entry *old_ce)
{
	uint idx;
	Bucket *p, *q;
	zend_ulong nIndex;
	zend_property_info *prop_info;

	ht->nTableSize = source->nTableSize;
	ht->nTableMask = source->nTableMask;
	ht->nNumUsed = 0;
	ht->nNumOfElements = source->nNumOfElements;
	ht->nNextFreeElement = source->nNextFreeElement;
	ht->pDestructor = NULL;
	ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED);
	ht->nInternalPointer = source->nNumOfElements ? 0 : INVALID_IDX;

	if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
		ht->arHash = (uint32_t*)&uninitialized_bucket;
		return;
	}

	ZEND_ASSERT(!(source->u.flags & HASH_FLAG_PACKED));
	ht->arData = (Bucket *) emalloc(ht->nTableSize * (sizeof(Bucket) + sizeof(uint32_t)));
	ht->arHash = (uint32_t*)(ht->arData + ht->nTableSize);
	memset(ht->arHash, INVALID_IDX, sizeof(uint32_t) * ht->nTableSize);

	for (idx = 0; idx < source->nNumUsed; idx++) {
		p = source->arData + idx;
		if (Z_TYPE(p->val) == IS_UNDEF) continue;

		nIndex = p->h & ht->nTableMask;

		/* Insert into hash collision list */
		q = ht->arData + ht->nNumUsed;
		Z_NEXT(q->val) = ht->arHash[nIndex];
		ht->arHash[nIndex] = ht->nNumUsed++;

		/* Initialize key */
		q->h = p->h;
		ZEND_ASSERT(p->key != NULL);
		q->key = zend_clone_str(p->key);

		/* Copy data */
		prop_info = ARENA_REALLOC(Z_PTR(p->val));
		ZVAL_PTR(&q->val, prop_info);

		if (prop_info->ce == old_ce || (prop_info->flags & ZEND_ACC_SHADOW)) {
			/* Copy constructor */
			prop_info->name = zend_clone_str(prop_info->name);
			if (prop_info->doc_comment) {
				if (ZCG(accel_directives).load_comments) {
					prop_info->doc_comment = zend_string_dup(prop_info->doc_comment, 0);
				} else {
					prop_info->doc_comment = NULL;
				}
			}
			prop_info->ce = ARENA_REALLOC(prop_info->ce);
		} else if ((void*)prop_info->ce >= ZCG(current_persistent_script)->arena_mem &&
		           (void*)prop_info->ce < (void*)((char*)ZCG(current_persistent_script)->arena_mem + ZCG(current_persistent_script)->arena_size)) {
			prop_info->ce = ARENA_REALLOC(prop_info->ce);
		}
	}
}
static void zend_hash_clone_zval(HashTable *ht, HashTable *source, int bind)
{
	uint idx;
	Bucket *p, *q, *r;
	zend_ulong nIndex;

	ht->nTableSize = source->nTableSize;
	ht->nTableMask = source->nTableMask;
	ht->nNumUsed = 0;
	ht->nNumOfElements = source->nNumOfElements;
	ht->nNextFreeElement = source->nNextFreeElement;
	ht->pDestructor = ZVAL_PTR_DTOR;
	ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED) | HASH_FLAG_APPLY_PROTECTION;
	ht->arData = NULL;
	ht->arHash = NULL;
	ht->nInternalPointer = source->nNumOfElements ? 0 : INVALID_IDX;

	if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
		ht->arHash = (uint32_t*)&uninitialized_bucket;
		return;
	}

	if (source->u.flags & HASH_FLAG_PACKED) {
		ht->u.flags |= HASH_FLAG_PACKED;
		ht->arData = (Bucket *) emalloc(ht->nTableSize * sizeof(Bucket));
		ht->arHash = (uint32_t*)&uninitialized_bucket;

		for (idx = 0; idx < source->nNumUsed; idx++) {
			p = source->arData + idx;
			if (Z_TYPE(p->val) == IS_UNDEF) continue;
			nIndex = p->h & ht->nTableMask;

			r = ht->arData + ht->nNumUsed;
			q = ht->arData + p->h;
			while (r != q) {
				ZVAL_UNDEF(&r->val);
				r++;
			}
			ht->nNumUsed = p->h + 1;

			/* Initialize key */
			q->h = p->h;
			q->key = NULL;

			/* Copy data */
			ZVAL_COPY_VALUE(&q->val, &p->val);
			zend_clone_zval(&q->val, bind);
		}
	} else {
		ht->arData = (Bucket *) emalloc(ht->nTableSize * (sizeof(Bucket) + sizeof(uint32_t)));
		ht->arHash = (uint32_t*)(ht->arData + ht->nTableSize);
		memset(ht->arHash, INVALID_IDX, sizeof(uint32_t) * ht->nTableSize);

		for (idx = 0; idx < source->nNumUsed; idx++) {
			p = source->arData + idx;
			if (Z_TYPE(p->val) == IS_UNDEF) continue;
			nIndex = p->h & ht->nTableMask;

			/* Insert into hash collision list */
			q = ht->arData + ht->nNumUsed;
			Z_NEXT(q->val) = ht->arHash[nIndex];
			ht->arHash[nIndex] = ht->nNumUsed++;

			/* Initialize key */
			q->h = p->h;
			if (!p->key) {
				q->key = NULL;
			} else {
				q->key = zend_clone_str(p->key);
			}

			/* Copy data */
			ZVAL_COPY_VALUE(&q->val, &p->val);
			zend_clone_zval(&q->val, bind);
		}
	}
}
static void zend_hash_clone_zval(HashTable *ht, HashTable *source, int bind)
{
	uint idx;
	Bucket *p, *q, *r;
	zend_ulong nIndex;

	ht->nTableSize = source->nTableSize;
	ht->nTableMask = source->nTableMask;
	ht->nNumUsed = 0;
	ht->nNumOfElements = source->nNumOfElements;
	ht->nNextFreeElement = source->nNextFreeElement;
	ht->pDestructor = ZVAL_PTR_DTOR;
	ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED) | HASH_FLAG_APPLY_PROTECTION;
	ht->nInternalPointer = source->nNumOfElements ? 0 : HT_INVALID_IDX;

	if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
		ht->arData = source->arData;
		return;
	}

	if (source->u.flags & HASH_FLAG_PACKED) {
		ht->u.flags |= HASH_FLAG_PACKED;
		HT_SET_DATA_ADDR(ht, (Bucket *) emalloc(HT_SIZE(ht)));
		HT_HASH_RESET_PACKED(ht);

		for (idx = 0; idx < source->nNumUsed; idx++) {
			p = source->arData + idx;
			if (Z_TYPE(p->val) == IS_UNDEF) continue;
			nIndex = p->h | ht->nTableMask;

			r = ht->arData + ht->nNumUsed;
			q = ht->arData + p->h;
			while (r != q) {
				ZVAL_UNDEF(&r->val);
				r++;
			}
			ht->nNumUsed = p->h + 1;

			/* Initialize key */
			q->h = p->h;
			q->key = NULL;

			/* Copy data */
			ZVAL_COPY_VALUE(&q->val, &p->val);
			zend_clone_zval(&q->val, bind);
		}
	} else {
		HT_SET_DATA_ADDR(ht, emalloc(HT_SIZE(ht)));
		HT_HASH_RESET(ht);

		for (idx = 0; idx < source->nNumUsed; idx++) {
			p = source->arData + idx;
			if (Z_TYPE(p->val) == IS_UNDEF) continue;
			nIndex = p->h | ht->nTableMask;

			/* Insert into hash collision list */
			q = ht->arData + ht->nNumUsed;
			Z_NEXT(q->val) = HT_HASH(ht, nIndex);
			HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(ht->nNumUsed++);

			/* Initialize key */
			q->h = p->h;
			if (!p->key) {
				q->key = NULL;
			} else {
				q->key = zend_clone_str(p->key);
			}

			/* Copy data */
			ZVAL_COPY_VALUE(&q->val, &p->val);
			zend_clone_zval(&q->val, bind);
		}
	}
}
Example #12
0
static void zend_hash_persist(HashTable *ht, zend_persist_func_t pPersistElement)
{
	uint32_t idx, nIndex;
	Bucket *p;

	HT_FLAGS(ht) |= HASH_FLAG_STATIC_KEYS;
	ht->pDestructor = NULL;
	ht->nInternalPointer = 0;

	if (HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) {
		if (EXPECTED(!ZCG(current_persistent_script)->corrupted)) {
			HT_SET_DATA_ADDR(ht, &ZCSG(uninitialized_bucket));
		} else {
			HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
		}
		return;
	}
	if (ht->nNumUsed == 0) {
		efree(HT_GET_DATA_ADDR(ht));
		ht->nTableMask = HT_MIN_MASK;
		if (EXPECTED(!ZCG(current_persistent_script)->corrupted)) {
			HT_SET_DATA_ADDR(ht, &ZCSG(uninitialized_bucket));
		} else {
			HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
		}
		HT_FLAGS(ht) |= HASH_FLAG_UNINITIALIZED;
		return;
	}
	if (HT_FLAGS(ht) & HASH_FLAG_PACKED) {
		void *data = HT_GET_DATA_ADDR(ht);
		data = zend_shared_memdup_free(data, HT_USED_SIZE(ht));
		HT_SET_DATA_ADDR(ht, data);
	} else if (ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 4) {
		/* compact table */
		void *old_data = HT_GET_DATA_ADDR(ht);
		Bucket *old_buckets = ht->arData;
		uint32_t hash_size;

		if (ht->nNumUsed <= HT_MIN_SIZE) {
			hash_size = HT_MIN_SIZE * 2;
		} else {
			hash_size = (uint32_t)(-(int32_t)ht->nTableMask);
			while (hash_size >> 2 > ht->nNumUsed) {
				hash_size >>= 1;
			}
		}
		ht->nTableMask = (uint32_t)(-(int32_t)hash_size);
		ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
		HT_SET_DATA_ADDR(ht, ZCG(mem));
		ZCG(mem) = (void*)((char*)ZCG(mem) + ZEND_ALIGNED_SIZE((hash_size * sizeof(uint32_t)) + (ht->nNumUsed * sizeof(Bucket))));
		HT_HASH_RESET(ht);
		memcpy(ht->arData, old_buckets, ht->nNumUsed * sizeof(Bucket));
		efree(old_data);

		for (idx = 0; idx < ht->nNumUsed; idx++) {
			p = ht->arData + idx;
			if (Z_TYPE(p->val) == IS_UNDEF) continue;

			/* persist bucket and key */
			if (p->key) {
				zend_accel_store_interned_string(p->key);
			}

			/* persist the data itself */
			pPersistElement(&p->val);

			nIndex = p->h | ht->nTableMask;
			Z_NEXT(p->val) = HT_HASH(ht, nIndex);
			HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
		}
		return;
	} else {