Skip to content

Commit c2fc25f

Browse files
committed
Avoid reading of property name in ASSIGN_OBJ if it can be accessed through run-time cache slot.
1 parent 1b94b5b commit c2fc25f

File tree

2 files changed

+2680
-2791
lines changed

2 files changed

+2680
-2791
lines changed

Zend/zend_vm_def.h

Lines changed: 75 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -2346,129 +2346,126 @@ ZEND_VM_HANDLER(155, ZEND_FETCH_LIST_W, VAR, CONST|TMPVAR|CV)
23462346
ZEND_VM_HANDLER(24, ZEND_ASSIGN_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_SLOT, SPEC(OP_DATA=CONST|TMP|VAR|CV))
23472347
{
23482348
USE_OPLINE
2349-
zval *object, *property, *value, tmp;
2349+
zval *object, *value, tmp;
23502350
zend_object *zobj;
23512351
zend_string *name, *tmp_name;
23522352

23532353
SAVE_OPLINE();
23542354
object = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);
2355-
property = GET_OP2_ZVAL_PTR(BP_VAR_R);
23562355
value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R);
23572356

23582357
if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
23592358
if (Z_ISREF_P(object) && Z_TYPE_P(Z_REFVAL_P(object)) == IS_OBJECT) {
23602359
object = Z_REFVAL_P(object);
23612360
ZEND_VM_C_GOTO(assign_object);
23622361
}
2363-
zend_throw_non_object_error(object, property OPLINE_CC EXECUTE_DATA_CC);
2362+
zend_throw_non_object_error(object, GET_OP2_ZVAL_PTR(BP_VAR_R) OPLINE_CC EXECUTE_DATA_CC);
23642363
value = &EG(uninitialized_zval);
23652364
ZEND_VM_C_GOTO(free_and_exit_assign_obj);
23662365
}
23672366

23682367
ZEND_VM_C_LABEL(assign_object):
23692368
zobj = Z_OBJ_P(object);
2370-
if (OP2_TYPE == IS_CONST &&
2371-
EXPECTED(zobj->ce == CACHED_PTR(opline->extended_value))) {
2372-
void **cache_slot = CACHE_ADDR(opline->extended_value);
2373-
uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1);
2374-
zend_object *zobj = Z_OBJ_P(object);
2375-
zval *property_val;
2376-
2377-
if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) {
2378-
property_val = OBJ_PROP(zobj, prop_offset);
2379-
if (Z_TYPE_P(property_val) != IS_UNDEF) {
2380-
zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2);
2381-
2382-
if (UNEXPECTED(prop_info != NULL)) {
2383-
zend_uchar orig_type = IS_UNDEF;
2384-
2385-
if (OP_DATA_TYPE == IS_CONST) {
2386-
orig_type = Z_TYPE_P(value);
2387-
}
2369+
if (OP2_TYPE == IS_CONST) {
2370+
if (EXPECTED(zobj->ce == CACHED_PTR(opline->extended_value))) {
2371+
void **cache_slot = CACHE_ADDR(opline->extended_value);
2372+
uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1);
2373+
zend_object *zobj = Z_OBJ_P(object);
2374+
zval *property_val;
2375+
2376+
if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) {
2377+
property_val = OBJ_PROP(zobj, prop_offset);
2378+
if (Z_TYPE_P(property_val) != IS_UNDEF) {
2379+
zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2);
2380+
2381+
if (UNEXPECTED(prop_info != NULL)) {
2382+
zend_uchar orig_type = IS_UNDEF;
2383+
2384+
if (OP_DATA_TYPE == IS_CONST) {
2385+
orig_type = Z_TYPE_P(value);
2386+
}
23882387

2389-
value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
2388+
value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
23902389

2391-
/* will remain valid, thus no need to check prop_info in future here */
2392-
if (OP_DATA_TYPE == IS_CONST && Z_TYPE_P(value) == orig_type) {
2393-
CACHE_PTR_EX(cache_slot + 2, NULL);
2394-
}
2395-
ZEND_VM_C_GOTO(free_and_exit_assign_obj);
2396-
} else {
2390+
/* will remain valid, thus no need to check prop_info in future here */
2391+
if (OP_DATA_TYPE == IS_CONST && Z_TYPE_P(value) == orig_type) {
2392+
CACHE_PTR_EX(cache_slot + 2, NULL);
2393+
}
2394+
ZEND_VM_C_GOTO(free_and_exit_assign_obj);
2395+
} else {
23972396
ZEND_VM_C_LABEL(fast_assign_obj):
2398-
value = zend_assign_to_variable(property_val, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES());
2399-
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
2400-
ZVAL_COPY(EX_VAR(opline->result.var), value);
2397+
value = zend_assign_to_variable(property_val, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES());
2398+
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
2399+
ZVAL_COPY(EX_VAR(opline->result.var), value);
2400+
}
2401+
ZEND_VM_C_GOTO(exit_assign_obj);
24012402
}
2402-
ZEND_VM_C_GOTO(exit_assign_obj);
24032403
}
2404-
}
2405-
} else {
2406-
if (EXPECTED(zobj->properties != NULL)) {
2407-
if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
2408-
if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) {
2409-
GC_DELREF(zobj->properties);
2404+
} else {
2405+
name = Z_STR_P(GET_OP2_ZVAL_PTR(BP_VAR_R));
2406+
if (EXPECTED(zobj->properties != NULL)) {
2407+
if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
2408+
if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) {
2409+
GC_DELREF(zobj->properties);
2410+
}
2411+
zobj->properties = zend_array_dup(zobj->properties);
2412+
}
2413+
property_val = zend_hash_find_ex(zobj->properties, name, 1);
2414+
if (property_val) {
2415+
ZEND_VM_C_GOTO(fast_assign_obj);
24102416
}
2411-
zobj->properties = zend_array_dup(zobj->properties);
2412-
}
2413-
property_val = zend_hash_find_ex(zobj->properties, Z_STR_P(property), 1);
2414-
if (property_val) {
2415-
ZEND_VM_C_GOTO(fast_assign_obj);
24162417
}
2417-
}
2418-
2419-
if (!zobj->ce->__set) {
24202418

2421-
if (EXPECTED(zobj->properties == NULL)) {
2422-
rebuild_object_properties(zobj);
2423-
}
2424-
if (OP_DATA_TYPE == IS_CONST) {
2425-
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(value))) {
2426-
Z_ADDREF_P(value);
2419+
if (!zobj->ce->__set) {
2420+
if (EXPECTED(zobj->properties == NULL)) {
2421+
rebuild_object_properties(zobj);
24272422
}
2428-
} else if (OP_DATA_TYPE != IS_TMP_VAR) {
2429-
if (Z_ISREF_P(value)) {
2430-
if (OP_DATA_TYPE == IS_VAR) {
2431-
zend_reference *ref = Z_REF_P(value);
2432-
if (GC_DELREF(ref) == 0) {
2433-
ZVAL_COPY_VALUE(&tmp, Z_REFVAL_P(value));
2434-
efree_size(ref, sizeof(zend_reference));
2435-
value = &tmp;
2423+
if (OP_DATA_TYPE == IS_CONST) {
2424+
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(value))) {
2425+
Z_ADDREF_P(value);
2426+
}
2427+
} else if (OP_DATA_TYPE != IS_TMP_VAR) {
2428+
if (Z_ISREF_P(value)) {
2429+
if (OP_DATA_TYPE == IS_VAR) {
2430+
zend_reference *ref = Z_REF_P(value);
2431+
if (GC_DELREF(ref) == 0) {
2432+
ZVAL_COPY_VALUE(&tmp, Z_REFVAL_P(value));
2433+
efree_size(ref, sizeof(zend_reference));
2434+
value = &tmp;
2435+
} else {
2436+
value = Z_REFVAL_P(value);
2437+
Z_TRY_ADDREF_P(value);
2438+
}
24362439
} else {
24372440
value = Z_REFVAL_P(value);
24382441
Z_TRY_ADDREF_P(value);
24392442
}
2440-
} else {
2441-
value = Z_REFVAL_P(value);
2443+
} else if (OP_DATA_TYPE == IS_CV) {
24422444
Z_TRY_ADDREF_P(value);
24432445
}
2444-
} else if (OP_DATA_TYPE == IS_CV) {
2445-
Z_TRY_ADDREF_P(value);
2446+
}
2447+
zend_hash_add_new(zobj->properties, name, value);
2448+
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
2449+
ZVAL_COPY(EX_VAR(opline->result.var), value);
24462450
}
2451+
ZEND_VM_C_GOTO(exit_assign_obj);
24472452
}
2448-
zend_hash_add_new(zobj->properties, Z_STR_P(property), value);
2449-
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
2450-
ZVAL_COPY(EX_VAR(opline->result.var), value);
2451-
}
2452-
ZEND_VM_C_GOTO(exit_assign_obj);
24532453
}
24542454
}
2455-
}
2456-
2457-
if (OP_DATA_TYPE == IS_CV || OP_DATA_TYPE == IS_VAR) {
2458-
ZVAL_DEREF(value);
2459-
}
2460-
2461-
if (OP2_TYPE == IS_CONST) {
2462-
name = Z_STR_P(property);
2455+
name = Z_STR_P(GET_OP2_ZVAL_PTR(BP_VAR_R));
24632456
} else {
2464-
name = zval_try_get_tmp_string(property, &tmp_name);
2457+
name = zval_try_get_tmp_string(GET_OP2_ZVAL_PTR(BP_VAR_R), &tmp_name);
24652458
if (UNEXPECTED(!name)) {
24662459
FREE_OP_DATA();
24672460
UNDEF_RESULT();
24682461
ZEND_VM_C_GOTO(exit_assign_obj);
24692462
}
24702463
}
24712464

2465+
if (OP_DATA_TYPE == IS_CV || OP_DATA_TYPE == IS_VAR) {
2466+
ZVAL_DEREF(value);
2467+
}
2468+
24722469
value = zobj->handlers->write_property(zobj, name, value, (OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL);
24732470

24742471
if (OP2_TYPE != IS_CONST) {

0 commit comments

Comments
 (0)