From: Dmitry Stogov Date: Mon, 7 Apr 2014 22:25:49 +0000 (+0400) Subject: Optimized ASSIGN_OP X-Git-Tag: POST_PHPNG_MERGE~412^2~155 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0e7d30e8d3d3b7b637e64f6f1e2430d607d01dfc;p=php Optimized ASSIGN_OP --- diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 8ea46f4af9..f8d79a6b53 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -430,42 +430,28 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMP|VAR ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HELPER_EX(zend_binary_assign_op_helper, VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV, int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC)) +ZEND_VM_HELPER_EX(zend_binary_assign_op_dim_helper, VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV, int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC)) { USE_OPLINE zend_free_op free_op1, free_op2, free_op_data2, free_op_data1; zval *var_ptr; - zval *value; + zval *value, *container; SAVE_OPLINE(); - switch (opline->extended_value) { - case ZEND_ASSIGN_OBJ: - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_obj_helper, binary_op, binary_op); - break; - case ZEND_ASSIGN_DIM: { - zval *container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW); - - if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { - zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (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); - } else { - zval *dim = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R); + container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW); + if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } else if (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); + } else { + zval *dim = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), 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); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); - } - } - break; - default: - value = GET_OP2_ZVAL_PTR(BP_VAR_R); - var_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW); - /* do nothing */ - break; + zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), 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); + var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); } if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { @@ -473,23 +459,17 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_helper, VAR|UNUSED|CV, CONST|TMP|VAR|UNU } if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - FREE_OP2(); - FREE_OP1_VAR_PTR(); - CHECK_EXCEPTION(); - if (opline->extended_value == ZEND_ASSIGN_DIM) { - ZEND_VM_INC_OPCODE(); - } - ZEND_VM_NEXT_OPCODE(); + ZEND_VM_C_GOTO(assign_op_dim_exit); } SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) - && Z_OBJ_HANDLER_P(var_ptr, get) - && Z_OBJ_HANDLER_P(var_ptr, set)) { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { /* proxy object */ zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); Z_ADDREF_P(objval); @@ -501,77 +481,210 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_helper, VAR|UNUSED|CV, CONST|TMP|VAR|UNU binary_op(var_ptr, var_ptr, value TSRMLS_CC); } - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } + +ZEND_VM_C_LABEL(assign_op_dim_exit): FREE_OP2(); + FREE_OP(free_op_data1); + FREE_OP_VAR_PTR(free_op_data2); + FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); + ZEND_VM_INC_OPCODE(); + ZEND_VM_NEXT_OPCODE(); +} - if (opline->extended_value == ZEND_ASSIGN_DIM) { - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); - FREE_OP1_VAR_PTR(); - CHECK_EXCEPTION(); - ZEND_VM_INC_OPCODE(); +ZEND_VM_HELPER_EX(zend_binary_assign_op_helper, VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV, int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC)) +{ + USE_OPLINE + zend_free_op free_op1, free_op2; + zval *var_ptr; + zval *value; + + SAVE_OPLINE(); + value = GET_OP2_ZVAL_PTR(BP_VAR_R); + var_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW); + + if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); + } + + if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + ZEND_VM_C_GOTO(assign_op_exit); + } + + SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); + + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { + /* proxy object */ + zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); + Z_ADDREF_P(objval); + binary_op(objval, objval, value TSRMLS_CC); + Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); + zval_ptr_dtor(objval); } else { - FREE_OP1_VAR_PTR(); - CHECK_EXCEPTION(); + ZVAL_DEREF(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); } + +ZEND_VM_C_LABEL(assign_op_exit): + FREE_OP2(); + FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(23, ZEND_ASSIGN_ADD, VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV) { - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, add_function); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, add_function); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_dim_helper, binary_op, add_function); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_obj_helper, binary_op, add_function); + } } ZEND_VM_HANDLER(24, ZEND_ASSIGN_SUB, VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV) { - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, sub_function); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, sub_function); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_dim_helper, binary_op, sub_function); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_obj_helper, binary_op, sub_function); + } } ZEND_VM_HANDLER(25, ZEND_ASSIGN_MUL, VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV) { - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, mul_function); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, mul_function); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_dim_helper, binary_op, mul_function); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_obj_helper, binary_op, mul_function); + } } ZEND_VM_HANDLER(26, ZEND_ASSIGN_DIV, VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV) { - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, div_function); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, div_function); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_dim_helper, binary_op, div_function); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_obj_helper, binary_op, div_function); + } } ZEND_VM_HANDLER(27, ZEND_ASSIGN_MOD, VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV) { - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, mod_function); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, mod_function); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_dim_helper, binary_op, mod_function); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_obj_helper, binary_op, mod_function); + } } ZEND_VM_HANDLER(28, ZEND_ASSIGN_SL, VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV) { - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, shift_left_function); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, shift_left_function); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_dim_helper, binary_op, shift_left_function); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_obj_helper, binary_op, shift_left_function); + } } ZEND_VM_HANDLER(29, ZEND_ASSIGN_SR, VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV) { - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, shift_right_function); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, shift_right_function); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_dim_helper, binary_op, shift_right_function); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_obj_helper, binary_op, shift_right_function); + } } ZEND_VM_HANDLER(30, ZEND_ASSIGN_CONCAT, VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV) { - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, concat_function); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, concat_function); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_dim_helper, binary_op, concat_function); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_obj_helper, binary_op, concat_function); + } } ZEND_VM_HANDLER(31, ZEND_ASSIGN_BW_OR, VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV) { - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, bitwise_or_function); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, bitwise_or_function); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_dim_helper, binary_op, bitwise_or_function); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_obj_helper, binary_op, bitwise_or_function); + } } ZEND_VM_HANDLER(32, ZEND_ASSIGN_BW_AND, VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV) { - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, bitwise_and_function); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, bitwise_and_function); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_dim_helper, binary_op, bitwise_and_function); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_obj_helper, binary_op, bitwise_and_function); + } } ZEND_VM_HANDLER(33, ZEND_ASSIGN_BW_XOR, VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV) { - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, bitwise_xor_function); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_helper, binary_op, bitwise_xor_function); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_dim_helper, binary_op, bitwise_xor_function); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_obj_helper, binary_op, bitwise_xor_function); + } } ZEND_VM_HELPER_EX(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMP|VAR|CV, incdec_t incdec_op) diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 87882bacc6..6fd32c049b 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -13781,42 +13781,28 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(int (*b ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_CONST(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_CONST(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op1, free_op_data2, free_op_data1; zval *var_ptr; - zval *value; + zval *value, *container; SAVE_OPLINE(); - switch (opline->extended_value) { - case ZEND_ASSIGN_OBJ: - return zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - break; - case ZEND_ASSIGN_DIM: { - zval *container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - - if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { - zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_VAR == IS_VAR && !(free_op1.var != NULL)) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } else { - zval *dim = opline->op2.zv; + container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + if (IS_VAR == IS_VAR && !(free_op1.var != NULL)) { + Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ + } + return zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else { + zval *dim = opline->op2.zv; - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_CONST TSRMLS_CC); - value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); - } - } - break; - default: - value = opline->op2.zv; - var_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - /* do nothing */ - break; + zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_CONST TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); } if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { @@ -13824,23 +13810,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_CONST(int (*binar } if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - - if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; - CHECK_EXCEPTION(); - if (opline->extended_value == ZEND_ASSIGN_DIM) { - ZEND_VM_INC_OPCODE(); - } - ZEND_VM_NEXT_OPCODE(); + goto assign_op_dim_exit; } SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) - && Z_OBJ_HANDLER_P(var_ptr, get) - && Z_OBJ_HANDLER_P(var_ptr, set)) { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { /* proxy object */ zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); Z_ADDREF_P(objval); @@ -13852,76 +13832,210 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_CONST(int (*binar binary_op(var_ptr, var_ptr, value TSRMLS_CC); } - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } - if (opline->extended_value == ZEND_ASSIGN_DIM) { - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); - if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; - CHECK_EXCEPTION(); - ZEND_VM_INC_OPCODE(); +assign_op_dim_exit: + + FREE_OP(free_op_data1); + FREE_OP_VAR_PTR(free_op_data2); + if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; + CHECK_EXCEPTION(); + ZEND_VM_INC_OPCODE(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_CONST(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *var_ptr; + zval *value; + + SAVE_OPLINE(); + value = opline->op2.zv; + var_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + + if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); + } + + if (IS_VAR == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + goto assign_op_exit; + } + + SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); + + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { + /* proxy object */ + zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); + Z_ADDREF_P(objval); + binary_op(objval, objval, value TSRMLS_CC); + Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); + zval_ptr_dtor(objval); } else { - if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; - CHECK_EXCEPTION(); + ZVAL_DEREF(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); } + +assign_op_exit: + + if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } static int ZEND_FASTCALL ZEND_ASSIGN_ADD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CONST(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CONST(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CONST(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SUB_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CONST(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CONST(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CONST(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MUL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CONST(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CONST(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CONST(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_DIV_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CONST(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CONST(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CONST(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MOD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CONST(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CONST(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CONST(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CONST(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CONST(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CONST(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SR_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CONST(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CONST(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CONST(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_CONCAT_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CONST(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CONST(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CONST(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_OR_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CONST(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CONST(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CONST(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_AND_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CONST(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CONST(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CONST(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_XOR_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CONST(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CONST(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CONST(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_CONST(incdec_t incdec_op, ZEND_OPCODE_HANDLER_ARGS) @@ -16084,42 +16198,28 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(int (*bin ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_TMP(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_TMP(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op1, free_op2, free_op_data2, free_op_data1; zval *var_ptr; - zval *value; + zval *value, *container; SAVE_OPLINE(); - switch (opline->extended_value) { - case ZEND_ASSIGN_OBJ: - return zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - break; - case ZEND_ASSIGN_DIM: { - zval *container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - - if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { - zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_VAR == IS_VAR && !(free_op1.var != NULL)) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } else { - zval *dim = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + if (IS_VAR == IS_VAR && !(free_op1.var != NULL)) { + Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ + } + return zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else { + zval *dim = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_TMP_VAR TSRMLS_CC); - value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); - } - } - break; - default: - value = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - var_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - /* do nothing */ - break; + zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_TMP_VAR TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); } if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { @@ -16127,23 +16227,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_TMP(int (*binary_ } if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - zval_dtor(free_op2.var); - if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; - CHECK_EXCEPTION(); - if (opline->extended_value == ZEND_ASSIGN_DIM) { - ZEND_VM_INC_OPCODE(); - } - ZEND_VM_NEXT_OPCODE(); + goto assign_op_dim_exit; } SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) - && Z_OBJ_HANDLER_P(var_ptr, get) - && Z_OBJ_HANDLER_P(var_ptr, set)) { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { /* proxy object */ zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); Z_ADDREF_P(objval); @@ -16155,77 +16249,210 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_TMP(int (*binary_ binary_op(var_ptr, var_ptr, value TSRMLS_CC); } - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } + +assign_op_dim_exit: zval_dtor(free_op2.var); + FREE_OP(free_op_data1); + FREE_OP_VAR_PTR(free_op_data2); + if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; + CHECK_EXCEPTION(); + ZEND_VM_INC_OPCODE(); + ZEND_VM_NEXT_OPCODE(); +} - if (opline->extended_value == ZEND_ASSIGN_DIM) { - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); - if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; - CHECK_EXCEPTION(); - ZEND_VM_INC_OPCODE(); +static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_TMP(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1, free_op2; + zval *var_ptr; + zval *value; + + SAVE_OPLINE(); + value = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + var_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + + if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); + } + + if (IS_VAR == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + goto assign_op_exit; + } + + SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); + + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { + /* proxy object */ + zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); + Z_ADDREF_P(objval); + binary_op(objval, objval, value TSRMLS_CC); + Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); + zval_ptr_dtor(objval); } else { - if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; - CHECK_EXCEPTION(); + ZVAL_DEREF(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); + } + +assign_op_exit: + zval_dtor(free_op2.var); + if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } static int ZEND_FASTCALL ZEND_ASSIGN_ADD_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_TMP(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_TMP(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_TMP(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SUB_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_TMP(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_TMP(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_TMP(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MUL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_TMP(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_TMP(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_TMP(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_DIV_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_TMP(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_TMP(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_TMP(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MOD_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_TMP(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_TMP(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_TMP(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_TMP(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_TMP(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_TMP(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SR_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_TMP(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_TMP(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_TMP(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_CONCAT_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_TMP(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_TMP(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_TMP(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_OR_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_TMP(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_TMP(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_TMP(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_AND_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_TMP(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_TMP(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_TMP(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_XOR_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_TMP(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_TMP(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_TMP(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_TMP(incdec_t incdec_op, ZEND_OPCODE_HANDLER_ARGS) @@ -18004,42 +18231,28 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(int (*bin ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_VAR(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_VAR(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op1, free_op2, free_op_data2, free_op_data1; zval *var_ptr; - zval *value; + zval *value, *container; SAVE_OPLINE(); - switch (opline->extended_value) { - case ZEND_ASSIGN_OBJ: - return zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - break; - case ZEND_ASSIGN_DIM: { - zval *container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - - if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { - zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_VAR == IS_VAR && !(free_op1.var != NULL)) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } else { - zval *dim = _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + if (IS_VAR == IS_VAR && !(free_op1.var != NULL)) { + Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ + } + return zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else { + zval *dim = _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_VAR TSRMLS_CC); - value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); - } - } - break; - default: - value = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - var_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - /* do nothing */ - break; + zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_VAR TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); } if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { @@ -18047,23 +18260,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_VAR(int (*binary_ } if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - zval_ptr_dtor_nogc(free_op2.var); - if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; - CHECK_EXCEPTION(); - if (opline->extended_value == ZEND_ASSIGN_DIM) { - ZEND_VM_INC_OPCODE(); - } - ZEND_VM_NEXT_OPCODE(); + goto assign_op_dim_exit; } SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) - && Z_OBJ_HANDLER_P(var_ptr, get) - && Z_OBJ_HANDLER_P(var_ptr, set)) { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { /* proxy object */ zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); Z_ADDREF_P(objval); @@ -18075,77 +18282,210 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_VAR(int (*binary_ binary_op(var_ptr, var_ptr, value TSRMLS_CC); } - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } + +assign_op_dim_exit: zval_ptr_dtor_nogc(free_op2.var); + FREE_OP(free_op_data1); + FREE_OP_VAR_PTR(free_op_data2); + if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; + CHECK_EXCEPTION(); + ZEND_VM_INC_OPCODE(); + ZEND_VM_NEXT_OPCODE(); +} - if (opline->extended_value == ZEND_ASSIGN_DIM) { - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); - if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; - CHECK_EXCEPTION(); - ZEND_VM_INC_OPCODE(); +static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_VAR(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1, free_op2; + zval *var_ptr; + zval *value; + + SAVE_OPLINE(); + value = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + var_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + + if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); + } + + if (IS_VAR == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + goto assign_op_exit; + } + + SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); + + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { + /* proxy object */ + zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); + Z_ADDREF_P(objval); + binary_op(objval, objval, value TSRMLS_CC); + Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); + zval_ptr_dtor(objval); } else { - if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; - CHECK_EXCEPTION(); + ZVAL_DEREF(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); } + +assign_op_exit: + zval_ptr_dtor_nogc(free_op2.var); + if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } static int ZEND_FASTCALL ZEND_ASSIGN_ADD_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_VAR(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_VAR(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_VAR(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SUB_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_VAR(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_VAR(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_VAR(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MUL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_VAR(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_VAR(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_VAR(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_DIV_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_VAR(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_VAR(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_VAR(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MOD_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_VAR(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_VAR(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_VAR(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_VAR(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_VAR(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_VAR(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SR_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_VAR(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_VAR(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_VAR(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_CONCAT_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_VAR(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_VAR(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_VAR(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_OR_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_VAR(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_VAR(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_VAR(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_AND_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_VAR(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_VAR(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_VAR(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_XOR_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_VAR(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_VAR(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_VAR(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_VAR(incdec_t incdec_op, ZEND_OPCODE_HANDLER_ARGS) @@ -20007,42 +20347,28 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(int (* ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_UNUSED(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_UNUSED(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op1, free_op_data2, free_op_data1; zval *var_ptr; - zval *value; + zval *value, *container; SAVE_OPLINE(); - switch (opline->extended_value) { - case ZEND_ASSIGN_OBJ: - return zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - break; - case ZEND_ASSIGN_DIM: { - zval *container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - - if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { - zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_VAR == IS_VAR && !(free_op1.var != NULL)) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } else { - zval *dim = NULL; + container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + if (IS_VAR == IS_VAR && !(free_op1.var != NULL)) { + Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ + } + return zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else { + zval *dim = NULL; - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_UNUSED TSRMLS_CC); - value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); - } - } - break; - default: - value = NULL; - var_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - /* do nothing */ - break; + zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_UNUSED TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); } if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { @@ -20050,23 +20376,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_UNUSED(int (*bina } if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - - if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; - CHECK_EXCEPTION(); - if (opline->extended_value == ZEND_ASSIGN_DIM) { - ZEND_VM_INC_OPCODE(); - } - ZEND_VM_NEXT_OPCODE(); + goto assign_op_dim_exit; } SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) - && Z_OBJ_HANDLER_P(var_ptr, get) - && Z_OBJ_HANDLER_P(var_ptr, set)) { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { /* proxy object */ zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); Z_ADDREF_P(objval); @@ -20078,76 +20398,210 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_UNUSED(int (*bina binary_op(var_ptr, var_ptr, value TSRMLS_CC); } - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } - if (opline->extended_value == ZEND_ASSIGN_DIM) { - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); - if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; - CHECK_EXCEPTION(); - ZEND_VM_INC_OPCODE(); +assign_op_dim_exit: + + FREE_OP(free_op_data1); + FREE_OP_VAR_PTR(free_op_data2); + if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; + CHECK_EXCEPTION(); + ZEND_VM_INC_OPCODE(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_UNUSED(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *var_ptr; + zval *value; + + SAVE_OPLINE(); + value = NULL; + var_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + + if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); + } + + if (IS_VAR == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + goto assign_op_exit; + } + + SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); + + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { + /* proxy object */ + zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); + Z_ADDREF_P(objval); + binary_op(objval, objval, value TSRMLS_CC); + Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); + zval_ptr_dtor(objval); } else { - if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; - CHECK_EXCEPTION(); + ZVAL_DEREF(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); } + +assign_op_exit: + + if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } static int ZEND_FASTCALL ZEND_ASSIGN_ADD_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_UNUSED(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SUB_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_UNUSED(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MUL_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_UNUSED(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_DIV_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_UNUSED(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MOD_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_UNUSED(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SL_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_UNUSED(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SR_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_UNUSED(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_CONCAT_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_UNUSED(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_OR_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_UNUSED(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_AND_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_UNUSED(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_XOR_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_UNUSED(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_UNUSED(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_VAR_UNUSED(int type, ZEND_OPCODE_HANDLER_ARGS) @@ -21337,42 +21791,28 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CV(int (*bina ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_CV(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_CV(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op1, free_op_data2, free_op_data1; zval *var_ptr; - zval *value; + zval *value, *container; SAVE_OPLINE(); - switch (opline->extended_value) { - case ZEND_ASSIGN_OBJ: - return zend_binary_assign_op_obj_helper_SPEC_VAR_CV(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - break; - case ZEND_ASSIGN_DIM: { - zval *container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - - if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { - zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_VAR == IS_VAR && !(free_op1.var != NULL)) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_VAR_CV(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } else { - zval *dim = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + if (IS_VAR == IS_VAR && !(free_op1.var != NULL)) { + Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ + } + return zend_binary_assign_op_obj_helper_SPEC_VAR_CV(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else { + zval *dim = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_CV TSRMLS_CC); - value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); - } - } - break; - default: - value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); - var_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - /* do nothing */ - break; + zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_CV TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); } if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { @@ -21380,23 +21820,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_CV(int (*binary_o } if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - - if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; - CHECK_EXCEPTION(); - if (opline->extended_value == ZEND_ASSIGN_DIM) { - ZEND_VM_INC_OPCODE(); - } - ZEND_VM_NEXT_OPCODE(); + goto assign_op_dim_exit; } SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) - && Z_OBJ_HANDLER_P(var_ptr, get) - && Z_OBJ_HANDLER_P(var_ptr, set)) { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { /* proxy object */ zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); Z_ADDREF_P(objval); @@ -21408,76 +21842,210 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_CV(int (*binary_o binary_op(var_ptr, var_ptr, value TSRMLS_CC); } - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } - if (opline->extended_value == ZEND_ASSIGN_DIM) { - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); - if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; - CHECK_EXCEPTION(); - ZEND_VM_INC_OPCODE(); +assign_op_dim_exit: + + FREE_OP(free_op_data1); + FREE_OP_VAR_PTR(free_op_data2); + if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; + CHECK_EXCEPTION(); + ZEND_VM_INC_OPCODE(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_CV(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *var_ptr; + zval *value; + + SAVE_OPLINE(); + value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + var_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + + if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); + } + + if (IS_VAR == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + goto assign_op_exit; + } + + SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); + + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { + /* proxy object */ + zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); + Z_ADDREF_P(objval); + binary_op(objval, objval, value TSRMLS_CC); + Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); + zval_ptr_dtor(objval); } else { - if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; - CHECK_EXCEPTION(); + ZVAL_DEREF(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); + } + +assign_op_exit: + + if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } static int ZEND_FASTCALL ZEND_ASSIGN_ADD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CV(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CV(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CV(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CV(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SUB_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CV(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CV(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CV(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CV(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MUL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CV(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CV(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CV(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CV(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_DIV_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CV(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CV(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CV(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CV(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MOD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CV(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CV(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CV(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CV(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CV(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CV(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CV(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CV(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SR_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CV(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CV(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CV(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CV(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_CONCAT_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CV(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CV(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CV(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CV(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_OR_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CV(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CV(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CV(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CV(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_AND_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CV(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CV(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CV(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CV(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_XOR_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_VAR_CV(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_VAR_CV(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_VAR_CV(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_VAR_CV(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_CV(incdec_t incdec_op, ZEND_OPCODE_HANDLER_ARGS) @@ -23119,42 +23687,28 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(int ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_CONST(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_CONST(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op_data2, free_op_data1; zval *var_ptr; - zval *value; + zval *value, *container; SAVE_OPLINE(); - switch (opline->extended_value) { - case ZEND_ASSIGN_OBJ: - return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - break; - case ZEND_ASSIGN_DIM: { - zval *container = _get_obj_zval_ptr_unused(TSRMLS_C); - - if (IS_UNUSED == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { - zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_UNUSED == IS_VAR && !0) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } else { - zval *dim = opline->op2.zv; + container = _get_obj_zval_ptr_unused(TSRMLS_C); + if (IS_UNUSED == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + if (IS_UNUSED == IS_VAR && !0) { + Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ + } + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else { + zval *dim = opline->op2.zv; - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_CONST TSRMLS_CC); - value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); - } - } - break; - default: - value = opline->op2.zv; - var_ptr = NULL; - /* do nothing */ - break; + zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_CONST TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); } if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { @@ -23162,23 +23716,69 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_CONST(int (*bi } if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } + goto assign_op_dim_exit; + } + SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - CHECK_EXCEPTION(); - if (opline->extended_value == ZEND_ASSIGN_DIM) { - ZEND_VM_INC_OPCODE(); + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { + /* proxy object */ + zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); + Z_ADDREF_P(objval); + binary_op(objval, objval, value TSRMLS_CC); + Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); + zval_ptr_dtor(objval); + } else { + ZVAL_DEREF(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); + } + +assign_op_dim_exit: + + FREE_OP(free_op_data1); + FREE_OP_VAR_PTR(free_op_data2); + + CHECK_EXCEPTION(); + ZEND_VM_INC_OPCODE(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_CONST(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *var_ptr; + zval *value; + + SAVE_OPLINE(); + value = opline->op2.zv; + var_ptr = NULL; + + if (IS_UNUSED == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); + } + + if (IS_UNUSED == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); } - ZEND_VM_NEXT_OPCODE(); + goto assign_op_exit; } SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) - && Z_OBJ_HANDLER_P(var_ptr, get) - && Z_OBJ_HANDLER_P(var_ptr, set)) { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { /* proxy object */ zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); Z_ADDREF_P(objval); @@ -23190,76 +23790,158 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_CONST(int (*bi binary_op(var_ptr, var_ptr, value TSRMLS_CC); } - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } - if (opline->extended_value == ZEND_ASSIGN_DIM) { - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); +assign_op_exit: - CHECK_EXCEPTION(); - ZEND_VM_INC_OPCODE(); - } else { - CHECK_EXCEPTION(); - } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } static int ZEND_FASTCALL ZEND_ASSIGN_ADD_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CONST(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SUB_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CONST(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MUL_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CONST(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_DIV_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CONST(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MOD_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CONST(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SL_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CONST(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SR_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CONST(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_CONCAT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CONST(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_OR_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CONST(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_AND_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CONST(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_XOR_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CONST(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CONST(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_CONST(incdec_t incdec_op, ZEND_OPCODE_HANDLER_ARGS) @@ -24433,42 +25115,28 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(int (* ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_TMP(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_TMP(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op2, free_op_data2, free_op_data1; zval *var_ptr; - zval *value; + zval *value, *container; SAVE_OPLINE(); - switch (opline->extended_value) { - case ZEND_ASSIGN_OBJ: - return zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - break; - case ZEND_ASSIGN_DIM: { - zval *container = _get_obj_zval_ptr_unused(TSRMLS_C); - - if (IS_UNUSED == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { - zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_UNUSED == IS_VAR && !0) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } else { - zval *dim = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + container = _get_obj_zval_ptr_unused(TSRMLS_C); + if (IS_UNUSED == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + if (IS_UNUSED == IS_VAR && !0) { + Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ + } + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else { + zval *dim = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_TMP_VAR TSRMLS_CC); - value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); - } - } - break; - default: - value = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - var_ptr = NULL; - /* do nothing */ - break; + zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_TMP_VAR TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); } if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { @@ -24476,23 +25144,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_TMP(int (*bina } if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - zval_dtor(free_op2.var); - - CHECK_EXCEPTION(); - if (opline->extended_value == ZEND_ASSIGN_DIM) { - ZEND_VM_INC_OPCODE(); - } - ZEND_VM_NEXT_OPCODE(); + goto assign_op_dim_exit; } SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) - && Z_OBJ_HANDLER_P(var_ptr, get) - && Z_OBJ_HANDLER_P(var_ptr, set)) { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { /* proxy object */ zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); Z_ADDREF_P(objval); @@ -24504,77 +25166,210 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_TMP(int (*bina binary_op(var_ptr, var_ptr, value TSRMLS_CC); } - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } - zval_dtor(free_op2.var); - - if (opline->extended_value == ZEND_ASSIGN_DIM) { - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); - CHECK_EXCEPTION(); - ZEND_VM_INC_OPCODE(); - } else { +assign_op_dim_exit: + zval_dtor(free_op2.var); + FREE_OP(free_op_data1); + FREE_OP_VAR_PTR(free_op_data2); - CHECK_EXCEPTION(); - } + CHECK_EXCEPTION(); + ZEND_VM_INC_OPCODE(); ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL ZEND_ASSIGN_ADD_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_TMP(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); -} + USE_OPLINE + zend_free_op free_op2; + zval *var_ptr; + zval *value; -static int ZEND_FASTCALL ZEND_ASSIGN_SUB_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + SAVE_OPLINE(); + value = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + var_ptr = NULL; + + if (IS_UNUSED == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); + } + + if (IS_UNUSED == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + goto assign_op_exit; + } + + SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); + + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { + /* proxy object */ + zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); + Z_ADDREF_P(objval); + binary_op(objval, objval, value TSRMLS_CC); + Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); + zval_ptr_dtor(objval); + } else { + ZVAL_DEREF(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); + } + +assign_op_exit: + zval_dtor(free_op2.var); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_ASSIGN_ADD_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_TMP(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } +} + +static int ZEND_FASTCALL ZEND_ASSIGN_SUB_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_TMP(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MUL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_TMP(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_DIV_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_TMP(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MOD_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_TMP(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_TMP(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SR_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_TMP(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_CONCAT_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_TMP(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_OR_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_TMP(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_AND_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_TMP(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_XOR_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_TMP(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_TMP(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_TMP(incdec_t incdec_op, ZEND_OPCODE_HANDLER_ARGS) @@ -25662,42 +26457,28 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(int (* ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_VAR(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_VAR(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op2, free_op_data2, free_op_data1; zval *var_ptr; - zval *value; + zval *value, *container; SAVE_OPLINE(); - switch (opline->extended_value) { - case ZEND_ASSIGN_OBJ: - return zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - break; - case ZEND_ASSIGN_DIM: { - zval *container = _get_obj_zval_ptr_unused(TSRMLS_C); - - if (IS_UNUSED == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { - zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_UNUSED == IS_VAR && !0) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } else { - zval *dim = _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + container = _get_obj_zval_ptr_unused(TSRMLS_C); + if (IS_UNUSED == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + if (IS_UNUSED == IS_VAR && !0) { + Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ + } + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else { + zval *dim = _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_VAR TSRMLS_CC); - value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); - } - } - break; - default: - value = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - var_ptr = NULL; - /* do nothing */ - break; + zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_VAR TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); } if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { @@ -25705,23 +26486,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_VAR(int (*bina } if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - zval_ptr_dtor_nogc(free_op2.var); - - CHECK_EXCEPTION(); - if (opline->extended_value == ZEND_ASSIGN_DIM) { - ZEND_VM_INC_OPCODE(); - } - ZEND_VM_NEXT_OPCODE(); + goto assign_op_dim_exit; } SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) - && Z_OBJ_HANDLER_P(var_ptr, get) - && Z_OBJ_HANDLER_P(var_ptr, set)) { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { /* proxy object */ zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); Z_ADDREF_P(objval); @@ -25733,77 +26508,210 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_VAR(int (*bina binary_op(var_ptr, var_ptr, value TSRMLS_CC); } - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } + +assign_op_dim_exit: zval_ptr_dtor_nogc(free_op2.var); + FREE_OP(free_op_data1); + FREE_OP_VAR_PTR(free_op_data2); - if (opline->extended_value == ZEND_ASSIGN_DIM) { - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); + CHECK_EXCEPTION(); + ZEND_VM_INC_OPCODE(); + ZEND_VM_NEXT_OPCODE(); +} - CHECK_EXCEPTION(); - ZEND_VM_INC_OPCODE(); +static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_VAR(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op2; + zval *var_ptr; + zval *value; + + SAVE_OPLINE(); + value = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + var_ptr = NULL; + + if (IS_UNUSED == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); + } + + if (IS_UNUSED == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + goto assign_op_exit; + } + + SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); + + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { + /* proxy object */ + zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); + Z_ADDREF_P(objval); + binary_op(objval, objval, value TSRMLS_CC); + Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); + zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); + } - CHECK_EXCEPTION(); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } + +assign_op_exit: + zval_ptr_dtor_nogc(free_op2.var); + + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } static int ZEND_FASTCALL ZEND_ASSIGN_ADD_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_VAR(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SUB_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_VAR(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MUL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_VAR(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_DIV_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_VAR(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MOD_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_VAR(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_VAR(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SR_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_VAR(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_CONCAT_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_VAR(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_OR_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_VAR(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_AND_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_VAR(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_XOR_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_VAR(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_VAR(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_VAR(incdec_t incdec_op, ZEND_OPCODE_HANDLER_ARGS) @@ -26892,42 +27800,28 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(int ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_UNUSED(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op_data2, free_op_data1; zval *var_ptr; - zval *value; + zval *value, *container; SAVE_OPLINE(); - switch (opline->extended_value) { - case ZEND_ASSIGN_OBJ: - return zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - break; - case ZEND_ASSIGN_DIM: { - zval *container = _get_obj_zval_ptr_unused(TSRMLS_C); - - if (IS_UNUSED == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { - zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_UNUSED == IS_VAR && !0) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } else { - zval *dim = NULL; + container = _get_obj_zval_ptr_unused(TSRMLS_C); + if (IS_UNUSED == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + if (IS_UNUSED == IS_VAR && !0) { + Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ + } + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else { + zval *dim = NULL; - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_UNUSED TSRMLS_CC); - value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); - } - } - break; - default: - value = NULL; - var_ptr = NULL; - /* do nothing */ - break; + zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_UNUSED TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); } if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { @@ -26935,23 +27829,69 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(int (*b } if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } + goto assign_op_dim_exit; + } + SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - CHECK_EXCEPTION(); - if (opline->extended_value == ZEND_ASSIGN_DIM) { - ZEND_VM_INC_OPCODE(); + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { + /* proxy object */ + zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); + Z_ADDREF_P(objval); + binary_op(objval, objval, value TSRMLS_CC); + Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); + zval_ptr_dtor(objval); + } else { + ZVAL_DEREF(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); + } + +assign_op_dim_exit: + + FREE_OP(free_op_data1); + FREE_OP_VAR_PTR(free_op_data2); + + CHECK_EXCEPTION(); + ZEND_VM_INC_OPCODE(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *var_ptr; + zval *value; + + SAVE_OPLINE(); + value = NULL; + var_ptr = NULL; + + if (IS_UNUSED == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); + } + + if (IS_UNUSED == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); } - ZEND_VM_NEXT_OPCODE(); + goto assign_op_exit; } SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) - && Z_OBJ_HANDLER_P(var_ptr, get) - && Z_OBJ_HANDLER_P(var_ptr, set)) { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { /* proxy object */ zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); Z_ADDREF_P(objval); @@ -26963,76 +27903,158 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(int (*b binary_op(var_ptr, var_ptr, value TSRMLS_CC); } - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } - if (opline->extended_value == ZEND_ASSIGN_DIM) { - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); +assign_op_exit: - CHECK_EXCEPTION(); - ZEND_VM_INC_OPCODE(); - } else { - CHECK_EXCEPTION(); - } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } static int ZEND_FASTCALL ZEND_ASSIGN_ADD_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_UNUSED(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SUB_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_UNUSED(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MUL_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_UNUSED(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_DIV_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_UNUSED(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MOD_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_UNUSED(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SL_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_UNUSED(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SR_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_UNUSED(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_CONCAT_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_UNUSED(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_OR_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_UNUSED(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_AND_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_UNUSED(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_XOR_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_UNUSED(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -27290,42 +28312,28 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(int (*b ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_CV(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_CV(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op_data2, free_op_data1; zval *var_ptr; - zval *value; + zval *value, *container; SAVE_OPLINE(); - switch (opline->extended_value) { - case ZEND_ASSIGN_OBJ: - return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - break; - case ZEND_ASSIGN_DIM: { - zval *container = _get_obj_zval_ptr_unused(TSRMLS_C); - - if (IS_UNUSED == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { - zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_UNUSED == IS_VAR && !0) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } else { - zval *dim = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + container = _get_obj_zval_ptr_unused(TSRMLS_C); + if (IS_UNUSED == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + if (IS_UNUSED == IS_VAR && !0) { + Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ + } + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else { + zval *dim = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_CV TSRMLS_CC); - value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); - } - } - break; - default: - value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); - var_ptr = NULL; - /* do nothing */ - break; + zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_CV TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); } if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { @@ -27333,23 +28341,69 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_CV(int (*binar } if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } + goto assign_op_dim_exit; + } + SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - CHECK_EXCEPTION(); - if (opline->extended_value == ZEND_ASSIGN_DIM) { - ZEND_VM_INC_OPCODE(); + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { + /* proxy object */ + zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); + Z_ADDREF_P(objval); + binary_op(objval, objval, value TSRMLS_CC); + Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); + zval_ptr_dtor(objval); + } else { + ZVAL_DEREF(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); + } + +assign_op_dim_exit: + + FREE_OP(free_op_data1); + FREE_OP_VAR_PTR(free_op_data2); + + CHECK_EXCEPTION(); + ZEND_VM_INC_OPCODE(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_CV(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *var_ptr; + zval *value; + + SAVE_OPLINE(); + value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + var_ptr = NULL; + + if (IS_UNUSED == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); + } + + if (IS_UNUSED == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); } - ZEND_VM_NEXT_OPCODE(); + goto assign_op_exit; } SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) - && Z_OBJ_HANDLER_P(var_ptr, get) - && Z_OBJ_HANDLER_P(var_ptr, set)) { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { /* proxy object */ zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); Z_ADDREF_P(objval); @@ -27361,76 +28415,158 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_CV(int (*binar binary_op(var_ptr, var_ptr, value TSRMLS_CC); } - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } - if (opline->extended_value == ZEND_ASSIGN_DIM) { - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); +assign_op_exit: - CHECK_EXCEPTION(); - ZEND_VM_INC_OPCODE(); - } else { - CHECK_EXCEPTION(); - } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } static int ZEND_FASTCALL ZEND_ASSIGN_ADD_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CV(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CV(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CV(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SUB_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CV(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CV(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CV(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MUL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CV(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CV(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CV(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_DIV_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CV(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CV(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CV(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MOD_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CV(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CV(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CV(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CV(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CV(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CV(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SR_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CV(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CV(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CV(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_CONCAT_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CV(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CV(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CV(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_OR_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CV(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CV(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CV(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_AND_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CV(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CV(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CV(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_XOR_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_UNUSED_CV(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_UNUSED_CV(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_UNUSED_CV(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_CV(incdec_t incdec_op, ZEND_OPCODE_HANDLER_ARGS) @@ -30018,42 +31154,28 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CONST(int (*bi ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_CONST(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_CONST(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op_data2, free_op_data1; zval *var_ptr; - zval *value; + zval *value, *container; SAVE_OPLINE(); - switch (opline->extended_value) { - case ZEND_ASSIGN_OBJ: - return zend_binary_assign_op_obj_helper_SPEC_CV_CONST(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - break; - case ZEND_ASSIGN_DIM: { - zval *container = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); - - if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { - zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_CV == IS_VAR && !0) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_CV_CONST(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } else { - zval *dim = opline->op2.zv; + container = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); + if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + if (IS_CV == IS_VAR && !0) { + Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ + } + return zend_binary_assign_op_obj_helper_SPEC_CV_CONST(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else { + zval *dim = opline->op2.zv; - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_CONST TSRMLS_CC); - value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); - } - } - break; - default: - value = opline->op2.zv; - var_ptr = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); - /* do nothing */ - break; + zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_CONST TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); } if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { @@ -30061,23 +31183,69 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_CONST(int (*binary } if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } + goto assign_op_dim_exit; + } + SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - CHECK_EXCEPTION(); - if (opline->extended_value == ZEND_ASSIGN_DIM) { - ZEND_VM_INC_OPCODE(); + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { + /* proxy object */ + zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); + Z_ADDREF_P(objval); + binary_op(objval, objval, value TSRMLS_CC); + Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); + zval_ptr_dtor(objval); + } else { + ZVAL_DEREF(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); + } + +assign_op_dim_exit: + + FREE_OP(free_op_data1); + FREE_OP_VAR_PTR(free_op_data2); + + CHECK_EXCEPTION(); + ZEND_VM_INC_OPCODE(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_CONST(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *var_ptr; + zval *value; + + SAVE_OPLINE(); + value = opline->op2.zv; + var_ptr = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); + + if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); + } + + if (IS_CV == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); } - ZEND_VM_NEXT_OPCODE(); + goto assign_op_exit; } SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) - && Z_OBJ_HANDLER_P(var_ptr, get) - && Z_OBJ_HANDLER_P(var_ptr, set)) { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { /* proxy object */ zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); Z_ADDREF_P(objval); @@ -30089,76 +31257,158 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_CONST(int (*binary binary_op(var_ptr, var_ptr, value TSRMLS_CC); } - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } - if (opline->extended_value == ZEND_ASSIGN_DIM) { - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); +assign_op_exit: - CHECK_EXCEPTION(); - ZEND_VM_INC_OPCODE(); - } else { - CHECK_EXCEPTION(); - } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } static int ZEND_FASTCALL ZEND_ASSIGN_ADD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CONST(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CONST(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CONST(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CONST(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SUB_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CONST(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CONST(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CONST(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CONST(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MUL_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CONST(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CONST(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CONST(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CONST(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_DIV_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CONST(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CONST(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CONST(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CONST(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MOD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CONST(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CONST(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CONST(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CONST(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SL_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CONST(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CONST(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CONST(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CONST(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SR_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CONST(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CONST(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CONST(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CONST(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_CONCAT_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CONST(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CONST(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CONST(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CONST(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_OR_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CONST(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CONST(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CONST(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CONST(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_AND_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CONST(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CONST(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CONST(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CONST(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_XOR_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CONST(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CONST(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CONST(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CONST(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_CONST(incdec_t incdec_op, ZEND_OPCODE_HANDLER_ARGS) @@ -32107,42 +33357,28 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_TMP(int (*bina ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_TMP(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_TMP(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op2, free_op_data2, free_op_data1; zval *var_ptr; - zval *value; + zval *value, *container; SAVE_OPLINE(); - switch (opline->extended_value) { - case ZEND_ASSIGN_OBJ: - return zend_binary_assign_op_obj_helper_SPEC_CV_TMP(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - break; - case ZEND_ASSIGN_DIM: { - zval *container = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); - - if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { - zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_CV == IS_VAR && !0) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_CV_TMP(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } else { - zval *dim = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + container = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); + if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + if (IS_CV == IS_VAR && !0) { + Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ + } + return zend_binary_assign_op_obj_helper_SPEC_CV_TMP(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else { + zval *dim = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_TMP_VAR TSRMLS_CC); - value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); - } - } - break; - default: - value = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - var_ptr = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); - /* do nothing */ - break; + zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_TMP_VAR TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); } if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { @@ -32150,23 +33386,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_TMP(int (*binary_o } if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - zval_dtor(free_op2.var); - - CHECK_EXCEPTION(); - if (opline->extended_value == ZEND_ASSIGN_DIM) { - ZEND_VM_INC_OPCODE(); - } - ZEND_VM_NEXT_OPCODE(); + goto assign_op_dim_exit; } SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) - && Z_OBJ_HANDLER_P(var_ptr, get) - && Z_OBJ_HANDLER_P(var_ptr, set)) { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { /* proxy object */ zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); Z_ADDREF_P(objval); @@ -32178,77 +33408,210 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_TMP(int (*binary_o binary_op(var_ptr, var_ptr, value TSRMLS_CC); } - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } + +assign_op_dim_exit: zval_dtor(free_op2.var); + FREE_OP(free_op_data1); + FREE_OP_VAR_PTR(free_op_data2); - if (opline->extended_value == ZEND_ASSIGN_DIM) { - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); + CHECK_EXCEPTION(); + ZEND_VM_INC_OPCODE(); + ZEND_VM_NEXT_OPCODE(); +} - CHECK_EXCEPTION(); - ZEND_VM_INC_OPCODE(); +static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_TMP(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op2; + zval *var_ptr; + zval *value; + + SAVE_OPLINE(); + value = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + var_ptr = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); + + if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); + } + + if (IS_CV == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + goto assign_op_exit; + } + + SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); + + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { + /* proxy object */ + zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); + Z_ADDREF_P(objval); + binary_op(objval, objval, value TSRMLS_CC); + Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); + zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); + } - CHECK_EXCEPTION(); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } + +assign_op_exit: + zval_dtor(free_op2.var); + + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } static int ZEND_FASTCALL ZEND_ASSIGN_ADD_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_TMP(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_TMP(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_TMP(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_TMP(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SUB_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_TMP(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_TMP(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_TMP(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_TMP(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MUL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_TMP(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_TMP(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_TMP(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_TMP(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_DIV_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_TMP(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_TMP(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_TMP(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_TMP(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MOD_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_TMP(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_TMP(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_TMP(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_TMP(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_TMP(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_TMP(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_TMP(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_TMP(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SR_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_TMP(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_TMP(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_TMP(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_TMP(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_CONCAT_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_TMP(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_TMP(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_TMP(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_TMP(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_OR_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_TMP(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_TMP(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_TMP(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_TMP(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_AND_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_TMP(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_TMP(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_TMP(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_TMP(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_XOR_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_TMP(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_TMP(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_TMP(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_TMP(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_TMP(incdec_t incdec_op, ZEND_OPCODE_HANDLER_ARGS) @@ -33906,42 +35269,28 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_VAR(int (*bina ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_VAR(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_VAR(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op2, free_op_data2, free_op_data1; zval *var_ptr; - zval *value; + zval *value, *container; SAVE_OPLINE(); - switch (opline->extended_value) { - case ZEND_ASSIGN_OBJ: - return zend_binary_assign_op_obj_helper_SPEC_CV_VAR(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - break; - case ZEND_ASSIGN_DIM: { - zval *container = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); - - if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { - zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_CV == IS_VAR && !0) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_CV_VAR(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } else { - zval *dim = _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + container = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); + if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + if (IS_CV == IS_VAR && !0) { + Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ + } + return zend_binary_assign_op_obj_helper_SPEC_CV_VAR(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else { + zval *dim = _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_VAR TSRMLS_CC); - value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); - } - } - break; - default: - value = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - var_ptr = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); - /* do nothing */ - break; + zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_VAR TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); } if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { @@ -33949,23 +35298,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_VAR(int (*binary_o } if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - zval_ptr_dtor_nogc(free_op2.var); - - CHECK_EXCEPTION(); - if (opline->extended_value == ZEND_ASSIGN_DIM) { - ZEND_VM_INC_OPCODE(); - } - ZEND_VM_NEXT_OPCODE(); + goto assign_op_dim_exit; } SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) - && Z_OBJ_HANDLER_P(var_ptr, get) - && Z_OBJ_HANDLER_P(var_ptr, set)) { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { /* proxy object */ zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); Z_ADDREF_P(objval); @@ -33977,77 +35320,210 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_VAR(int (*binary_o binary_op(var_ptr, var_ptr, value TSRMLS_CC); } - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } + +assign_op_dim_exit: zval_ptr_dtor_nogc(free_op2.var); + FREE_OP(free_op_data1); + FREE_OP_VAR_PTR(free_op_data2); - if (opline->extended_value == ZEND_ASSIGN_DIM) { - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); + CHECK_EXCEPTION(); + ZEND_VM_INC_OPCODE(); + ZEND_VM_NEXT_OPCODE(); +} - CHECK_EXCEPTION(); - ZEND_VM_INC_OPCODE(); +static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_VAR(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op2; + zval *var_ptr; + zval *value; + + SAVE_OPLINE(); + value = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + var_ptr = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); + + if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); + } + + if (IS_CV == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + goto assign_op_exit; + } + + SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); + + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { + /* proxy object */ + zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); + Z_ADDREF_P(objval); + binary_op(objval, objval, value TSRMLS_CC); + Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); + zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); + } - CHECK_EXCEPTION(); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } + +assign_op_exit: + zval_ptr_dtor_nogc(free_op2.var); + + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } static int ZEND_FASTCALL ZEND_ASSIGN_ADD_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_VAR(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_VAR(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_VAR(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_VAR(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SUB_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_VAR(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_VAR(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_VAR(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_VAR(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MUL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_VAR(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_VAR(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_VAR(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_VAR(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_DIV_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_VAR(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_VAR(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_VAR(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_VAR(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MOD_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_VAR(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_VAR(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_VAR(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_VAR(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_VAR(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_VAR(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_VAR(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_VAR(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SR_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_VAR(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_VAR(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_VAR(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_VAR(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_CONCAT_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_VAR(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_VAR(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_VAR(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_VAR(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_OR_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_VAR(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_VAR(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_VAR(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_VAR(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_AND_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_VAR(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_VAR(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_VAR(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_VAR(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_XOR_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_VAR(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_VAR(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_VAR(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_VAR(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_VAR(incdec_t incdec_op, ZEND_OPCODE_HANDLER_ARGS) @@ -35787,42 +37263,28 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(int (*b ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_UNUSED(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_UNUSED(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op_data2, free_op_data1; zval *var_ptr; - zval *value; + zval *value, *container; SAVE_OPLINE(); - switch (opline->extended_value) { - case ZEND_ASSIGN_OBJ: - return zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - break; - case ZEND_ASSIGN_DIM: { - zval *container = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); - - if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { - zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_CV == IS_VAR && !0) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } else { - zval *dim = NULL; + container = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); + if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + if (IS_CV == IS_VAR && !0) { + Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ + } + return zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else { + zval *dim = NULL; - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_UNUSED TSRMLS_CC); - value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); - } - } - break; - default: - value = NULL; - var_ptr = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); - /* do nothing */ - break; + zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_UNUSED TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); } if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { @@ -35830,23 +37292,69 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_UNUSED(int (*binar } if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } + goto assign_op_dim_exit; + } + SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - CHECK_EXCEPTION(); - if (opline->extended_value == ZEND_ASSIGN_DIM) { - ZEND_VM_INC_OPCODE(); + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { + /* proxy object */ + zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); + Z_ADDREF_P(objval); + binary_op(objval, objval, value TSRMLS_CC); + Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); + zval_ptr_dtor(objval); + } else { + ZVAL_DEREF(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); + } + +assign_op_dim_exit: + + FREE_OP(free_op_data1); + FREE_OP_VAR_PTR(free_op_data2); + + CHECK_EXCEPTION(); + ZEND_VM_INC_OPCODE(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_UNUSED(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *var_ptr; + zval *value; + + SAVE_OPLINE(); + value = NULL; + var_ptr = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); + + if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); + } + + if (IS_CV == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); } - ZEND_VM_NEXT_OPCODE(); + goto assign_op_exit; } SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) - && Z_OBJ_HANDLER_P(var_ptr, get) - && Z_OBJ_HANDLER_P(var_ptr, set)) { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { /* proxy object */ zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); Z_ADDREF_P(objval); @@ -35858,76 +37366,158 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_UNUSED(int (*binar binary_op(var_ptr, var_ptr, value TSRMLS_CC); } - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } - if (opline->extended_value == ZEND_ASSIGN_DIM) { - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); +assign_op_exit: - CHECK_EXCEPTION(); - ZEND_VM_INC_OPCODE(); - } else { - CHECK_EXCEPTION(); - } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } static int ZEND_FASTCALL ZEND_ASSIGN_ADD_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_UNUSED(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_UNUSED(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_UNUSED(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SUB_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_UNUSED(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_UNUSED(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_UNUSED(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MUL_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_UNUSED(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_UNUSED(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_UNUSED(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_DIV_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_UNUSED(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_UNUSED(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_UNUSED(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MOD_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_UNUSED(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_UNUSED(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_UNUSED(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SL_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_UNUSED(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_UNUSED(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_UNUSED(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SR_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_UNUSED(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_UNUSED(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_UNUSED(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_CONCAT_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_UNUSED(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_UNUSED(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_UNUSED(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_OR_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_UNUSED(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_UNUSED(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_UNUSED(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_AND_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_UNUSED(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_UNUSED(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_UNUSED(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_XOR_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_UNUSED(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_UNUSED(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_UNUSED(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CV_UNUSED(int type, ZEND_OPCODE_HANDLER_ARGS) @@ -36982,42 +38572,28 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CV(int (*binar ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_CV(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_CV(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op_data2, free_op_data1; zval *var_ptr; - zval *value; + zval *value, *container; SAVE_OPLINE(); - switch (opline->extended_value) { - case ZEND_ASSIGN_OBJ: - return zend_binary_assign_op_obj_helper_SPEC_CV_CV(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - break; - case ZEND_ASSIGN_DIM: { - zval *container = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); - - if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { - zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_CV == IS_VAR && !0) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_CV_CV(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } else { - zval *dim = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + container = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); + if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + if (IS_CV == IS_VAR && !0) { + Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ + } + return zend_binary_assign_op_obj_helper_SPEC_CV_CV(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else { + zval *dim = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_CV TSRMLS_CC); - value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); - } - } - break; - default: - value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); - var_ptr = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); - /* do nothing */ - break; + zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_CV TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); } if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { @@ -37025,23 +38601,69 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_CV(int (*binary_op } if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } + goto assign_op_dim_exit; + } + SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - CHECK_EXCEPTION(); - if (opline->extended_value == ZEND_ASSIGN_DIM) { - ZEND_VM_INC_OPCODE(); + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { + /* proxy object */ + zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); + Z_ADDREF_P(objval); + binary_op(objval, objval, value TSRMLS_CC); + Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); + zval_ptr_dtor(objval); + } else { + ZVAL_DEREF(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); + } + +assign_op_dim_exit: + + FREE_OP(free_op_data1); + FREE_OP_VAR_PTR(free_op_data2); + + CHECK_EXCEPTION(); + ZEND_VM_INC_OPCODE(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_CV(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *var_ptr; + zval *value; + + SAVE_OPLINE(); + value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + var_ptr = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); + + if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); + } + + if (IS_CV == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); } - ZEND_VM_NEXT_OPCODE(); + goto assign_op_exit; } SEPARATE_ZVAL_IF_NOT_REF(var_ptr); + ZVAL_DEREF(var_ptr); - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) - && Z_OBJ_HANDLER_P(var_ptr, get) - && Z_OBJ_HANDLER_P(var_ptr, set)) { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && + UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { /* proxy object */ zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr TSRMLS_CC); Z_ADDREF_P(objval); @@ -37053,76 +38675,158 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_CV(int (*binary_op binary_op(var_ptr, var_ptr, value TSRMLS_CC); } - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } - if (opline->extended_value == ZEND_ASSIGN_DIM) { - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); +assign_op_exit: - CHECK_EXCEPTION(); - ZEND_VM_INC_OPCODE(); - } else { - CHECK_EXCEPTION(); - } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } static int ZEND_FASTCALL ZEND_ASSIGN_ADD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CV(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CV(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CV(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CV(add_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SUB_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CV(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CV(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CV(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CV(sub_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MUL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CV(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CV(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CV(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CV(mul_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_DIV_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CV(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CV(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CV(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CV(div_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_MOD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CV(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CV(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CV(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CV(mod_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CV(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CV(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CV(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CV(shift_left_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_SR_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CV(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CV(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CV(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CV(shift_right_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_CONCAT_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CV(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CV(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CV(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CV(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_OR_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CV(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CV(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CV(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CV(bitwise_or_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_AND_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CV(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CV(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CV(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CV(bitwise_and_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL ZEND_ASSIGN_BW_XOR_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - return zend_binary_assign_op_helper_SPEC_CV_CV(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + USE_OPLINE + + if (EXPECTED(opline->extended_value == 0)) { + return zend_binary_assign_op_helper_SPEC_CV_CV(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { + return zend_binary_assign_op_dim_helper_SPEC_CV_CV(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) */ { + return zend_binary_assign_op_obj_helper_SPEC_CV_CV(bitwise_xor_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_CV(incdec_t incdec_op, ZEND_OPCODE_HANDLER_ARGS)