mirror of
https://github.com/php/php-src.git
synced 2024-11-24 10:24:11 +08:00
Improved ASSIGN_<OP>, ASSIGN_DIM and UNSET_DIM
This commit is contained in:
parent
f0f51da936
commit
5b3a69c29f
@ -390,39 +390,43 @@ static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_W(const zend_execu
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline zval *_get_zval_ptr(int op_type, znode_op node, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC)
|
||||
static zend_always_inline zval *_get_zval_ptr(int op_type, znode_op node, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC)
|
||||
{
|
||||
switch (op_type) {
|
||||
case IS_CONST:
|
||||
*should_free = NULL;
|
||||
return node.zv;
|
||||
case IS_TMP_VAR:
|
||||
if (op_type & (IS_TMP_VAR|IS_VAR)) {
|
||||
if (op_type == IS_TMP_VAR) {
|
||||
return _get_zval_ptr_tmp(node.var, execute_data, should_free);
|
||||
case IS_VAR:
|
||||
} else {
|
||||
ZEND_ASSERT(op_type == IS_VAR);
|
||||
return _get_zval_ptr_var(node.var, execute_data, should_free);
|
||||
case IS_CV:
|
||||
default:
|
||||
}
|
||||
} else {
|
||||
*should_free = NULL;
|
||||
if (op_type == IS_CONST) {
|
||||
return node.zv;
|
||||
} else {
|
||||
ZEND_ASSERT(op_type == IS_CV);
|
||||
*should_free = NULL;
|
||||
return _get_zval_ptr_cv(execute_data, node.var, type TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline zval *_get_zval_ptr_deref(int op_type, znode_op node, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC)
|
||||
static zend_always_inline zval *_get_zval_ptr_deref(int op_type, znode_op node, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC)
|
||||
{
|
||||
switch (op_type) {
|
||||
case IS_CONST:
|
||||
*should_free = NULL;
|
||||
return node.zv;
|
||||
case IS_TMP_VAR:
|
||||
if (op_type & (IS_TMP_VAR|IS_VAR)) {
|
||||
if (op_type == IS_TMP_VAR) {
|
||||
return _get_zval_ptr_tmp(node.var, execute_data, should_free);
|
||||
case IS_VAR:
|
||||
} else {
|
||||
ZEND_ASSERT(op_type == IS_VAR);
|
||||
return _get_zval_ptr_var_deref(node.var, execute_data, should_free);
|
||||
case IS_CV:
|
||||
default:
|
||||
}
|
||||
} else {
|
||||
*should_free = NULL;
|
||||
if (op_type == IS_CONST) {
|
||||
return node.zv;
|
||||
} else {
|
||||
ZEND_ASSERT(op_type == IS_CV);
|
||||
*should_free = NULL;
|
||||
return _get_zval_ptr_cv_deref(execute_data, node.var, type TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -930,6 +934,39 @@ static zend_always_inline void zend_assign_to_object_dim(zval *retval, zval *obj
|
||||
}
|
||||
}
|
||||
|
||||
static void zend_binary_assign_op_obj_dim(zval *object, zval *property, zval *value, zval *retval, int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC))
|
||||
{
|
||||
zval *z;
|
||||
zval rv;
|
||||
|
||||
if (Z_OBJ_HT_P(object)->read_dimension &&
|
||||
(z = Z_OBJ_HT_P(object)->read_dimension(object, property, BP_VAR_R, &rv TSRMLS_CC)) != NULL) {
|
||||
|
||||
if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) {
|
||||
zval rv;
|
||||
zval *value = Z_OBJ_HT_P(z)->get(z, &rv TSRMLS_CC);
|
||||
|
||||
if (Z_REFCOUNT_P(z) == 0) {
|
||||
zend_objects_store_del(Z_OBJ_P(z) TSRMLS_CC);
|
||||
}
|
||||
ZVAL_COPY_VALUE(z, value);
|
||||
}
|
||||
ZVAL_DEREF(z);
|
||||
SEPARATE_ZVAL_NOREF(z);
|
||||
binary_op(z, z, value TSRMLS_CC);
|
||||
Z_OBJ_HT_P(object)->write_dimension(object, property, z TSRMLS_CC);
|
||||
if (retval) {
|
||||
ZVAL_COPY(retval, z);
|
||||
}
|
||||
zval_ptr_dtor(z);
|
||||
} else {
|
||||
zend_error(E_WARNING, "Attempt to assign property of non-object");
|
||||
if (retval) {
|
||||
ZVAL_NULL(retval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void zend_assign_to_string_offset(zval *str, zend_long offset, zval *value, zval *result TSRMLS_DC)
|
||||
{
|
||||
zend_string *old_str;
|
||||
|
@ -347,7 +347,7 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMPVAR|
|
||||
}
|
||||
|
||||
do {
|
||||
value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
|
||||
value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
|
||||
|
||||
if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
|
||||
if (UNEXPECTED(!make_real_object(&object TSRMLS_CC))) {
|
||||
@ -360,8 +360,7 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMPVAR|
|
||||
}
|
||||
|
||||
/* here we are sure we are dealing with an object */
|
||||
if (opline->extended_value == ZEND_ASSIGN_OBJ
|
||||
&& EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr)
|
||||
if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr)
|
||||
&& EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) {
|
||||
|
||||
ZVAL_DEREF(zptr);
|
||||
@ -372,19 +371,11 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMPVAR|
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), zptr);
|
||||
}
|
||||
} else {
|
||||
zval *z = NULL;
|
||||
zval *z;
|
||||
zval rv;
|
||||
|
||||
if (opline->extended_value == ZEND_ASSIGN_OBJ) {
|
||||
if (Z_OBJ_HT_P(object)->read_property) {
|
||||
z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC);
|
||||
}
|
||||
} else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ {
|
||||
if (Z_OBJ_HT_P(object)->read_dimension) {
|
||||
z = Z_OBJ_HT_P(object)->read_dimension(object, property, BP_VAR_R, &rv TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
if (z) {
|
||||
if (Z_OBJ_HT_P(object)->read_property &&
|
||||
(z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC)) != NULL) {
|
||||
if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) {
|
||||
zval rv;
|
||||
zval *value = Z_OBJ_HT_P(z)->get(z, &rv TSRMLS_CC);
|
||||
@ -394,14 +385,10 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMPVAR|
|
||||
}
|
||||
ZVAL_COPY_VALUE(z, value);
|
||||
}
|
||||
//??? if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z);
|
||||
SEPARATE_ZVAL_IF_NOT_REF(z);
|
||||
ZVAL_DEREF(z);
|
||||
SEPARATE_ZVAL_NOREF(z);
|
||||
binary_op(z, z, value TSRMLS_CC);
|
||||
if (opline->extended_value == ZEND_ASSIGN_OBJ) {
|
||||
Z_OBJ_HT_P(object)->write_property(object, property, z, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC);
|
||||
} else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ {
|
||||
Z_OBJ_HT_P(object)->write_dimension(object, property, z TSRMLS_CC);
|
||||
}
|
||||
Z_OBJ_HT_P(object)->write_property(object, property, z, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC);
|
||||
if (RETURN_VALUE_USED(opline)) {
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), z);
|
||||
}
|
||||
@ -434,44 +421,47 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_dim_helper, VAR|UNUSED|CV, CONST|TMPVAR|
|
||||
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
|
||||
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array");
|
||||
}
|
||||
if (OP1_TYPE != IS_UNUSED) {
|
||||
ZVAL_DEREF(container);
|
||||
}
|
||||
|
||||
#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED)
|
||||
if (OP1_TYPE == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
|
||||
if (OP1_TYPE == IS_VAR && !OP1_FREE) {
|
||||
Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */
|
||||
}
|
||||
ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_obj_helper, binary_op, binary_op);
|
||||
}
|
||||
#endif
|
||||
|
||||
dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
|
||||
|
||||
zend_fetch_dimension_address_RW(&rv, container, dim, OP2_TYPE TSRMLS_CC);
|
||||
value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
|
||||
ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT);
|
||||
var_ptr = Z_INDIRECT(rv);
|
||||
|
||||
if (UNEXPECTED(var_ptr == NULL)) {
|
||||
zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets");
|
||||
}
|
||||
|
||||
if (UNEXPECTED(var_ptr == &EG(error_zval))) {
|
||||
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
|
||||
ZVAL_NULL(EX_VAR(opline->result.var));
|
||||
do {
|
||||
if (OP1_TYPE == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) != IS_ARRAY)) {
|
||||
if (OP1_TYPE != IS_UNUSED) {
|
||||
ZVAL_DEREF(container);
|
||||
}
|
||||
#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED)
|
||||
if (OP1_TYPE == IS_UNUSED || EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
|
||||
value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
|
||||
zend_binary_assign_op_obj_dim(container, dim, value, UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, binary_op TSRMLS_CC);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
ZVAL_DEREF(var_ptr);
|
||||
SEPARATE_ZVAL_NOREF(var_ptr);
|
||||
|
||||
binary_op(var_ptr, var_ptr, value TSRMLS_CC);
|
||||
zend_fetch_dimension_address_RW(&rv, container, dim, OP2_TYPE TSRMLS_CC);
|
||||
value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
|
||||
ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT);
|
||||
var_ptr = Z_INDIRECT(rv);
|
||||
|
||||
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), var_ptr);
|
||||
if (UNEXPECTED(var_ptr == NULL)) {
|
||||
zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets");
|
||||
}
|
||||
}
|
||||
|
||||
if (UNEXPECTED(var_ptr == &EG(error_zval))) {
|
||||
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
|
||||
ZVAL_NULL(EX_VAR(opline->result.var));
|
||||
}
|
||||
} else {
|
||||
ZVAL_DEREF(var_ptr);
|
||||
SEPARATE_ZVAL_NOREF(var_ptr);
|
||||
|
||||
binary_op(var_ptr, var_ptr, value TSRMLS_CC);
|
||||
|
||||
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), var_ptr);
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
|
||||
FREE_OP2();
|
||||
FREE_OP(free_op_data1);
|
||||
@ -793,12 +783,13 @@ ZEND_VM_HELPER_EX(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR|C
|
||||
}
|
||||
ZVAL_COPY_VALUE(z, value);
|
||||
}
|
||||
if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z);
|
||||
SEPARATE_ZVAL_IF_NOT_REF(z);
|
||||
ZVAL_DEREF(z);
|
||||
SEPARATE_ZVAL_NOREF(z);
|
||||
incdec_op(z);
|
||||
ZVAL_COPY_VALUE(retval, z);
|
||||
if (RETURN_VALUE_USED(opline)) {
|
||||
ZVAL_COPY(retval, z);
|
||||
}
|
||||
Z_OBJ_HT_P(object)->write_property(object, property, z, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC);
|
||||
SELECTIVE_PZVAL_LOCK(retval, opline);
|
||||
zval_ptr_dtor(z);
|
||||
} else {
|
||||
zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
|
||||
@ -4486,15 +4477,15 @@ ZEND_VM_HANDLER(75, ZEND_UNSET_DIM, VAR|UNUSED|CV, CONST|TMPVAR|CV)
|
||||
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
|
||||
zend_error_noreturn(E_ERROR, "Cannot unset string offsets");
|
||||
}
|
||||
if (OP1_TYPE != IS_UNUSED) {
|
||||
ZVAL_DEREF(container);
|
||||
}
|
||||
SEPARATE_ZVAL_NOREF(container);
|
||||
offset = GET_OP2_ZVAL_PTR(BP_VAR_R);
|
||||
|
||||
ZEND_VM_C_LABEL(unset_dim_again):
|
||||
if (OP1_TYPE != IS_UNUSED && EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
|
||||
HashTable *ht = Z_ARRVAL_P(container);
|
||||
HashTable *ht;
|
||||
|
||||
ZEND_VM_C_LABEL(offset_again):
|
||||
SEPARATE_ARRAY(container);
|
||||
ht = Z_ARRVAL_P(container);
|
||||
switch (Z_TYPE_P(offset)) {
|
||||
case IS_DOUBLE:
|
||||
hval = zend_dval_to_lval(Z_DVAL_P(offset));
|
||||
@ -4547,7 +4538,10 @@ ZEND_VM_C_LABEL(num_index_dim):
|
||||
//??? }
|
||||
Z_OBJ_HT_P(container)->unset_dimension(container, offset TSRMLS_CC);
|
||||
FREE_OP2();
|
||||
} else if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) {
|
||||
} else if (OP1_TYPE != IS_UNUSED && Z_ISREF_P(container)) {
|
||||
container = Z_REFVAL_P(container);
|
||||
ZEND_VM_C_GOTO(unset_dim_again);
|
||||
} else if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) {
|
||||
zend_error_noreturn(E_ERROR, "Cannot unset string offsets");
|
||||
ZEND_VM_CONTINUE(); /* bailed out before */
|
||||
} else {
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user