diff options
Diffstat (limited to 'Zend/zend_vm_def.h')
-rw-r--r-- | Zend/zend_vm_def.h | 735 |
1 files changed, 405 insertions, 330 deletions
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 09f5e22281..7490e577d7 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -346,47 +346,36 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMPVAR| zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - if (OP1_TYPE != IS_UNUSED) { - object = make_real_object(object TSRMLS_CC); - } - - value = get_zval_ptr_deref((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)) { - zend_error(E_WARNING, "Attempt to assign property of non-object"); - FREE_OP2(); - FREE_OP(free_op_data1); + do { + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - if (RETURN_VALUE_USED(opline)) { - ZVAL_NULL(EX_VAR(opline->result.var)); + if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(!make_real_object(&object TSRMLS_CC))) { + zend_error(E_WARNING, "Attempt to assign property of non-object"); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + break; + } } - } else { + /* 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); SEPARATE_ZVAL_NOREF(zptr); binary_op(zptr, zptr, value TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { 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); @@ -396,29 +385,22 @@ 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); - } - if (RETURN_VALUE_USED(opline)) { + 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 (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), z); } zval_ptr_dtor(z); } else { zend_error(E_WARNING, "Attempt to assign property of non-object"); - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } } - - FREE_OP2(); - FREE_OP(free_op_data1); - } + } while (0); FREE_OP1_VAR_PTR(); /* assign_obj has two opcodes! */ @@ -439,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); + 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 + } - if (UNEXPECTED(var_ptr == NULL)) { - zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); - } + 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(var_ptr == &EG(error_zval))) { - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_NULL(EX_VAR(opline->result.var)); + if (UNEXPECTED(var_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); } - } else { - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - binary_op(var_ptr, var_ptr, value TSRMLS_CC); + 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); - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), 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); @@ -524,9 +509,9 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_helper, VAR|CV, CONST|TMPVAR|CV, int (*b ZEND_VM_HANDLER(23, ZEND_ASSIGN_ADD, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) { +#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) USE_OPLINE -#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) # if !defined(ZEND_VM_SPEC) || (OP1_TYPE != IS_UNUSED) if (EXPECTED(opline->extended_value == 0)) { ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, add_function); @@ -544,9 +529,9 @@ ZEND_VM_HANDLER(23, ZEND_ASSIGN_ADD, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) ZEND_VM_HANDLER(24, ZEND_ASSIGN_SUB, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) { +#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) USE_OPLINE -#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) # if !defined(ZEND_VM_SPEC) || (OP1_TYPE != IS_UNUSED) if (EXPECTED(opline->extended_value == 0)) { ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, sub_function); @@ -564,9 +549,9 @@ ZEND_VM_HANDLER(24, ZEND_ASSIGN_SUB, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) ZEND_VM_HANDLER(25, ZEND_ASSIGN_MUL, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) { +#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) USE_OPLINE -#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) # if !defined(ZEND_VM_SPEC) || (OP1_TYPE != IS_UNUSED) if (EXPECTED(opline->extended_value == 0)) { ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, mul_function); @@ -584,9 +569,9 @@ ZEND_VM_HANDLER(25, ZEND_ASSIGN_MUL, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) ZEND_VM_HANDLER(26, ZEND_ASSIGN_DIV, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) { +#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) USE_OPLINE -#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) # if !defined(ZEND_VM_SPEC) || (OP1_TYPE != IS_UNUSED) if (EXPECTED(opline->extended_value == 0)) { ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, div_function); @@ -604,9 +589,9 @@ ZEND_VM_HANDLER(26, ZEND_ASSIGN_DIV, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) ZEND_VM_HANDLER(27, ZEND_ASSIGN_MOD, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) { +#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) USE_OPLINE -#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) # if !defined(ZEND_VM_SPEC) || (OP1_TYPE != IS_UNUSED) if (EXPECTED(opline->extended_value == 0)) { ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, mod_function); @@ -624,9 +609,9 @@ ZEND_VM_HANDLER(27, ZEND_ASSIGN_MOD, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) ZEND_VM_HANDLER(28, ZEND_ASSIGN_SL, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) { +#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) USE_OPLINE -#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) # if !defined(ZEND_VM_SPEC) || (OP1_TYPE != IS_UNUSED) if (EXPECTED(opline->extended_value == 0)) { ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, shift_left_function); @@ -644,9 +629,9 @@ ZEND_VM_HANDLER(28, ZEND_ASSIGN_SL, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) ZEND_VM_HANDLER(29, ZEND_ASSIGN_SR, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) { +#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) USE_OPLINE -#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) # if !defined(ZEND_VM_SPEC) || (OP1_TYPE != IS_UNUSED) if (EXPECTED(opline->extended_value == 0)) { ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, shift_right_function); @@ -664,9 +649,9 @@ ZEND_VM_HANDLER(29, ZEND_ASSIGN_SR, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) ZEND_VM_HANDLER(30, ZEND_ASSIGN_CONCAT, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) { +#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) USE_OPLINE -#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) # if !defined(ZEND_VM_SPEC) || (OP1_TYPE != IS_UNUSED) if (EXPECTED(opline->extended_value == 0)) { ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, concat_function); @@ -684,9 +669,9 @@ ZEND_VM_HANDLER(30, ZEND_ASSIGN_CONCAT, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) ZEND_VM_HANDLER(31, ZEND_ASSIGN_BW_OR, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) { +#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) USE_OPLINE -#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) # if !defined(ZEND_VM_SPEC) || (OP1_TYPE != IS_UNUSED) if (EXPECTED(opline->extended_value == 0)) { ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, bitwise_or_function); @@ -704,9 +689,9 @@ ZEND_VM_HANDLER(31, ZEND_ASSIGN_BW_OR, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) ZEND_VM_HANDLER(32, ZEND_ASSIGN_BW_AND, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) { +#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) USE_OPLINE -#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) # if !defined(ZEND_VM_SPEC) || (OP1_TYPE != IS_UNUSED) if (EXPECTED(opline->extended_value == 0)) { ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, bitwise_and_function); @@ -724,9 +709,9 @@ ZEND_VM_HANDLER(32, ZEND_ASSIGN_BW_AND, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) ZEND_VM_HANDLER(33, ZEND_ASSIGN_BW_XOR, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV) { +#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) USE_OPLINE -#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) # if !defined(ZEND_VM_SPEC) || (OP1_TYPE != IS_UNUSED) if (EXPECTED(opline->extended_value == 0)) { ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, bitwise_xor_function); @@ -760,62 +745,60 @@ ZEND_VM_HELPER_EX(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR|C zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); } - if (OP1_TYPE != IS_UNUSED) { - object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */ - } - - if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { - zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); - FREE_OP2(); - if (RETURN_VALUE_USED(opline)) { - ZVAL_NULL(retval); + do { + if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(!make_real_object(&object TSRMLS_CC))) { + zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(retval); + } + break; + } } - FREE_OP1_VAR_PTR(); - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); - } - /* here we are sure we are dealing with an object */ + /* here we are sure we are dealing with an object */ - 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)) { + 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); - SEPARATE_ZVAL_NOREF(zptr); + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - incdec_op(zptr); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(retval, zptr); - } - } else { - zval rv; + incdec_op(zptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(retval, zptr); + } + } else { + zval rv; - if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { - zval *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); + if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { + zval *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); - if (UNEXPECTED(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 (UNEXPECTED(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); + 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); + incdec_op(z); + if (UNEXPECTED(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); + zval_ptr_dtor(z); + } else { + zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(retval); } - ZVAL_COPY_VALUE(z, value); - } - if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); - incdec_op(z); - ZVAL_COPY_VALUE(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"); - if (RETURN_VALUE_USED(opline)) { - ZVAL_NULL(retval); } } - } + } while (0); FREE_OP2(); FREE_OP1_VAR_PTR(); @@ -851,56 +834,53 @@ ZEND_VM_HELPER_EX(zend_post_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR| zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); } - if (OP1_TYPE != IS_UNUSED) { - object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */ - } - - if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { - zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); - FREE_OP2(); - ZVAL_NULL(retval); - FREE_OP1_VAR_PTR(); - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); - } - - /* here we are sure we are dealing with an object */ + do { + if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(!make_real_object(&object TSRMLS_CC))) { + zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); + ZVAL_NULL(retval); + break; + } + } - 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)) { + /* here we are sure we are dealing with an object */ - ZVAL_DEREF(zptr); - ZVAL_COPY_VALUE(retval, zptr); - zval_opt_copy_ctor(zptr); + 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)) { - incdec_op(zptr); - } else { - if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { - zval rv; - zval *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); - zval z_copy; + ZVAL_DEREF(zptr); + ZVAL_COPY_VALUE(retval, zptr); + zval_opt_copy_ctor(zptr); - if (UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) && Z_OBJ_HT_P(z)->get) { + incdec_op(zptr); + } else { + if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { zval rv; - zval *value = Z_OBJ_HT_P(z)->get(z, &rv TSRMLS_CC); + zval *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); + zval z_copy; + + if (UNEXPECTED(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); + if (Z_REFCOUNT_P(z) == 0) { + zend_objects_store_del(Z_OBJ_P(z) TSRMLS_CC); + } + ZVAL_COPY_VALUE(z, value); } - ZVAL_COPY_VALUE(z, value); - } - ZVAL_DUP(retval, z); - ZVAL_DUP(&z_copy, z); - incdec_op(&z_copy); - if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - Z_OBJ_HT_P(object)->write_property(object, property, &z_copy, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - zval_ptr_dtor(&z_copy); - zval_ptr_dtor(z); - } else { - zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); - ZVAL_NULL(retval); + ZVAL_DUP(retval, z); + ZVAL_DUP(&z_copy, z); + incdec_op(&z_copy); + if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); + Z_OBJ_HT_P(object)->write_property(object, property, &z_copy, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); + zval_ptr_dtor(&z_copy); + zval_ptr_dtor(z); + } else { + zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); + ZVAL_NULL(retval); + } } - } + } while (0); FREE_OP2(); FREE_OP1_VAR_PTR(); @@ -933,14 +913,14 @@ ZEND_VM_HANDLER(34, ZEND_PRE_INC, VAR|CV, ANY) if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { fast_increment_function(var_ptr); - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); } ZEND_VM_NEXT_OPCODE(); } if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } CHECK_EXCEPTION(); @@ -952,7 +932,7 @@ ZEND_VM_HANDLER(34, ZEND_PRE_INC, VAR|CV, ANY) increment_function(var_ptr); - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } @@ -976,14 +956,14 @@ ZEND_VM_HANDLER(35, ZEND_PRE_DEC, VAR|CV, ANY) if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { fast_decrement_function(var_ptr); - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); } ZEND_VM_NEXT_OPCODE(); } if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } CHECK_EXCEPTION(); @@ -995,7 +975,7 @@ ZEND_VM_HANDLER(35, ZEND_PRE_DEC, VAR|CV, ANY) decrement_function(var_ptr); - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } @@ -1261,14 +1241,14 @@ ZEND_VM_HANDLER(89, ZEND_FETCH_IS, CONST|TMPVAR|CV, UNUSED|CONST|VAR) ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_var_address_helper, type, BP_VAR_IS); } -ZEND_VM_HANDLER(81, ZEND_FETCH_DIM_R, CONST|TMP|VAR|CV, CONST|TMPVAR|CV) +ZEND_VM_HANDLER(81, ZEND_FETCH_DIM_R, CONST|TMPVAR|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; zval *container; SAVE_OPLINE(); - container = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); + container = GET_OP1_ZVAL_PTR(BP_VAR_R); zend_fetch_dimension_address_read_R(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE TSRMLS_CC); FREE_OP2(); FREE_OP1(); @@ -1283,12 +1263,11 @@ ZEND_VM_HANDLER(84, ZEND_FETCH_DIM_W, VAR|CV, CONST|TMPVAR|UNUSED|CV) zval *container; SAVE_OPLINE(); - container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); + container = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE TSRMLS_CC); FREE_OP2(); if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1)) { @@ -1311,7 +1290,6 @@ ZEND_VM_HANDLER(87, ZEND_FETCH_DIM_RW, VAR|CV, CONST|TMPVAR|UNUSED|CV) if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - ZVAL_DEREF(container); zend_fetch_dimension_address_RW(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE TSRMLS_CC); FREE_OP2(); if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1)) { @@ -1322,14 +1300,14 @@ ZEND_VM_HANDLER(87, ZEND_FETCH_DIM_RW, VAR|CV, CONST|TMPVAR|UNUSED|CV) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(90, ZEND_FETCH_DIM_IS, CONST|TMP|VAR|CV, CONST|TMPVAR|CV) +ZEND_VM_HANDLER(90, ZEND_FETCH_DIM_IS, CONST|TMPVAR|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; zval *container; SAVE_OPLINE(); - container = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_IS); + container = GET_OP1_ZVAL_PTR(BP_VAR_IS); zend_fetch_dimension_address_read_IS(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE TSRMLS_CC); FREE_OP2(); FREE_OP1(); @@ -1349,11 +1327,10 @@ ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, CONST|TMP|VAR|CV, CONST|TMPVAR|UNUS if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_TMP_VAR) { zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); } - container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); + container = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE TSRMLS_CC); if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -1364,7 +1341,7 @@ ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, CONST|TMP|VAR|CV, CONST|TMPVAR|UNUS if (OP2_TYPE == IS_UNUSED) { zend_error_noreturn(E_ERROR, "Cannot use [] for reading"); } - container = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); + container = GET_OP1_ZVAL_PTR(BP_VAR_R); zend_fetch_dimension_address_read_R(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE TSRMLS_CC); FREE_OP2(); FREE_OP1(); @@ -1385,7 +1362,6 @@ ZEND_VM_HANDLER(96, ZEND_FETCH_DIM_UNSET, VAR|CV, CONST|TMPVAR|CV) if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - ZVAL_DEREF(container); zend_fetch_dimension_address_UNSET(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE TSRMLS_CC); FREE_OP2(); if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1)) { @@ -1405,11 +1381,21 @@ ZEND_VM_HANDLER(82, ZEND_FETCH_OBJ_R, CONST|TMP|VAR|UNUSED|CV, CONST|TMPVAR|CV) zval *offset; SAVE_OPLINE(); - container = GET_OP1_OBJ_ZVAL_PTR_DEREF(BP_VAR_R); + container = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_R); offset = GET_OP2_ZVAL_PTR(BP_VAR_R); - if ((OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT)) || - UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT)) { + if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_ISREF_P(container)) { + container = Z_REFVAL_P(container); + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT)) { + ZEND_VM_C_GOTO(fetch_obj_r_no_object); + } + } else { + ZEND_VM_C_GOTO(fetch_obj_r_no_object); + } + } + if (UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { +ZEND_VM_C_LABEL(fetch_obj_r_no_object): zend_error(E_NOTICE, "Trying to get property of non-object"); ZVAL_NULL(EX_VAR(opline->result.var)); } else { @@ -1461,7 +1447,7 @@ ZEND_VM_HANDLER(85, ZEND_FETCH_OBJ_W, VAR|UNUSED|CV, CONST|TMPVAR|CV) SAVE_OPLINE(); property = GET_OP2_ZVAL_PTR(BP_VAR_R); - container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_W); + container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } @@ -1500,7 +1486,7 @@ ZEND_VM_HANDLER(88, ZEND_FETCH_OBJ_RW, VAR|UNUSED|CV, CONST|TMPVAR|CV) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(91, ZEND_FETCH_OBJ_IS, CONST|TMP|VAR|UNUSED|CV, CONST|TMPVAR|CV) +ZEND_VM_HANDLER(91, ZEND_FETCH_OBJ_IS, CONST|TMPVAR|UNUSED|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1; @@ -1509,11 +1495,21 @@ ZEND_VM_HANDLER(91, ZEND_FETCH_OBJ_IS, CONST|TMP|VAR|UNUSED|CV, CONST|TMPVAR|CV) zval *offset; SAVE_OPLINE(); - container = GET_OP1_OBJ_ZVAL_PTR_DEREF(BP_VAR_IS); + container = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_IS); offset = GET_OP2_ZVAL_PTR(BP_VAR_R); - if ((OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT)) || - UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT)) { + if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_ISREF_P(container)) { + container = Z_REFVAL_P(container); + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT)) { + ZEND_VM_C_GOTO(fetch_obj_is_no_object); + } + } else { + ZEND_VM_C_GOTO(fetch_obj_is_no_object); + } + } + if (UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { +ZEND_VM_C_LABEL(fetch_obj_is_no_object): ZVAL_NULL(EX_VAR(opline->result.var)); } else { zval *retval; @@ -1566,7 +1562,7 @@ ZEND_VM_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, CONST|TMP|VAR|UNUSED|CV, CONST|TMPV SAVE_OPLINE(); property = GET_OP2_ZVAL_PTR(BP_VAR_R); - container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_W); + container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_TMP_VAR) { zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); @@ -1610,15 +1606,16 @@ ZEND_VM_HANDLER(97, ZEND_FETCH_OBJ_UNSET, VAR|UNUSED|CV, CONST|TMPVAR|CV) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(98, ZEND_FETCH_LIST, CONST|TMP|VAR|CV, CONST) +ZEND_VM_HANDLER(98, ZEND_FETCH_LIST, CONST|TMPVAR|CV, CONST) { USE_OPLINE zend_free_op free_op1; zval *container; SAVE_OPLINE(); - container = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); + container = GET_OP1_ZVAL_PTR(BP_VAR_R); +ZEND_VM_C_LABEL(try_fetch_list): if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { zend_free_op free_op2; zval *value = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE, BP_VAR_R TSRMLS_CC); @@ -1636,6 +1633,9 @@ ZEND_VM_HANDLER(98, ZEND_FETCH_LIST, CONST|TMP|VAR|CV, CONST) } else { ZVAL_NULL(result); } + } else if (Z_TYPE_P(container) == IS_REFERENCE) { + container = Z_REFVAL_P(container); + ZEND_VM_C_GOTO(try_fetch_list); } else { ZVAL_NULL(EX_VAR(opline->result.var)); } @@ -1651,13 +1651,13 @@ ZEND_VM_HANDLER(136, ZEND_ASSIGN_OBJ, VAR|UNUSED|CV, CONST|TMPVAR|CV) zval *property_name; SAVE_OPLINE(); - object = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_W); + object = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); property_name = GET_OP2_ZVAL_PTR(BP_VAR_R); if (OP1_TYPE == IS_VAR && UNEXPECTED(object == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - zend_assign_to_object(RETURN_VALUE_USED(opline)?EX_VAR(opline->result.var):NULL, object, OP1_TYPE, property_name, (opline+1)->op1_type, &(opline+1)->op1, execute_data, ZEND_ASSIGN_OBJ, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property_name)) : NULL) TSRMLS_CC); + zend_assign_to_object(UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, object, OP1_TYPE, property_name, OP2_TYPE, (opline+1)->op1_type, (opline+1)->op1, execute_data, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property_name)) : NULL) TSRMLS_CC); FREE_OP2(); FREE_OP1_VAR_PTR(); /* assign_obj has two opcodes! */ @@ -1671,55 +1671,63 @@ ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMPVAR|UNUSED|CV) USE_OPLINE zend_free_op free_op1; zval *object_ptr; + zend_free_op free_op2, free_op_data1; + zval rv; + zval *value; + zval *variable_ptr; + zval *dim; SAVE_OPLINE(); - object_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); + object_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); if (OP1_TYPE == IS_VAR && UNEXPECTED(object_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - ZVAL_DEREF(object_ptr); - if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { - zend_free_op free_op2; - zval *property_name = GET_OP2_ZVAL_PTR(BP_VAR_R); - zend_assign_to_object(RETURN_VALUE_USED(opline)?EX_VAR(opline->result.var):NULL, object_ptr, OP1_TYPE, property_name, (opline+1)->op1_type, &(opline+1)->op1, execute_data, ZEND_ASSIGN_DIM, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property_name)) : NULL) TSRMLS_CC); +ZEND_VM_C_LABEL(try_assign_dim): + if (EXPECTED(Z_TYPE_P(object_ptr) == IS_ARRAY)) { +ZEND_VM_C_LABEL(try_assign_dim_array): + dim = GET_OP2_ZVAL_PTR(BP_VAR_R); + zend_fetch_dimension_address_W(&rv, object_ptr, dim, OP2_TYPE TSRMLS_CC); FREE_OP2(); - } else { - zend_free_op free_op2, free_op_data1; - zval rv; - zval *value; - zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R); - zval *variable_ptr; - - if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) && - EXPECTED(Z_STRLEN_P(object_ptr) != 0)) { - zend_long offset = zend_fetch_string_offset(object_ptr, dim, BP_VAR_W TSRMLS_CC); - FREE_OP2(); - value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - zend_assign_to_string_offset(object_ptr, offset, value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) 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); + variable_ptr = Z_INDIRECT(rv); + if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } } else { - zend_fetch_dimension_address_W(&rv, object_ptr, dim, OP2_TYPE TSRMLS_CC); - FREE_OP2(); - 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); - variable_ptr = Z_INDIRECT(rv); - if (UNEXPECTED(variable_ptr == &EG(error_zval))) { + value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type TSRMLS_CC); + if ((opline+1)->op1_type == IS_VAR) { FREE_OP(free_op_data1); - if (RETURN_VALUE_USED(opline)) { - ZVAL_NULL(EX_VAR(opline->result.var)); - } - } else { - value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type TSRMLS_CC); - if ((opline+1)->op1_type == IS_VAR) { - FREE_OP(free_op_data1); - } - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(EX_VAR(opline->result.var), value); - } + } + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), value); } } + } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_free_op free_op2; + zval *property_name = GET_OP2_ZVAL_PTR(BP_VAR_R); + + zend_assign_to_object_dim(UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, object_ptr, property_name, (opline+1)->op1_type, (opline+1)->op1, execute_data TSRMLS_CC); + FREE_OP2(); + } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) && + EXPECTED(Z_STRLEN_P(object_ptr) != 0)) { + zend_long offset; + + dim = GET_OP2_ZVAL_PTR(BP_VAR_R); + offset = zend_fetch_string_offset(object_ptr, dim, BP_VAR_W TSRMLS_CC); + FREE_OP2(); + value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_assign_to_string_offset(object_ptr, offset, value, (UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + FREE_OP(free_op_data1); + } else if (EXPECTED(Z_ISREF_P(object_ptr))) { + object_ptr = Z_REFVAL_P(object_ptr); + ZEND_VM_C_GOTO(try_assign_dim); + } else { + ZEND_VM_C_GOTO(try_assign_dim_array); } FREE_OP1_VAR_PTR(); /* assign_dim has two opcodes! */ @@ -1743,12 +1751,12 @@ ZEND_VM_HANDLER(38, ZEND_ASSIGN, VAR|CV, CONST|TMP|VAR|CV) if (OP2_TYPE == IS_TMP_VAR) { FREE_OP2(); } - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { value = zend_assign_to_variable(variable_ptr, value, OP2_TYPE TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } FREE_OP1_VAR_PTR(); @@ -1815,7 +1823,7 @@ ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV) } } - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr); } @@ -2237,7 +2245,7 @@ ZEND_VM_C_LABEL(try_class_name): } } -ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMPVAR|CV) +ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMPVAR|UNUSED|CV, CONST|TMPVAR|CV) { USE_OPLINE zval *function_name; @@ -2259,52 +2267,61 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMPVAR|CV) zend_error_noreturn(E_ERROR, "Method name must be a string"); } - object = GET_OP1_OBJ_ZVAL_PTR_DEREF(BP_VAR_R); + object = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_R); - if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { - uint32_t nesting = 1; + do { + if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + uint32_t nesting = 1; - if (UNEXPECTED(EG(exception) != NULL)) { - FREE_OP2(); - HANDLE_EXCEPTION(); - } + if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_ISREF_P(object)) { + object = Z_REFVAL_P(object); + if (EXPECTED(Z_TYPE_P(object) == IS_OBJECT)) { + break; + } + } - zend_error(E_RECOVERABLE_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); - FREE_OP2(); - FREE_OP1_IF_VAR(); + if (UNEXPECTED(EG(exception) != NULL)) { + FREE_OP2(); + HANDLE_EXCEPTION(); + } - if (EG(exception) != NULL) { - HANDLE_EXCEPTION(); - } + zend_error(E_RECOVERABLE_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); + FREE_OP2(); + FREE_OP1(); - /* No exception raised: Skip over arguments until fcall opcode with correct - * nesting level. Return NULL (except when return value unused) */ - do { - opline++; - if (opline->opcode == ZEND_INIT_FCALL || - opline->opcode == ZEND_INIT_FCALL_BY_NAME || - opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME || - opline->opcode == ZEND_INIT_METHOD_CALL || - opline->opcode == ZEND_INIT_STATIC_METHOD_CALL || - opline->opcode == ZEND_INIT_USER_CALL || - opline->opcode == ZEND_NEW - ) { - nesting++; - } else if (opline->opcode == ZEND_DO_FCALL) { - nesting--; - } - } while (nesting); + if (EG(exception) != NULL) { + HANDLE_EXCEPTION(); + } - if (RETURN_VALUE_USED(opline)) { - ZVAL_NULL(EX_VAR(opline->result.var)); - } + /* No exception raised: Skip over arguments until fcall opcode with correct + * nesting level. Return NULL (except when return value unused) */ + do { + opline++; + if (opline->opcode == ZEND_INIT_FCALL || + opline->opcode == ZEND_INIT_FCALL_BY_NAME || + opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME || + opline->opcode == ZEND_INIT_METHOD_CALL || + opline->opcode == ZEND_INIT_STATIC_METHOD_CALL || + opline->opcode == ZEND_INIT_USER_CALL || + opline->opcode == ZEND_NEW + ) { + nesting++; + } else if (opline->opcode == ZEND_DO_FCALL) { + nesting--; + } + } while (nesting); + + if (RETURN_VALUE_USED(opline)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } - /* We've skipped EXT_FCALL_BEGIND, so also skip the ending opcode */ - if ((opline + 1)->opcode == ZEND_EXT_FCALL_END) { - opline++; + /* We've skipped EXT_FCALL_BEGIND, so also skip the ending opcode */ + if ((opline + 1)->opcode == ZEND_EXT_FCALL_END) { + opline++; + } + ZEND_VM_JMP(++opline); } - ZEND_VM_JMP(++opline); - } + } while (0); obj = Z_OBJ_P(object); called_scope = obj->ce; @@ -2340,7 +2357,7 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMPVAR|CV) fbc, opline->extended_value, called_scope, obj, EX(call) TSRMLS_CC); FREE_OP2(); - FREE_OP1_IF_VAR(); + FREE_OP1(); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -3022,14 +3039,22 @@ ZEND_VM_HANDLER(108, ZEND_THROW, CONST|TMP|VAR|CV, ANY) zend_free_op free_op1; SAVE_OPLINE(); - value = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); + value = GET_OP1_ZVAL_PTR(BP_VAR_R); - if (OP1_TYPE == IS_CONST || UNEXPECTED(Z_TYPE_P(value) != IS_OBJECT)) { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + do { + if (OP1_TYPE == IS_CONST || UNEXPECTED(Z_TYPE_P(value) != IS_OBJECT)) { + if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_ISREF_P(value)) { + value = Z_REFVAL_P(value); + if (EXPECTED(Z_TYPE_P(value) == IS_OBJECT)) { + break; + } + } + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Can only throw objects"); } - zend_error_noreturn(E_ERROR, "Can only throw objects"); - } + } while (0); zend_exception_save(TSRMLS_C); if (OP1_TYPE != IS_TMP_VAR) { @@ -3427,9 +3452,15 @@ ZEND_VM_HANDLER(119, ZEND_SEND_ARRAY, ANY, ANY) zval *args; SAVE_OPLINE(); - args = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); + args = GET_OP1_ZVAL_PTR(BP_VAR_R); - if (Z_TYPE_P(args) != IS_ARRAY) { + if (UNEXPECTED(Z_TYPE_P(args) != IS_ARRAY)) { + if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_ISREF_P(args)) { + args = Z_REFVAL_P(args); + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY)) { + ZEND_VM_C_GOTO(send_array); + } + } zend_error(E_WARNING, "call_user_func_array() expects parameter 2 to be array, %s given", zend_get_type_by_const(Z_TYPE_P(args))); if (EX(call)->func->common.fn_flags & ZEND_ACC_CLOSURE) { OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); @@ -3441,11 +3472,13 @@ ZEND_VM_HANDLER(119, ZEND_SEND_ARRAY, ANY, ANY) EX(call)->called_scope = NULL; Z_OBJ(EX(call)->This) = NULL; } else { - uint32_t arg_num = 1; - - HashTable *ht = Z_ARRVAL_P(args); + uint32_t arg_num; + HashTable *ht; zval *arg, *param, tmp; +ZEND_VM_C_LABEL(send_array): + arg_num = 1; + ht = Z_ARRVAL_P(args); zend_vm_stack_extend_call_frame(&EX(call), 0, zend_hash_num_elements(ht) TSRMLS_CC); if (OP1_TYPE != IS_CONST && OP1_TYPE != IS_TMP_VAR && Z_IMMUTABLE_P(args)) { @@ -3814,7 +3847,7 @@ ZEND_VM_HANDLER(68, ZEND_NEW, CONST|VAR, ANY) constructor = Z_OBJ_HT(object_zval)->get_constructor(Z_OBJ(object_zval) TSRMLS_CC); if (constructor == NULL) { - if (RETURN_VALUE_USED(opline)) { + if (EXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), &object_zval); } else { OBJ_RELEASE(Z_OBJ(object_zval)); @@ -3824,14 +3857,14 @@ ZEND_VM_HANDLER(68, ZEND_NEW, CONST|VAR, ANY) /* We are not handling overloaded classes right now */ EX(call) = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION | ZEND_CALL_CTOR | - (RETURN_VALUE_USED(opline) ? 0 : ZEND_CALL_CTOR_RESULT_UNUSED), + (EXPECTED(RETURN_VALUE_USED(opline)) ? 0 : ZEND_CALL_CTOR_RESULT_UNUSED), constructor, opline->extended_value, ce, Z_OBJ(object_zval), EX(call) TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { + if (EXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), &object_zval); EX(call)->return_value = EX_VAR(opline->result.var); } else { @@ -3843,7 +3876,7 @@ ZEND_VM_HANDLER(68, ZEND_NEW, CONST|VAR, ANY) } } -ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMP|VAR|UNUSED|CV, ANY) +ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|CV, ANY) { USE_OPLINE zend_free_op free_op1; @@ -3853,15 +3886,23 @@ ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMP|VAR|UNUSED|CV, ANY) zend_object_clone_obj_t clone_call; SAVE_OPLINE(); - obj = GET_OP1_OBJ_ZVAL_PTR_DEREF(BP_VAR_R); + obj = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_R); - if (OP1_TYPE == IS_CONST || - (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(obj) != IS_OBJECT))) { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + do { + if (OP1_TYPE == IS_CONST || + (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(obj) != IS_OBJECT))) { + if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_ISREF_P(obj)) { + obj = Z_REFVAL_P(obj); + if (EXPECTED(Z_TYPE_P(obj) == IS_OBJECT)) { + break; + } + } + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "__clone method called on non-object"); } - zend_error_noreturn(E_ERROR, "__clone method called on non-object"); - } + } while (0); ce = Z_OBJCE_P(obj); clone = ce ? ce->clone : NULL; @@ -3892,11 +3933,11 @@ ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMP|VAR|UNUSED|CV, ANY) if (EXPECTED(EG(exception) == NULL)) { ZVAL_OBJ(EX_VAR(opline->result.var), clone_call(obj TSRMLS_CC)); - if (!RETURN_VALUE_USED(opline) || UNEXPECTED(EG(exception) != NULL)) { + if (UNEXPECTED(!RETURN_VALUE_USED(opline)) || UNEXPECTED(EG(exception) != NULL)) { OBJ_RELEASE(Z_OBJ_P(EX_VAR(opline->result.var))); } } - FREE_OP1_IF_VAR(); + FREE_OP1(); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -4126,7 +4167,7 @@ ZEND_VM_HANDLER(21, ZEND_CAST, CONST|TMP|VAR|CV, ANY) zval *result = EX_VAR(opline->result.var); SAVE_OPLINE(); - expr = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); + expr = GET_OP1_ZVAL_PTR(BP_VAR_R); switch (opline->extended_value) { case IS_NULL: @@ -4159,6 +4200,9 @@ ZEND_VM_HANDLER(21, ZEND_CAST, CONST|TMP|VAR|CV, ANY) ZVAL_STR(result, zval_get_string(expr)); break; default: + if (OP1_TYPE & (IS_VAR|IS_CV)) { + ZVAL_DEREF(expr); + } /* If value is already of correct type, return it directly */ if (Z_TYPE_P(expr) == opline->extended_value) { ZVAL_COPY_VALUE(result, expr); @@ -4434,15 +4478,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)); @@ -4495,7 +4539,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_OBJECT)) { + } 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 { @@ -4520,16 +4567,24 @@ ZEND_VM_HANDLER(76, ZEND_UNSET_OBJ, VAR|UNUSED|CV, CONST|TMPVAR|CV) } offset = GET_OP2_ZVAL_PTR(BP_VAR_R); - if (OP1_TYPE != IS_UNUSED) { - ZVAL_DEREF(container); - } - if (OP1_TYPE == IS_UNUSED || Z_TYPE_P(container) == IS_OBJECT) { + do { + if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT)) { + if (Z_ISREF_P(container)) { + container = Z_REFVAL_P(container); + if (Z_TYPE_P(container) != IS_OBJECT) { + break; + } + } else { + break; + } + } if (Z_OBJ_HT_P(container)->unset_property) { Z_OBJ_HT_P(container)->unset_property(container, offset, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(offset)) : NULL) TSRMLS_CC); } else { zend_error(E_NOTICE, "Trying to unset property of non-object"); } - } + } while (0); + FREE_OP2(); FREE_OP1_VAR_PTR(); CHECK_EXCEPTION(); @@ -5049,7 +5104,7 @@ ZEND_VM_HANDLER(114, ZEND_ISSET_ISEMPTY_VAR, CONST|TMPVAR|CV, UNUSED|CONST|VAR) } } -ZEND_VM_HANDLER(115, ZEND_ISSET_ISEMPTY_DIM_OBJ, CONST|TMP|VAR|UNUSED|CV, CONST|TMPVAR|CV) +ZEND_VM_HANDLER(115, ZEND_ISSET_ISEMPTY_DIM_OBJ, CONST|TMPVAR|UNUSED|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -5059,9 +5114,10 @@ ZEND_VM_HANDLER(115, ZEND_ISSET_ISEMPTY_DIM_OBJ, CONST|TMP|VAR|UNUSED|CV, CONST| zval *offset; SAVE_OPLINE(); - container = GET_OP1_OBJ_ZVAL_PTR_DEREF(BP_VAR_IS); + container = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_IS); offset = GET_OP2_ZVAL_PTR(BP_VAR_R); +ZEND_VM_C_LABEL(isset_dim_obj_again): if (OP1_TYPE != IS_UNUSED && EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { HashTable *ht = Z_ARRVAL_P(container); zval *value; @@ -5152,6 +5208,9 @@ ZEND_VM_C_LABEL(num_index_prop): if ((opline->extended_value & ZEND_ISSET) == 0) { result = !result; } + } else if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_ISREF_P(container)) { + container = Z_REFVAL_P(container); + ZEND_VM_C_GOTO(isset_dim_obj_again); } else { result = ((opline->extended_value & ZEND_ISSET) == 0); } @@ -5163,7 +5222,7 @@ ZEND_VM_C_LABEL(num_index_prop): ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(148, ZEND_ISSET_ISEMPTY_PROP_OBJ, CONST|TMP|VAR|UNUSED|CV, CONST|TMPVAR|CV) +ZEND_VM_HANDLER(148, ZEND_ISSET_ISEMPTY_PROP_OBJ, CONST|TMPVAR|UNUSED|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -5172,21 +5231,28 @@ ZEND_VM_HANDLER(148, ZEND_ISSET_ISEMPTY_PROP_OBJ, CONST|TMP|VAR|UNUSED|CV, CONST zval *offset; SAVE_OPLINE(); - container = GET_OP1_OBJ_ZVAL_PTR_DEREF(BP_VAR_IS); + container = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_IS); offset = GET_OP2_ZVAL_PTR(BP_VAR_R); - if (OP1_TYPE == IS_UNUSED || EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (EXPECTED(Z_OBJ_HT_P(container)->has_property)) { - result = Z_OBJ_HT_P(container)->has_property(container, offset, (opline->extended_value & ZEND_ISSET) == 0, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(offset)) : NULL) TSRMLS_CC); + if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT)) { + if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_ISREF_P(container)) { + container = Z_REFVAL_P(container); + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT)) { + ZEND_VM_C_GOTO(isset_no_object); + } } else { - zend_error(E_NOTICE, "Trying to check property of non-object"); - result = 0; + ZEND_VM_C_GOTO(isset_no_object); } + } + if (UNEXPECTED(!Z_OBJ_HT_P(container)->has_property)) { + zend_error(E_NOTICE, "Trying to check property of non-object"); +ZEND_VM_C_LABEL(isset_no_object): + result = ((opline->extended_value & ZEND_ISSET) == 0); + } else { + result = Z_OBJ_HT_P(container)->has_property(container, offset, (opline->extended_value & ZEND_ISSET) == 0, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(offset)) : NULL) TSRMLS_CC); if ((opline->extended_value & ZEND_ISSET) == 0) { result = !result; } - } else { - result = ((opline->extended_value & ZEND_ISSET) == 0); } FREE_OP2(); @@ -5196,7 +5262,7 @@ ZEND_VM_HANDLER(148, ZEND_ISSET_ISEMPTY_PROP_OBJ, CONST|TMP|VAR|UNUSED|CV, CONST ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(79, ZEND_EXIT, CONST|TMP|VAR|UNUSED|CV, ANY) +ZEND_VM_HANDLER(79, ZEND_EXIT, CONST|TMPVAR|UNUSED|CV, ANY) { #if !defined(ZEND_VM_SPEC) || (OP1_TYPE != IS_UNUSED) USE_OPLINE @@ -5204,13 +5270,22 @@ ZEND_VM_HANDLER(79, ZEND_EXIT, CONST|TMP|VAR|UNUSED|CV, ANY) SAVE_OPLINE(); if (OP1_TYPE != IS_UNUSED) { zend_free_op free_op1; - zval *ptr = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); + zval *ptr = GET_OP1_ZVAL_PTR(BP_VAR_R); - if (Z_TYPE_P(ptr) == IS_LONG) { - EG(exit_status) = Z_LVAL_P(ptr); - } else { - zend_print_variable(ptr TSRMLS_CC); - } + do { + if (Z_TYPE_P(ptr) == IS_LONG) { + EG(exit_status) = Z_LVAL_P(ptr); + } else { + if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_ISREF_P(ptr)) { + ptr = Z_REFVAL_P(ptr); + if (Z_TYPE_P(ptr) == IS_LONG) { + EG(exit_status) = Z_LVAL_P(ptr); + break; + } + } + zend_print_variable(ptr TSRMLS_CC); + } + } while (0); FREE_OP1(); } #endif |