mirror of
https://github.com/php/php-src.git
synced 2025-01-27 06:03:45 +08:00
Use run-time cache to keep position of dynamic properties in HashTable to access them without hash lookup.
This commit is contained in:
parent
0eeaff09cb
commit
193adbdf30
@ -36,7 +36,6 @@
|
||||
#define DEBUG_OBJECT_HANDLERS 0
|
||||
|
||||
#define ZEND_WRONG_PROPERTY_OFFSET 0
|
||||
#define ZEND_DYNAMIC_PROPERTY_OFFSET ((uint32_t)(-1))
|
||||
|
||||
/* guard flags */
|
||||
#define IN_GET (1<<0)
|
||||
@ -578,8 +577,33 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_
|
||||
}
|
||||
} else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(property_offset))) {
|
||||
if (EXPECTED(zobj->properties != NULL)) {
|
||||
if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(property_offset)) {
|
||||
uint32_t idx = ZEND_DECODE_DYN_PROP_OFFSET(property_offset);
|
||||
|
||||
if (EXPECTED(idx < zobj->properties->nNumUsed)) {
|
||||
Bucket *p = zobj->properties->arData + idx;
|
||||
|
||||
if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) &&
|
||||
(EXPECTED(p->key == Z_STR_P(member)) ||
|
||||
(EXPECTED(p->h == ZSTR_H(Z_STR_P(member))) &&
|
||||
EXPECTED(p->key != NULL) &&
|
||||
EXPECTED(ZSTR_LEN(p->key) == Z_STRLEN_P(member)) &&
|
||||
EXPECTED(memcmp(ZSTR_VAL(p->key), Z_STRVAL_P(member), Z_STRLEN_P(member)) == 0)))) {
|
||||
retval = &p->val;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
CACHE_PTR_EX(cache_slot + 1, (void*)(uintptr_t)ZEND_DYNAMIC_PROPERTY_OFFSET);
|
||||
}
|
||||
retval = zend_hash_find(zobj->properties, Z_STR_P(member));
|
||||
if (EXPECTED(retval)) goto exit;
|
||||
if (EXPECTED(retval)) {
|
||||
if (cache_slot) {
|
||||
uint32_t idx = ((char*)retval - (char*)zobj->properties->arData) / sizeof(Bucket);
|
||||
/* Store "hash slot index" + 2 (NULL is a mark of uninitialized cache slot) */
|
||||
CACHE_PTR_EX(cache_slot + 1, (void*)(uintptr_t)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
} else if (UNEXPECTED(EG(exception))) {
|
||||
retval = &EG(uninitialized_zval);
|
||||
@ -1522,22 +1546,47 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists,
|
||||
goto found;
|
||||
}
|
||||
} else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(property_offset))) {
|
||||
if (EXPECTED(zobj->properties != NULL) &&
|
||||
(value = zend_hash_find(zobj->properties, Z_STR_P(member))) != NULL) {
|
||||
found:
|
||||
switch (has_set_exists) {
|
||||
case 0:
|
||||
ZVAL_DEREF(value);
|
||||
result = (Z_TYPE_P(value) != IS_NULL);
|
||||
break;
|
||||
default:
|
||||
result = zend_is_true(value);
|
||||
break;
|
||||
case 2:
|
||||
result = 1;
|
||||
break;
|
||||
if (EXPECTED(zobj->properties != NULL)) {
|
||||
if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(property_offset)) {
|
||||
uint32_t idx = ZEND_DECODE_DYN_PROP_OFFSET(property_offset);
|
||||
|
||||
if (EXPECTED(idx < zobj->properties->nNumUsed)) {
|
||||
Bucket *p = zobj->properties->arData + idx;
|
||||
|
||||
if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) &&
|
||||
(EXPECTED(p->key == Z_STR_P(member)) ||
|
||||
(EXPECTED(p->h == ZSTR_H(Z_STR_P(member))) &&
|
||||
EXPECTED(p->key != NULL) &&
|
||||
EXPECTED(ZSTR_LEN(p->key) == Z_STRLEN_P(member)) &&
|
||||
EXPECTED(memcmp(ZSTR_VAL(p->key), Z_STRVAL_P(member), Z_STRLEN_P(member)) == 0)))) {
|
||||
value = &p->val;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
CACHE_PTR_EX(cache_slot + 1, (void*)(uintptr_t)ZEND_DYNAMIC_PROPERTY_OFFSET);
|
||||
}
|
||||
value = zend_hash_find(zobj->properties, Z_STR_P(member));
|
||||
if (value) {
|
||||
if (cache_slot) {
|
||||
uint32_t idx = ((char*)value - (char*)zobj->properties->arData) / sizeof(Bucket);
|
||||
/* Store "hash slot index" + 2 (NULL is a mark of uninitialized cache slot) */
|
||||
CACHE_PTR_EX(cache_slot + 1, (void*)(uintptr_t)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
|
||||
}
|
||||
found:
|
||||
switch (has_set_exists) {
|
||||
case 0:
|
||||
ZVAL_DEREF(value);
|
||||
result = (Z_TYPE_P(value) != IS_NULL);
|
||||
break;
|
||||
default:
|
||||
result = zend_is_true(value);
|
||||
break;
|
||||
case 2:
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
} else if (UNEXPECTED(EG(exception))) {
|
||||
result = 0;
|
||||
|
@ -27,9 +27,16 @@ struct _zend_property_info;
|
||||
#define ZEND_WRONG_PROPERTY_INFO \
|
||||
((struct _zend_property_info*)((zend_intptr_t)-1))
|
||||
|
||||
#define IS_VALID_PROPERTY_OFFSET(offset) ((int32_t)(offset) > 0)
|
||||
#define IS_WRONG_PROPERTY_OFFSET(offset) ((int32_t)(offset) == 0)
|
||||
#define IS_DYNAMIC_PROPERTY_OFFSET(offset) ((int32_t)(offset) < 0)
|
||||
#define ZEND_DYNAMIC_PROPERTY_OFFSET ((uint32_t)(-1))
|
||||
|
||||
#define IS_VALID_PROPERTY_OFFSET(offset) ((int32_t)(offset) > 0)
|
||||
#define IS_WRONG_PROPERTY_OFFSET(offset) ((int32_t)(offset) == 0)
|
||||
#define IS_DYNAMIC_PROPERTY_OFFSET(offset) ((int32_t)(offset) < 0)
|
||||
|
||||
#define IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(offset) (offset == ZEND_DYNAMIC_PROPERTY_OFFSET)
|
||||
#define ZEND_DECODE_DYN_PROP_OFFSET(offset) ((uint32_t)(-(int32_t)(offset) - 2))
|
||||
#define ZEND_ENCODE_DYN_PROP_OFFSET(idx) ((uint32_t)(-(idx + 2)))
|
||||
|
||||
|
||||
/* The following rule applies to read_property() and read_dimension() implementations:
|
||||
If you return a zval which is not otherwise referenced by the extension or the engine's
|
||||
|
@ -1760,6 +1760,7 @@ ZEND_VM_HANDLER(82, ZEND_FETCH_OBJ_R, CONST|TMP|VAR|UNUSED|THIS|CV, CONST|TMPVAR
|
||||
zval *container;
|
||||
zend_free_op free_op2;
|
||||
zval *offset;
|
||||
void **cache_slot = NULL;
|
||||
|
||||
SAVE_OPLINE();
|
||||
container = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_R);
|
||||
@ -1787,21 +1788,44 @@ ZEND_VM_HANDLER(82, ZEND_FETCH_OBJ_R, CONST|TMP|VAR|UNUSED|THIS|CV, CONST|TMPVAR
|
||||
zend_object *zobj = Z_OBJ_P(container);
|
||||
zval *retval;
|
||||
|
||||
if (OP2_TYPE == IS_CONST &&
|
||||
EXPECTED(zobj->ce == CACHED_PTR(Z_CACHE_SLOT_P(offset)))) {
|
||||
uint32_t prop_offset = (uint32_t)(intptr_t)CACHED_PTR(Z_CACHE_SLOT_P(offset) + sizeof(void*));
|
||||
if (OP2_TYPE == IS_CONST) {
|
||||
cache_slot = CACHE_ADDR(Z_CACHE_SLOT_P(offset));
|
||||
|
||||
if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) {
|
||||
retval = OBJ_PROP(zobj, prop_offset);
|
||||
if (EXPECTED(Z_TYPE_INFO_P(retval) != IS_UNDEF)) {
|
||||
ZVAL_COPY_UNREF(EX_VAR(opline->result.var), retval);
|
||||
break;
|
||||
}
|
||||
} else if (EXPECTED(zobj->properties != NULL)) {
|
||||
retval = zend_hash_find(zobj->properties, Z_STR_P(offset));
|
||||
if (EXPECTED(retval)) {
|
||||
ZVAL_COPY_UNREF(EX_VAR(opline->result.var), retval);
|
||||
break;
|
||||
if (EXPECTED(zobj->ce == CACHED_PTR_EX(cache_slot))) {
|
||||
uint32_t prop_offset = (uint32_t)(intptr_t)CACHED_PTR_EX(cache_slot + 1);
|
||||
|
||||
if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) {
|
||||
retval = OBJ_PROP(zobj, prop_offset);
|
||||
if (EXPECTED(Z_TYPE_INFO_P(retval) != IS_UNDEF)) {
|
||||
ZVAL_COPY_UNREF(EX_VAR(opline->result.var), retval);
|
||||
break;
|
||||
}
|
||||
} else if (EXPECTED(zobj->properties != NULL)) {
|
||||
if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(prop_offset)) {
|
||||
uint32_t idx = ZEND_DECODE_DYN_PROP_OFFSET(prop_offset);
|
||||
|
||||
if (EXPECTED(idx < zobj->properties->nNumUsed)) {
|
||||
Bucket *p = zobj->properties->arData + idx;
|
||||
|
||||
if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) &&
|
||||
(EXPECTED(p->key == Z_STR_P(offset)) ||
|
||||
(EXPECTED(p->h == ZSTR_H(Z_STR_P(offset))) &&
|
||||
EXPECTED(p->key != NULL) &&
|
||||
EXPECTED(ZSTR_LEN(p->key) == Z_STRLEN_P(offset)) &&
|
||||
EXPECTED(memcmp(ZSTR_VAL(p->key), Z_STRVAL_P(offset), Z_STRLEN_P(offset)) == 0)))) {
|
||||
ZVAL_COPY_UNREF(EX_VAR(opline->result.var), &p->val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
CACHE_PTR_EX(cache_slot + 1, (void*)(uintptr_t)ZEND_DYNAMIC_PROPERTY_OFFSET);
|
||||
}
|
||||
retval = zend_hash_find(zobj->properties, Z_STR_P(offset));
|
||||
if (EXPECTED(retval)) {
|
||||
uint32_t idx = ((char*)retval - (char*)zobj->properties->arData) / sizeof(Bucket);
|
||||
CACHE_PTR_EX(cache_slot + 1, (void*)(uintptr_t)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
|
||||
ZVAL_COPY_UNREF(EX_VAR(opline->result.var), retval);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1814,7 +1838,7 @@ ZEND_VM_C_LABEL(fetch_obj_r_no_object):
|
||||
zend_string_release(property_name);
|
||||
ZVAL_NULL(EX_VAR(opline->result.var));
|
||||
} else {
|
||||
retval = zobj->handlers->read_property(container, offset, BP_VAR_R, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(offset)) : NULL), EX_VAR(opline->result.var));
|
||||
retval = zobj->handlers->read_property(container, offset, BP_VAR_R, cache_slot, EX_VAR(opline->result.var));
|
||||
|
||||
if (retval != EX_VAR(opline->result.var)) {
|
||||
ZVAL_COPY_UNREF(EX_VAR(opline->result.var), retval);
|
||||
@ -1881,6 +1905,7 @@ ZEND_VM_HANDLER(91, ZEND_FETCH_OBJ_IS, CONST|TMPVAR|UNUSED|THIS|CV, CONST|TMPVAR
|
||||
zval *container;
|
||||
zend_free_op free_op2;
|
||||
zval *offset;
|
||||
void **cache_slot = NULL;
|
||||
|
||||
SAVE_OPLINE();
|
||||
container = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_IS);
|
||||
@ -1908,21 +1933,44 @@ ZEND_VM_HANDLER(91, ZEND_FETCH_OBJ_IS, CONST|TMPVAR|UNUSED|THIS|CV, CONST|TMPVAR
|
||||
zend_object *zobj = Z_OBJ_P(container);
|
||||
zval *retval;
|
||||
|
||||
if (OP2_TYPE == IS_CONST &&
|
||||
EXPECTED(zobj->ce == CACHED_PTR(Z_CACHE_SLOT_P(offset)))) {
|
||||
uint32_t prop_offset = (uint32_t)(intptr_t)CACHED_PTR(Z_CACHE_SLOT_P(offset) + sizeof(void*));
|
||||
if (OP2_TYPE == IS_CONST) {
|
||||
cache_slot = CACHE_ADDR(Z_CACHE_SLOT_P(offset));
|
||||
|
||||
if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) {
|
||||
retval = OBJ_PROP(zobj, prop_offset);
|
||||
if (EXPECTED(Z_TYPE_P(retval) != IS_UNDEF)) {
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), retval);
|
||||
break;
|
||||
}
|
||||
} else if (EXPECTED(zobj->properties != NULL)) {
|
||||
retval = zend_hash_find(zobj->properties, Z_STR_P(offset));
|
||||
if (EXPECTED(retval)) {
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), retval);
|
||||
break;
|
||||
if (EXPECTED(zobj->ce == CACHED_PTR_EX(cache_slot))) {
|
||||
uint32_t prop_offset = (uint32_t)(intptr_t)CACHED_PTR_EX(cache_slot + 1);
|
||||
|
||||
if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) {
|
||||
retval = OBJ_PROP(zobj, prop_offset);
|
||||
if (EXPECTED(Z_TYPE_P(retval) != IS_UNDEF)) {
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), retval);
|
||||
break;
|
||||
}
|
||||
} else if (EXPECTED(zobj->properties != NULL)) {
|
||||
if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(prop_offset)) {
|
||||
uint32_t idx = ZEND_DECODE_DYN_PROP_OFFSET(prop_offset);
|
||||
|
||||
if (EXPECTED(idx < zobj->properties->nNumUsed)) {
|
||||
Bucket *p = zobj->properties->arData + idx;
|
||||
|
||||
if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) &&
|
||||
(EXPECTED(p->key == Z_STR_P(offset)) ||
|
||||
(EXPECTED(p->h == ZSTR_H(Z_STR_P(offset))) &&
|
||||
EXPECTED(p->key != NULL) &&
|
||||
EXPECTED(ZSTR_LEN(p->key) == Z_STRLEN_P(offset)) &&
|
||||
EXPECTED(memcmp(ZSTR_VAL(p->key), Z_STRVAL_P(offset), Z_STRLEN_P(offset)) == 0)))) {
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), &p->val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
CACHE_PTR_EX(cache_slot + 1, (void*)(uintptr_t)ZEND_DYNAMIC_PROPERTY_OFFSET);
|
||||
}
|
||||
retval = zend_hash_find(zobj->properties, Z_STR_P(offset));
|
||||
if (EXPECTED(retval)) {
|
||||
uint32_t idx = ((char*)retval - (char*)zobj->properties->arData) / sizeof(Bucket);
|
||||
CACHE_PTR_EX(cache_slot + 1, (void*)(uintptr_t)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), retval);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1932,7 +1980,7 @@ ZEND_VM_C_LABEL(fetch_obj_is_no_object):
|
||||
ZVAL_NULL(EX_VAR(opline->result.var));
|
||||
} else {
|
||||
|
||||
retval = zobj->handlers->read_property(container, offset, BP_VAR_IS, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(offset)) : NULL), EX_VAR(opline->result.var));
|
||||
retval = zobj->handlers->read_property(container, offset, BP_VAR_IS, cache_slot, EX_VAR(opline->result.var));
|
||||
|
||||
if (retval != EX_VAR(opline->result.var)) {
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), retval);
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user