diff options
Diffstat (limited to 'Zend/zend_vm_def.h')
-rw-r--r-- | Zend/zend_vm_def.h | 3331 |
1 files changed, 1925 insertions, 1406 deletions
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 6f9aca4b55..40b20f0d9c 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | Zend Engine | +----------------------------------------------------------------------+ - | Copyright (c) 1998-2018 Zend Technologies Ltd. (http://www.zend.com) | + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | +----------------------------------------------------------------------+ | This source file is subject to version 2.00 of the Zend license, | | that is bundled with this package in the file LICENSE, and is | @@ -23,101 +23,159 @@ * php zend_vm_gen.php */ -ZEND_VM_COLD_CONSTCONST_HANDLER(1, ZEND_ADD, CONST|TMPVAR|CV, CONST|TMPVAR|CV) +ZEND_VM_HELPER(zend_add_helper, ANY, ANY, zval *op_1, zval *op_2) +{ + USE_OPLINE + + SAVE_OPLINE(); + if (UNEXPECTED(Z_TYPE_INFO_P(op_1) == IS_UNDEF)) { + op_1 = ZVAL_UNDEFINED_OP1(); + } + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } + add_function(EX_VAR(opline->result.var), op_1, op_2); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_2); + } + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + +ZEND_VM_HOT_NOCONSTCONST_HANDLER(1, ZEND_ADD, CONST|TMPVARCV, CONST|TMPVARCV) { USE_OPLINE zend_free_op free_op1, free_op2; zval *op1, *op2, *result; + double d1, d2; op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); - if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) { + if (ZEND_VM_SPEC && OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) { + /* pass */ + } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) { if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { result = EX_VAR(opline->result.var); fast_long_add_function(result, op1, op2); ZEND_VM_NEXT_OPCODE(); } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { - result = EX_VAR(opline->result.var); - ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2)); - ZEND_VM_NEXT_OPCODE(); + d1 = (double)Z_LVAL_P(op1); + d2 = Z_DVAL_P(op2); + ZEND_VM_C_GOTO(add_double); } } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) { if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { + d1 = Z_DVAL_P(op1); + d2 = Z_DVAL_P(op2); +ZEND_VM_C_LABEL(add_double): result = EX_VAR(opline->result.var); - ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); + ZVAL_DOUBLE(result, d1 + d2); ZEND_VM_NEXT_OPCODE(); } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { - result = EX_VAR(opline->result.var); - ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2))); - ZEND_VM_NEXT_OPCODE(); + d1 = Z_DVAL_P(op1); + d2 = (double)Z_LVAL_P(op2); + ZEND_VM_C_GOTO(add_double); } } + ZEND_VM_DISPATCH_TO_HELPER(zend_add_helper, op_1, op1, op_2, op2); +} + +ZEND_VM_HELPER(zend_sub_helper, ANY, ANY, zval *op_1, zval *op_2) +{ + USE_OPLINE + SAVE_OPLINE(); - if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) { - op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + if (UNEXPECTED(Z_TYPE_INFO_P(op_1) == IS_UNDEF)) { + op_1 = ZVAL_UNDEFINED_OP1(); } - if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) { - op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } + sub_function(EX_VAR(opline->result.var), op_1, op_2); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_2); } - add_function(EX_VAR(opline->result.var), op1, op2); - FREE_OP1(); - FREE_OP2(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_CONSTCONST_HANDLER(2, ZEND_SUB, CONST|TMPVAR|CV, CONST|TMPVAR|CV) +ZEND_VM_HOT_NOCONSTCONST_HANDLER(2, ZEND_SUB, CONST|TMPVARCV, CONST|TMPVARCV) { USE_OPLINE zend_free_op free_op1, free_op2; zval *op1, *op2, *result; + double d1, d2; op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); - if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) { + if (ZEND_VM_SPEC && OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) { + /* pass */ + } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) { if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { result = EX_VAR(opline->result.var); fast_long_sub_function(result, op1, op2); ZEND_VM_NEXT_OPCODE(); } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { - result = EX_VAR(opline->result.var); - ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2)); - ZEND_VM_NEXT_OPCODE(); + d1 = (double)Z_LVAL_P(op1); + d2 = Z_DVAL_P(op2); + ZEND_VM_C_GOTO(sub_double); } } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) { if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { + d1 = Z_DVAL_P(op1); + d2 = Z_DVAL_P(op2); +ZEND_VM_C_LABEL(sub_double): result = EX_VAR(opline->result.var); - ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2)); + ZVAL_DOUBLE(result, d1 - d2); ZEND_VM_NEXT_OPCODE(); } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { - result = EX_VAR(opline->result.var); - ZVAL_DOUBLE(result, Z_DVAL_P(op1) - ((double)Z_LVAL_P(op2))); - ZEND_VM_NEXT_OPCODE(); + d1 = Z_DVAL_P(op1); + d2 = (double)Z_LVAL_P(op2); + ZEND_VM_C_GOTO(sub_double); } } + ZEND_VM_DISPATCH_TO_HELPER(zend_sub_helper, op_1, op1, op_2, op2); +} + +ZEND_VM_HELPER(zend_mul_helper, ANY, ANY, zval *op_1, zval *op_2) +{ + USE_OPLINE + SAVE_OPLINE(); - if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) { - op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + if (UNEXPECTED(Z_TYPE_INFO_P(op_1) == IS_UNDEF)) { + op_1 = ZVAL_UNDEFINED_OP1(); } - if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) { - op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } + mul_function(EX_VAR(opline->result.var), op_1, op_2); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_2); } - sub_function(EX_VAR(opline->result.var), op1, op2); - FREE_OP1(); - FREE_OP2(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_CONSTCONST_HANDLER(3, ZEND_MUL, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(COMMUTATIVE)) +ZEND_VM_COLD_CONSTCONST_HANDLER(3, ZEND_MUL, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(COMMUTATIVE)) { USE_OPLINE zend_free_op free_op1, free_op2; zval *op1, *op2, *result; + double d1, d2; op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); - if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) { + if (ZEND_VM_SPEC && OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) { + /* pass */ + } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) { if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { zend_long overflow; @@ -126,33 +184,26 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(3, ZEND_MUL, CONST|TMPVAR|CV, CONST|TMPVAR|CV, S Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG; ZEND_VM_NEXT_OPCODE(); } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { - result = EX_VAR(opline->result.var); - ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2)); - ZEND_VM_NEXT_OPCODE(); + d1 = (double)Z_LVAL_P(op1); + d2 = Z_DVAL_P(op2); + ZEND_VM_C_GOTO(mul_double); } } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) { if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { + d1 = Z_DVAL_P(op1); + d2 = Z_DVAL_P(op2); +ZEND_VM_C_LABEL(mul_double): result = EX_VAR(opline->result.var); - ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2)); + ZVAL_DOUBLE(result, d1 * d2); ZEND_VM_NEXT_OPCODE(); } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { - result = EX_VAR(opline->result.var); - ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2))); - ZEND_VM_NEXT_OPCODE(); + d1 = Z_DVAL_P(op1); + d2 = (double)Z_LVAL_P(op2); + ZEND_VM_C_GOTO(mul_double); } } - SAVE_OPLINE(); - if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) { - op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); - } - if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) { - op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); - } - mul_function(EX_VAR(opline->result.var), op1, op2); - FREE_OP1(); - FREE_OP2(); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_DISPATCH_TO_HELPER(zend_mul_helper, op_1, op1, op_2, op2); } ZEND_VM_COLD_CONSTCONST_HANDLER(4, ZEND_DIV, CONST|TMPVAR|CV, CONST|TMPVAR|CV) @@ -180,7 +231,28 @@ ZEND_VM_COLD_HELPER(zend_mod_by_zero_helper, ANY, ANY) HANDLE_EXCEPTION(); } -ZEND_VM_COLD_CONSTCONST_HANDLER(5, ZEND_MOD, CONST|TMPVAR|CV, CONST|TMPVAR|CV) +ZEND_VM_HELPER(zend_mod_helper, ANY, ANY, zval *op_1, zval *op_2) +{ + USE_OPLINE + + SAVE_OPLINE(); + if (UNEXPECTED(Z_TYPE_INFO_P(op_1) == IS_UNDEF)) { + op_1 = ZVAL_UNDEFINED_OP1(); + } + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } + mod_function(EX_VAR(opline->result.var), op_1, op_2); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_2); + } + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + +ZEND_VM_COLD_CONSTCONST_HANDLER(5, ZEND_MOD, CONST|TMPVARCV, CONST|TMPVARCV) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -188,7 +260,9 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(5, ZEND_MOD, CONST|TMPVAR|CV, CONST|TMPVAR|CV) op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); - if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) { + if (ZEND_VM_SPEC && OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) { + /* pass */ + } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) { if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { result = EX_VAR(opline->result.var); if (UNEXPECTED(Z_LVAL_P(op2) == 0)) { @@ -203,20 +277,31 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(5, ZEND_MOD, CONST|TMPVAR|CV, CONST|TMPVAR|CV) } } + ZEND_VM_DISPATCH_TO_HELPER(zend_mod_helper, op_1, op1, op_2, op2); +} + +ZEND_VM_HELPER(zend_shift_left_helper, ANY, ANY, zval *op_1, zval *op_2) +{ + USE_OPLINE + SAVE_OPLINE(); - if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) { - op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + if (UNEXPECTED(Z_TYPE_INFO_P(op_1) == IS_UNDEF)) { + op_1 = ZVAL_UNDEFINED_OP1(); } - if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) { - op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } + shift_left_function(EX_VAR(opline->result.var), op_1, op_2); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_2); } - mod_function(EX_VAR(opline->result.var), op1, op2); - FREE_OP1(); - FREE_OP2(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_CONSTCONST_HANDLER(6, ZEND_SL, CONST|TMPVAR|CV, CONST|TMPVAR|CV) +ZEND_VM_COLD_CONSTCONST_HANDLER(6, ZEND_SL, CONST|TMPVARCV, CONST|TMPVARCV) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -224,27 +309,42 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(6, ZEND_SL, CONST|TMPVAR|CV, CONST|TMPVAR|CV) op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); - if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG) + if (ZEND_VM_SPEC && OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) { + /* pass */ + } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG) && EXPECTED((zend_ulong)Z_LVAL_P(op2) < SIZEOF_ZEND_LONG * 8)) { - ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(op1) << Z_LVAL_P(op2)); + /* Perform shift on unsigned numbers to get well-defined wrap behavior. */ + ZVAL_LONG(EX_VAR(opline->result.var), + (zend_long) ((zend_ulong) Z_LVAL_P(op1) << Z_LVAL_P(op2))); ZEND_VM_NEXT_OPCODE(); } + ZEND_VM_DISPATCH_TO_HELPER(zend_shift_left_helper, op_1, op1, op_2, op2); +} + +ZEND_VM_HELPER(zend_shift_right_helper, ANY, ANY, zval *op_1, zval *op_2) +{ + USE_OPLINE + SAVE_OPLINE(); - if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) { - op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + if (UNEXPECTED(Z_TYPE_INFO_P(op_1) == IS_UNDEF)) { + op_1 = ZVAL_UNDEFINED_OP1(); } - if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) { - op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } + shift_right_function(EX_VAR(opline->result.var), op_1, op_2); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_2); } - shift_left_function(EX_VAR(opline->result.var), op1, op2); - FREE_OP1(); - FREE_OP2(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_CONSTCONST_HANDLER(7, ZEND_SR, CONST|TMPVAR|CV, CONST|TMPVAR|CV) +ZEND_VM_COLD_CONSTCONST_HANDLER(7, ZEND_SR, CONST|TMPVARCV, CONST|TMPVARCV) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -252,27 +352,19 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(7, ZEND_SR, CONST|TMPVAR|CV, CONST|TMPVAR|CV) op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); - if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG) + if (ZEND_VM_SPEC && OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) { + /* pass */ + } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG) && EXPECTED((zend_ulong)Z_LVAL_P(op2) < SIZEOF_ZEND_LONG * 8)) { ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(op1) >> Z_LVAL_P(op2)); ZEND_VM_NEXT_OPCODE(); } - SAVE_OPLINE(); - if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) { - op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); - } - if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) { - op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); - } - shift_right_function(EX_VAR(opline->result.var), op1, op2); - FREE_OP1(); - FREE_OP2(); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_DISPATCH_TO_HELPER(zend_shift_right_helper, op_1, op1, op_2, op2); } -ZEND_VM_COLD_CONSTCONST_HANDLER(166, ZEND_POW, CONST|TMPVAR|CV, CONST|TMPVAR|CV) +ZEND_VM_COLD_CONSTCONST_HANDLER(12, ZEND_POW, CONST|TMPVAR|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -308,14 +400,18 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ } else { ZVAL_STR(EX_VAR(opline->result.var), op2_str); } - FREE_OP1(); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zend_string_release_ex(op1_str, 0); + } } else if (OP2_TYPE != IS_CONST && UNEXPECTED(ZSTR_LEN(op2_str) == 0)) { if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_CV) { ZVAL_STR_COPY(EX_VAR(opline->result.var), op1_str); } else { ZVAL_STR(EX_VAR(opline->result.var), op1_str); } - FREE_OP2(); + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zend_string_release_ex(op2_str, 0); + } } else if (OP1_TYPE != IS_CONST && OP1_TYPE != IS_CV && !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { size_t len = ZSTR_LEN(op1_str); @@ -323,24 +419,30 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - FREE_OP2(); + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zend_string_release_ex(op2_str, 0); + } } else { str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - FREE_OP1(); - FREE_OP2(); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zend_string_release_ex(op1_str, 0); + } + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zend_string_release_ex(op2_str, 0); + } } ZEND_VM_NEXT_OPCODE(); } else { SAVE_OPLINE(); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { - op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + op1 = ZVAL_UNDEFINED_OP1(); } if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { - op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + op2 = ZVAL_UNDEFINED_OP2(); } concat_function(EX_VAR(opline->result.var), op1, op2); FREE_OP1(); @@ -349,12 +451,12 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ } } -ZEND_VM_COLD_CONSTCONST_HANDLER(15, ZEND_IS_IDENTICAL, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV, SPEC(COMMUTATIVE)) +ZEND_VM_COLD_CONSTCONST_HANDLER(16, ZEND_IS_IDENTICAL, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV, SPEC(COMMUTATIVE)) { USE_OPLINE zend_free_op free_op1, free_op2; zval *op1, *op2; - int result; + zend_bool result; SAVE_OPLINE(); op1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); @@ -367,12 +469,12 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(15, ZEND_IS_IDENTICAL, CONST|TMP|VAR|CV, CONST|T ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_CONSTCONST_HANDLER(16, ZEND_IS_NOT_IDENTICAL, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV, SPEC(COMMUTATIVE)) +ZEND_VM_COLD_CONSTCONST_HANDLER(17, ZEND_IS_NOT_IDENTICAL, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV, SPEC(COMMUTATIVE)) { USE_OPLINE zend_free_op free_op1, free_op2; zval *op1, *op2; - int result; + zend_bool result; SAVE_OPLINE(); op1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); @@ -385,220 +487,354 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(16, ZEND_IS_NOT_IDENTICAL, CONST|TMP|VAR|CV, CON ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_CONSTCONST_HANDLER(17, ZEND_IS_EQUAL, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(COMMUTATIVE)) +ZEND_VM_HELPER(zend_is_equal_helper, ANY, ANY, zval *op_1, zval *op_2) +{ + USE_OPLINE + + SAVE_OPLINE(); + if (UNEXPECTED(Z_TYPE_INFO_P(op_1) == IS_UNDEF)) { + op_1 = ZVAL_UNDEFINED_OP1(); + } + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } + compare_function(EX_VAR(opline->result.var), op_1, op_2); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_2); + } + if (UNEXPECTED(EG(exception))) { + HANDLE_EXCEPTION(); + } + if (Z_LVAL_P(EX_VAR(opline->result.var)) == 0) { + ZEND_VM_SMART_BRANCH_TRUE(); + ZVAL_TRUE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); + } else { + ZEND_VM_SMART_BRANCH_FALSE(); + ZVAL_FALSE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); + } +} + +ZEND_VM_COLD_CONSTCONST_HANDLER(18, ZEND_IS_EQUAL, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(SMART_BRANCH,COMMUTATIVE)) { USE_OPLINE zend_free_op free_op1, free_op2; - zval *op1, *op2, *result; + zval *op1, *op2; + double d1, d2; op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); - do { - int result; - - if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - result = (Z_LVAL_P(op1) == Z_LVAL_P(op2)); - } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - result = ((double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + if (ZEND_VM_SPEC && OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) { + /* pass */ + } else if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + if (EXPECTED(Z_LVAL_P(op1) == Z_LVAL_P(op2))) { +ZEND_VM_C_LABEL(is_equal_true): + ZEND_VM_SMART_BRANCH_TRUE(); + ZVAL_TRUE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); } else { - break; +ZEND_VM_C_LABEL(is_equal_false): + ZEND_VM_SMART_BRANCH_FALSE(); + ZVAL_FALSE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); } - } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - result = (Z_DVAL_P(op1) == Z_DVAL_P(op2)); - } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - result = (Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + d1 = (double)Z_LVAL_P(op1); + d2 = Z_DVAL_P(op2); + ZEND_VM_C_GOTO(is_equal_double); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + d1 = Z_DVAL_P(op1); + d2 = Z_DVAL_P(op2); +ZEND_VM_C_LABEL(is_equal_double): + if (d1 == d2) { + ZEND_VM_C_GOTO(is_equal_true); } else { - break; + ZEND_VM_C_GOTO(is_equal_false); } - } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { - result = zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2)); - FREE_OP1(); - FREE_OP2(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + d1 = Z_DVAL_P(op1); + d2 = (double)Z_LVAL_P(op2); + ZEND_VM_C_GOTO(is_equal_double); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + int result = zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2)); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_str(op1); + } + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_str(op2); + } + if (result) { + ZEND_VM_C_GOTO(is_equal_true); } else { - break; + ZEND_VM_C_GOTO(is_equal_false); } - } else { - break; } - ZEND_VM_SMART_BRANCH(result, 0); - ZVAL_BOOL(EX_VAR(opline->result.var), result); - ZEND_VM_NEXT_OPCODE(); - } while (0); + } + ZEND_VM_DISPATCH_TO_HELPER(zend_is_equal_helper, op_1, op1, op_2, op2); +} + +ZEND_VM_HELPER(zend_is_not_equal_helper, ANY, ANY, zval *op_1, zval *op_2) +{ + USE_OPLINE SAVE_OPLINE(); - if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { - op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + if (UNEXPECTED(Z_TYPE_INFO_P(op_1) == IS_UNDEF)) { + op_1 = ZVAL_UNDEFINED_OP1(); } - if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { - op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } + compare_function(EX_VAR(opline->result.var), op_1, op_2); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_2); + } + if (UNEXPECTED(EG(exception))) { + HANDLE_EXCEPTION(); + } + if (Z_LVAL_P(EX_VAR(opline->result.var)) != 0) { + ZEND_VM_SMART_BRANCH_TRUE(); + ZVAL_TRUE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); + } else { + ZEND_VM_SMART_BRANCH_FALSE(); + ZVAL_FALSE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); } - result = EX_VAR(opline->result.var); - compare_function(result, op1, op2); - ZVAL_BOOL(result, Z_LVAL_P(result) == 0); - FREE_OP1(); - FREE_OP2(); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_CONSTCONST_HANDLER(18, ZEND_IS_NOT_EQUAL, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(COMMUTATIVE)) +ZEND_VM_COLD_CONSTCONST_HANDLER(19, ZEND_IS_NOT_EQUAL, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(SMART_BRANCH,COMMUTATIVE)) { USE_OPLINE zend_free_op free_op1, free_op2; - zval *op1, *op2, *result; + zval *op1, *op2; + double d1, d2; op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); - do { - int result; - - if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - result = (Z_LVAL_P(op1) != Z_LVAL_P(op2)); - } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - result = ((double)Z_LVAL_P(op1) != Z_DVAL_P(op2)); + if (ZEND_VM_SPEC && OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) { + /* pass */ + } else if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + if (EXPECTED(Z_LVAL_P(op1) != Z_LVAL_P(op2))) { +ZEND_VM_C_LABEL(is_not_equal_true): + ZEND_VM_SMART_BRANCH_TRUE(); + ZVAL_TRUE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); } else { - break; +ZEND_VM_C_LABEL(is_not_equal_false): + ZEND_VM_SMART_BRANCH_FALSE(); + ZVAL_FALSE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); } - } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - result = (Z_DVAL_P(op1) != Z_DVAL_P(op2)); - } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - result = (Z_DVAL_P(op1) != ((double)Z_LVAL_P(op2))); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + d1 = (double)Z_LVAL_P(op1); + d2 = Z_DVAL_P(op2); + ZEND_VM_C_GOTO(is_not_equal_double); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + d1 = Z_DVAL_P(op1); + d2 = Z_DVAL_P(op2); +ZEND_VM_C_LABEL(is_not_equal_double): + if (d1 != d2) { + ZEND_VM_C_GOTO(is_not_equal_true); } else { - break; + ZEND_VM_C_GOTO(is_not_equal_false); } - } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { - result = !zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2)); - FREE_OP1(); - FREE_OP2(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + d1 = Z_DVAL_P(op1); + d2 = (double)Z_LVAL_P(op2); + ZEND_VM_C_GOTO(is_not_equal_double); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + int result = zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2)); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_str(op1); + } + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_str(op2); + } + if (!result) { + ZEND_VM_C_GOTO(is_not_equal_true); } else { - break; + ZEND_VM_C_GOTO(is_not_equal_false); } - } else { - break; } - ZEND_VM_SMART_BRANCH(result, 0); - ZVAL_BOOL(EX_VAR(opline->result.var), result); - ZEND_VM_NEXT_OPCODE(); - } while (0); + } + ZEND_VM_DISPATCH_TO_HELPER(zend_is_not_equal_helper, op_1, op1, op_2, op2); +} + +ZEND_VM_HELPER(zend_is_smaller_helper, ANY, ANY, zval *op_1, zval *op_2) +{ + USE_OPLINE SAVE_OPLINE(); - if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { - op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + if (UNEXPECTED(Z_TYPE_INFO_P(op_1) == IS_UNDEF)) { + op_1 = ZVAL_UNDEFINED_OP1(); } - if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { - op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } + compare_function(EX_VAR(opline->result.var), op_1, op_2); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_2); + } + if (UNEXPECTED(EG(exception))) { + HANDLE_EXCEPTION(); + } + if (Z_LVAL_P(EX_VAR(opline->result.var)) < 0) { + ZEND_VM_SMART_BRANCH_TRUE(); + ZVAL_TRUE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); + } else { + ZEND_VM_SMART_BRANCH_FALSE(); + ZVAL_FALSE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); } - result = EX_VAR(opline->result.var); - compare_function(result, op1, op2); - ZVAL_BOOL(result, Z_LVAL_P(result) != 0); - FREE_OP1(); - FREE_OP2(); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_CONSTCONST_HANDLER(19, ZEND_IS_SMALLER, CONST|TMPVAR|CV, CONST|TMPVAR|CV) +ZEND_VM_HOT_NOCONSTCONST_HANDLER(20, ZEND_IS_SMALLER, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH)) { USE_OPLINE zend_free_op free_op1, free_op2; - zval *op1, *op2, *result; + zval *op1, *op2; + double d1, d2; op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); - do { - int result; - - if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) { - if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { - result = (Z_LVAL_P(op1) < Z_LVAL_P(op2)); - } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { - result = ((double)Z_LVAL_P(op1) < Z_DVAL_P(op2)); + if (ZEND_VM_SPEC && OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) { + /* pass */ + } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { + if (EXPECTED(Z_LVAL_P(op1) < Z_LVAL_P(op2))) { +ZEND_VM_C_LABEL(is_smaller_true): + ZEND_VM_SMART_BRANCH_TRUE(); + ZVAL_TRUE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); } else { - break; +ZEND_VM_C_LABEL(is_smaller_false): + ZEND_VM_SMART_BRANCH_FALSE(); + ZVAL_FALSE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); } - } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) { - if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { - result = (Z_DVAL_P(op1) < Z_DVAL_P(op2)); - } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { - result = (Z_DVAL_P(op1) < ((double)Z_LVAL_P(op2))); + } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { + d1 = (double)Z_LVAL_P(op1); + d2 = Z_DVAL_P(op2); + ZEND_VM_C_GOTO(is_smaller_double); + } + } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { + d1 = Z_DVAL_P(op1); + d2 = Z_DVAL_P(op2); +ZEND_VM_C_LABEL(is_smaller_double): + if (d1 < d2) { + ZEND_VM_C_GOTO(is_smaller_true); } else { - break; + ZEND_VM_C_GOTO(is_smaller_false); } - } else { - break; + } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { + d1 = Z_DVAL_P(op1); + d2 = (double)Z_LVAL_P(op2); + ZEND_VM_C_GOTO(is_smaller_double); } - ZEND_VM_SMART_BRANCH(result, 0); - ZVAL_BOOL(EX_VAR(opline->result.var), result); - ZEND_VM_NEXT_OPCODE(); - } while (0); + } + ZEND_VM_DISPATCH_TO_HELPER(zend_is_smaller_helper, op_1, op1, op_2, op2); +} + +ZEND_VM_HELPER(zend_is_smaller_or_equal_helper, ANY, ANY, zval *op_1, zval *op_2) +{ + USE_OPLINE SAVE_OPLINE(); - if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) { - op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + if (UNEXPECTED(Z_TYPE_INFO_P(op_1) == IS_UNDEF)) { + op_1 = ZVAL_UNDEFINED_OP1(); } - if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) { - op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } + compare_function(EX_VAR(opline->result.var), op_1, op_2); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_2); + } + if (UNEXPECTED(EG(exception))) { + HANDLE_EXCEPTION(); + } + if (Z_LVAL_P(EX_VAR(opline->result.var)) <= 0) { + ZEND_VM_SMART_BRANCH_TRUE(); + ZVAL_TRUE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); + } else { + ZEND_VM_SMART_BRANCH_FALSE(); + ZVAL_FALSE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); } - result = EX_VAR(opline->result.var); - compare_function(result, op1, op2); - ZVAL_BOOL(result, Z_LVAL_P(result) < 0); - FREE_OP1(); - FREE_OP2(); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_CONSTCONST_HANDLER(20, ZEND_IS_SMALLER_OR_EQUAL, CONST|TMPVAR|CV, CONST|TMPVAR|CV) +ZEND_VM_HOT_NOCONSTCONST_HANDLER(21, ZEND_IS_SMALLER_OR_EQUAL, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH)) { USE_OPLINE zend_free_op free_op1, free_op2; - zval *op1, *op2, *result; + zval *op1, *op2; + double d1, d2; op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); - do { - int result; - - if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) { - if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { - result = (Z_LVAL_P(op1) <= Z_LVAL_P(op2)); - } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { - result = ((double)Z_LVAL_P(op1) <= Z_DVAL_P(op2)); + if (ZEND_VM_SPEC && OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) { + /* pass */ + } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { + if (EXPECTED(Z_LVAL_P(op1) <= Z_LVAL_P(op2))) { +ZEND_VM_C_LABEL(is_smaller_or_equal_true): + ZEND_VM_SMART_BRANCH_TRUE(); + ZVAL_TRUE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); } else { - break; +ZEND_VM_C_LABEL(is_smaller_or_equal_false): + ZEND_VM_SMART_BRANCH_FALSE(); + ZVAL_FALSE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); } - } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) { - if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { - result = (Z_DVAL_P(op1) <= Z_DVAL_P(op2)); - } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { - result = (Z_DVAL_P(op1) <= ((double)Z_LVAL_P(op2))); + } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { + d1 = (double)Z_LVAL_P(op1); + d2 = Z_DVAL_P(op2); + ZEND_VM_C_GOTO(is_smaller_or_equal_double); + } + } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { + d1 = Z_DVAL_P(op1); + d2 = Z_DVAL_P(op2); +ZEND_VM_C_LABEL(is_smaller_or_equal_double): + if (d1 <= d2) { + ZEND_VM_C_GOTO(is_smaller_or_equal_true); } else { - break; + ZEND_VM_C_GOTO(is_smaller_or_equal_false); } - } else { - break; + } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { + d1 = Z_DVAL_P(op1); + d2 = (double)Z_LVAL_P(op2); + ZEND_VM_C_GOTO(is_smaller_or_equal_double); } - ZEND_VM_SMART_BRANCH(result, 0); - ZVAL_BOOL(EX_VAR(opline->result.var), result); - ZEND_VM_NEXT_OPCODE(); - } while (0); - - SAVE_OPLINE(); - if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) { - op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); - } - if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) { - op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); } - result = EX_VAR(opline->result.var); - compare_function(result, op1, op2); - ZVAL_BOOL(result, Z_LVAL_P(result) <= 0); - FREE_OP1(); - FREE_OP2(); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_DISPATCH_TO_HELPER(zend_is_smaller_or_equal_helper, op_1, op1, op_2, op2); } ZEND_VM_COLD_CONSTCONST_HANDLER(170, ZEND_SPACESHIP, CONST|TMPVAR|CV, CONST|TMPVAR|CV) @@ -616,7 +852,28 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(170, ZEND_SPACESHIP, CONST|TMPVAR|CV, CONST|TMPV ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_CONSTCONST_HANDLER(9, ZEND_BW_OR, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(COMMUTATIVE)) +ZEND_VM_HELPER(zend_bw_or_helper, ANY, ANY, zval *op_1, zval *op_2) +{ + USE_OPLINE + + SAVE_OPLINE(); + if (UNEXPECTED(Z_TYPE_INFO_P(op_1) == IS_UNDEF)) { + op_1 = ZVAL_UNDEFINED_OP1(); + } + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } + bitwise_or_function(EX_VAR(opline->result.var), op_1, op_2); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_2); + } + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + +ZEND_VM_COLD_CONSTCONST_HANDLER(9, ZEND_BW_OR, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(COMMUTATIVE)) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -624,26 +881,39 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(9, ZEND_BW_OR, CONST|TMPVAR|CV, CONST|TMPVAR|CV, op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); - if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG) + if (ZEND_VM_SPEC && OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) { + /* pass */ + } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(op1) | Z_LVAL_P(op2)); ZEND_VM_NEXT_OPCODE(); } + ZEND_VM_DISPATCH_TO_HELPER(zend_bw_or_helper, op_1, op1, op_2, op2); +} + +ZEND_VM_HELPER(zend_bw_and_helper, ANY, ANY, zval *op_1, zval *op_2) +{ + USE_OPLINE + SAVE_OPLINE(); - if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) { - op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + if (UNEXPECTED(Z_TYPE_INFO_P(op_1) == IS_UNDEF)) { + op_1 = ZVAL_UNDEFINED_OP1(); } - if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) { - op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } + bitwise_and_function(EX_VAR(opline->result.var), op_1, op_2); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_2); } - bitwise_or_function(EX_VAR(opline->result.var), op1, op2); - FREE_OP1(); - FREE_OP2(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_CONSTCONST_HANDLER(10, ZEND_BW_AND, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(COMMUTATIVE)) +ZEND_VM_COLD_CONSTCONST_HANDLER(10, ZEND_BW_AND, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(COMMUTATIVE)) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -651,26 +921,39 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(10, ZEND_BW_AND, CONST|TMPVAR|CV, CONST|TMPVAR|C op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); - if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG) + if (ZEND_VM_SPEC && OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) { + /* pass */ + } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(op1) & Z_LVAL_P(op2)); ZEND_VM_NEXT_OPCODE(); } + ZEND_VM_DISPATCH_TO_HELPER(zend_bw_and_helper, op_1, op1, op_2, op2); +} + +ZEND_VM_HELPER(zend_bw_xor_helper, ANY, ANY, zval *op_1, zval *op_2) +{ + USE_OPLINE + SAVE_OPLINE(); - if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) { - op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + if (UNEXPECTED(Z_TYPE_INFO_P(op_1) == IS_UNDEF)) { + op_1 = ZVAL_UNDEFINED_OP1(); } - if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) { - op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } + bitwise_xor_function(EX_VAR(opline->result.var), op_1, op_2); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_2); } - bitwise_and_function(EX_VAR(opline->result.var), op1, op2); - FREE_OP1(); - FREE_OP2(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_CONSTCONST_HANDLER(11, ZEND_BW_XOR, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(COMMUTATIVE)) +ZEND_VM_COLD_CONSTCONST_HANDLER(11, ZEND_BW_XOR, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(COMMUTATIVE)) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -678,26 +961,18 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(11, ZEND_BW_XOR, CONST|TMPVAR|CV, CONST|TMPVAR|C op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); - if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG) + if (ZEND_VM_SPEC && OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) { + /* pass */ + } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(op1) ^ Z_LVAL_P(op2)); ZEND_VM_NEXT_OPCODE(); } - SAVE_OPLINE(); - if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) { - op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); - } - if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) { - op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); - } - bitwise_xor_function(EX_VAR(opline->result.var), op1, op2); - FREE_OP1(); - FREE_OP2(); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_DISPATCH_TO_HELPER(zend_bw_xor_helper, op_1, op1, op_2, op2); } -ZEND_VM_COLD_CONSTCONST_HANDLER(14, ZEND_BOOL_XOR, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(COMMUTATIVE)) +ZEND_VM_COLD_CONSTCONST_HANDLER(15, ZEND_BOOL_XOR, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(COMMUTATIVE)) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -712,7 +987,7 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(14, ZEND_BOOL_XOR, CONST|TMPVAR|CV, CONST|TMPVAR ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_CONST_HANDLER(12, ZEND_BW_NOT, CONST|TMPVAR|CV, ANY) +ZEND_VM_COLD_CONST_HANDLER(13, ZEND_BW_NOT, CONST|TMPVAR|CV, ANY) { USE_OPLINE zend_free_op free_op1; @@ -725,13 +1000,15 @@ ZEND_VM_COLD_CONST_HANDLER(12, ZEND_BW_NOT, CONST|TMPVAR|CV, ANY) } SAVE_OPLINE(); - bitwise_not_function(EX_VAR(opline->result.var), - GET_OP1_ZVAL_PTR(BP_VAR_R)); + if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = ZVAL_UNDEFINED_OP1(); + } + bitwise_not_function(EX_VAR(opline->result.var), op1); FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_CONST_HANDLER(13, ZEND_BOOL_NOT, CONST|TMPVAR|CV, ANY) +ZEND_VM_COLD_CONST_HANDLER(14, ZEND_BOOL_NOT, CONST|TMPVAR|CV, ANY) { USE_OPLINE zval *val; @@ -746,7 +1023,7 @@ ZEND_VM_COLD_CONST_HANDLER(13, ZEND_BOOL_NOT, CONST|TMPVAR|CV, ANY) ZVAL_TRUE(EX_VAR(opline->result.var)); if (OP1_TYPE == IS_CV && UNEXPECTED(orig_val_type == IS_UNDEF)) { SAVE_OPLINE(); - GET_OP1_UNDEF_CV(val, BP_VAR_R); + ZVAL_UNDEFINED_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } } else { @@ -772,34 +1049,30 @@ ZEND_VM_COLD_HELPER(zend_this_not_in_object_context_helper, ANY, ANY) HANDLE_EXCEPTION(); } -ZEND_VM_COLD_HELPER(zend_abstract_method_helper, ANY, ANY, zend_function *fbc) +ZEND_VM_COLD_HELPER(zend_undefined_function_helper, ANY, ANY) { USE_OPLINE + zval *function_name; SAVE_OPLINE(); - zend_throw_error(NULL, "Cannot call abstract method %s::%s()", ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name)); - UNDEF_RESULT(); - HANDLE_EXCEPTION(); -} - -ZEND_VM_COLD_HELPER(zend_undefined_function_helper, ANY, ANY, zval *function_name) -{ - SAVE_OPLINE(); + function_name = RT_CONSTANT(opline, opline->op2); zend_throw_error(NULL, "Call to undefined function %s()", Z_STRVAL_P(function_name)); HANDLE_EXCEPTION(); } -ZEND_VM_HELPER(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMPVAR|CV, binary_op_type binary_op) +ZEND_VM_HANDLER(28, ZEND_ASSIGN_OBJ_OP, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, OP) { USE_OPLINE - zend_free_op free_op1, free_op2, free_op_data1; + zend_free_op free_op1, free_op2, free_op_data; zval *object; zval *property; zval *value; zval *zptr; + void **cache_slot; + zend_property_info *prop_info; SAVE_OPLINE(); - object = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW); + object = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { ZEND_VM_DISPATCH_TO_HELPER(zend_this_not_in_object_context_helper); @@ -808,49 +1081,124 @@ ZEND_VM_HELPER(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMPVAR|CV, property = GET_OP2_ZVAL_PTR(BP_VAR_R); do { - value = get_op_data_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1, &free_op_data1); + value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R); if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { - if (Z_ISREF_P(object)) { + if (Z_ISREF_P(object) && Z_TYPE_P(Z_REFVAL_P(object)) == IS_OBJECT) { object = Z_REFVAL_P(object); - if (EXPECTED(Z_TYPE_P(object) == IS_OBJECT)) { - ZEND_VM_C_GOTO(assign_op_object); - } + ZEND_VM_C_GOTO(assign_op_object); } - if (UNEXPECTED(!make_real_object(object, property OPLINE_CC EXECUTE_DATA_CC))) { + if (OP1_TYPE == IS_CV + && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { + ZVAL_UNDEFINED_OP1(); + } + object = make_real_object(object, property OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(!object)) { break; } } - /* here we are sure we are dealing with an object */ ZEND_VM_C_LABEL(assign_op_object): - if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) - && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR((opline+1)->extended_value) : NULL))) != NULL)) { + /* here we are sure we are dealing with an object */ + cache_slot = (OP2_TYPE == IS_CONST) ? CACHE_ADDR((opline+1)->extended_value) : NULL; + if (EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, cache_slot)) != NULL)) { if (UNEXPECTED(Z_ISERROR_P(zptr))) { if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - ZVAL_DEREF(zptr); + zval *orig_zptr = zptr; + zend_reference *ref; + + do { + if (UNEXPECTED(Z_ISREF_P(zptr))) { + ref = Z_REF_P(zptr); + zptr = Z_REFVAL_P(zptr); + if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) { + zend_binary_assign_op_typed_ref(ref, value OPLINE_CC EXECUTE_DATA_CC); + break; + } + } + + if (OP2_TYPE == IS_CONST) { + prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); + } else { + prop_info = zend_object_fetch_property_type_info(Z_OBJ_P(object), orig_zptr); + } + if (UNEXPECTED(prop_info)) { + /* special case for typed properties */ + zend_binary_assign_op_typed_prop(prop_info, zptr, value OPLINE_CC EXECUTE_DATA_CC); + } else { + zend_binary_op(zptr, zptr, value OPLINE_CC); + } + } while (0); - binary_op(zptr, zptr, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), zptr); } } } else { - zend_assign_op_overloaded_property(object, property, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR((opline+1)->extended_value) : NULL), value, binary_op OPLINE_CC EXECUTE_DATA_CC); + zend_assign_op_overloaded_property(object, property, cache_slot, value OPLINE_CC EXECUTE_DATA_CC); } } while (0); - FREE_OP(free_op_data1); + FREE_OP_DATA(); FREE_OP2(); FREE_OP1_VAR_PTR(); /* assign_obj has two opcodes! */ ZEND_VM_NEXT_OPCODE_EX(1, 2); } -ZEND_VM_HELPER(zend_binary_assign_op_dim_helper, VAR|CV, CONST|TMPVAR|UNUSED|CV, binary_op_type binary_op) +/* No specialization for op_types (CONST|TMP|VAR|CV, UNUSED|CONST|TMPVAR) */ +ZEND_VM_HANDLER(29, ZEND_ASSIGN_STATIC_PROP_OP, ANY, ANY, OP) +{ + /* This helper actually never will receive IS_VAR as second op, and has the same handling for VAR and TMP in the first op, but for interoperability with the other binary_assign_op helpers, it is necessary to "include" it */ + + USE_OPLINE + zend_free_op free_op_data; + zval *prop, *value; + zend_property_info *prop_info; + zend_reference *ref; + + SAVE_OPLINE(); + + if (UNEXPECTED(zend_fetch_static_property_address(&prop, &prop_info, (opline+1)->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS)) { + ZEND_ASSERT(EG(exception)); + UNDEF_RESULT(); + FREE_UNFETCHED_OP_DATA(); + HANDLE_EXCEPTION(); + } + + value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R); + + do { + if (UNEXPECTED(Z_ISREF_P(prop))) { + ref = Z_REF_P(prop); + prop = Z_REFVAL_P(prop); + if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) { + zend_binary_assign_op_typed_ref(ref, value OPLINE_CC EXECUTE_DATA_CC); + break; + } + } + + if (UNEXPECTED(prop_info->type)) { + /* special case for typed properties */ + zend_binary_assign_op_typed_prop(prop_info, prop, value OPLINE_CC EXECUTE_DATA_CC); + } else { + zend_binary_op(prop, prop, value OPLINE_CC); + } + } while (0); + + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), prop); + } + + FREE_OP_DATA(); + /* assign_static_prop has two opcodes! */ + ZEND_VM_NEXT_OPCODE_EX(1, 2); +} + +ZEND_VM_HANDLER(27, ZEND_ASSIGN_DIM_OP, VAR|CV, CONST|TMPVAR|UNUSED|NEXT|CV, OP) { USE_OPLINE zend_free_op free_op1, free_op2, free_op_data1; @@ -880,68 +1228,63 @@ ZEND_VM_C_LABEL(assign_dim_op_new_array): if (UNEXPECTED(!var_ptr)) { ZEND_VM_C_GOTO(assign_dim_op_ret_null); } - ZVAL_DEREF(var_ptr); } value = get_op_data_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1, &free_op_data1); - binary_op(var_ptr, var_ptr, value); + do { + if (OP2_TYPE != IS_UNUSED && UNEXPECTED(Z_ISREF_P(var_ptr))) { + zend_reference *ref = Z_REF_P(var_ptr); + var_ptr = Z_REFVAL_P(var_ptr); + if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) { + zend_binary_assign_op_typed_ref(ref, value OPLINE_CC EXECUTE_DATA_CC); + break; + } + } + zend_binary_op(var_ptr, var_ptr, value OPLINE_CC); + } while (0); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); } + FREE_OP(free_op_data1); } else { if (EXPECTED(Z_ISREF_P(container))) { container = Z_REFVAL_P(container); if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { ZEND_VM_C_GOTO(assign_dim_op_array); } - } else if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { - container = GET_OP1_UNDEF_CV(container, BP_VAR_RW); -ZEND_VM_C_LABEL(assign_dim_op_convert_to_array): - ZVAL_ARR(container, zend_new_array(8)); - ZEND_VM_C_GOTO(assign_dim_op_new_array); } dim = GET_OP2_ZVAL_PTR(BP_VAR_R); if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - value = get_op_data_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1, &free_op_data1); if (OP2_TYPE == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - zend_binary_assign_op_obj_dim(container, dim, value, UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, binary_op EXECUTE_DATA_CC); + zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); + } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { + if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { + ZVAL_UNDEFINED_OP1(); + } + ZVAL_ARR(container, zend_new_array(8)); + ZEND_VM_C_GOTO(assign_dim_op_new_array); } else { - if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { - if (OP2_TYPE == IS_UNUSED) { - zend_use_new_element_for_string(); - } else { - zend_check_string_offset(dim, BP_VAR_RW EXECUTE_DATA_CC); - zend_wrong_string_offset(EXECUTE_DATA_C); - } - UNDEF_RESULT(); - } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { - ZEND_VM_C_GOTO(assign_dim_op_convert_to_array); - } else { - if (UNEXPECTED(OP1_TYPE != IS_VAR || EXPECTED(!Z_ISERROR_P(container)))) { - zend_use_scalar_as_array(); - } + zend_binary_assign_op_dim_slow(container, dim OPLINE_CC EXECUTE_DATA_CC); ZEND_VM_C_LABEL(assign_dim_op_ret_null): - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_NULL(EX_VAR(opline->result.var)); - } + FREE_UNFETCHED_OP_DATA(); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); } - value = get_op_data_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1, &free_op_data1); } } FREE_OP2(); - FREE_OP(free_op_data1); FREE_OP1_VAR_PTR(); ZEND_VM_NEXT_OPCODE_EX(1, 2); } -ZEND_VM_HELPER(zend_binary_assign_op_simple_helper, VAR|CV, CONST|TMPVAR|CV, binary_op_type binary_op) +ZEND_VM_HANDLER(26, ZEND_ASSIGN_OP, VAR|CV, CONST|TMPVAR|CV, OP) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -957,9 +1300,17 @@ ZEND_VM_HELPER(zend_binary_assign_op_simple_helper, VAR|CV, CONST|TMPVAR|CV, bin ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - ZVAL_DEREF(var_ptr); - - binary_op(var_ptr, var_ptr, value); + do { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_REFERENCE)) { + zend_reference *ref = Z_REF_P(var_ptr); + var_ptr = Z_REFVAL_P(var_ptr); + if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) { + zend_binary_assign_op_typed_ref(ref, value OPLINE_CC EXECUTE_DATA_CC); + break; + } + } + zend_binary_op(var_ptr, var_ptr, value OPLINE_CC); + } while (0); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); @@ -971,99 +1322,18 @@ ZEND_VM_HELPER(zend_binary_assign_op_simple_helper, VAR|CV, CONST|TMPVAR|CV, bin ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_INLINE_HELPER(zend_binary_assign_op_helper, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, SPEC(DIM_OBJ), binary_op_type binary_op) -{ -#if defined(ZEND_VM_SPEC) && OP2_TYPE == IS_UNUSED - ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, binary_op); -#else -# if !defined(ZEND_VM_SPEC) || OP1_TYPE != IS_UNUSED -# if !defined(ZEND_VM_SPEC) - /* opline->extended_value checks are specialized, don't need opline */ - USE_OPLINE -# endif - - if (EXPECTED(opline->extended_value == 0)) { - ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_simple_helper, binary_op, binary_op); - } - if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) { - ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, binary_op); - } -# endif - - ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, binary_op); -#endif -} - -ZEND_VM_HANDLER(23, ZEND_ASSIGN_ADD, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ|CACHE_SLOT, SPEC(DIM_OBJ)) -{ - ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, add_function); -} - -ZEND_VM_HANDLER(24, ZEND_ASSIGN_SUB, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ|CACHE_SLOT, SPEC(DIM_OBJ)) -{ - ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, sub_function); -} - -ZEND_VM_HANDLER(25, ZEND_ASSIGN_MUL, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ|CACHE_SLOT, SPEC(DIM_OBJ)) -{ - ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, mul_function); -} - -ZEND_VM_HANDLER(26, ZEND_ASSIGN_DIV, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ|CACHE_SLOT, SPEC(DIM_OBJ)) -{ - ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, div_function); -} - -ZEND_VM_HANDLER(27, ZEND_ASSIGN_MOD, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ|CACHE_SLOT, SPEC(DIM_OBJ)) -{ - ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, mod_function); -} - -ZEND_VM_HANDLER(28, ZEND_ASSIGN_SL, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ|CACHE_SLOT, SPEC(DIM_OBJ)) -{ - ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, shift_left_function); -} - -ZEND_VM_HANDLER(29, ZEND_ASSIGN_SR, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ|CACHE_SLOT, SPEC(DIM_OBJ)) -{ - ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, shift_right_function); -} - -ZEND_VM_HANDLER(30, ZEND_ASSIGN_CONCAT, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ|CACHE_SLOT, SPEC(DIM_OBJ)) -{ - ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, concat_function); -} - -ZEND_VM_HANDLER(31, ZEND_ASSIGN_BW_OR, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ|CACHE_SLOT, SPEC(DIM_OBJ)) -{ - ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, bitwise_or_function); -} - -ZEND_VM_HANDLER(32, ZEND_ASSIGN_BW_AND, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ|CACHE_SLOT, SPEC(DIM_OBJ)) -{ - ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, bitwise_and_function); -} - -ZEND_VM_HANDLER(33, ZEND_ASSIGN_BW_XOR, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ|CACHE_SLOT, SPEC(DIM_OBJ)) -{ - ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, bitwise_xor_function); -} - -ZEND_VM_HANDLER(167, ZEND_ASSIGN_POW, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ|CACHE_SLOT, SPEC(DIM_OBJ)) -{ - ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, pow_function); -} - -ZEND_VM_HELPER(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR|CV, int inc) +ZEND_VM_HANDLER(132, ZEND_PRE_INC_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_SLOT) { USE_OPLINE zend_free_op free_op1, free_op2; zval *object; zval *property; zval *zptr; + void **cache_slot; + zend_property_info *prop_info; SAVE_OPLINE(); - object = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW); + object = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { ZEND_VM_DISPATCH_TO_HELPER(zend_this_not_in_object_context_helper); @@ -1073,47 +1343,38 @@ ZEND_VM_HELPER(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR|CV, do { if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { - if (Z_ISREF_P(object)) { + if (Z_ISREF_P(object) && Z_TYPE_P(Z_REFVAL_P(object)) == IS_OBJECT) { object = Z_REFVAL_P(object); - if (EXPECTED(Z_TYPE_P(object) == IS_OBJECT)) { - ZEND_VM_C_GOTO(pre_incdec_object); - } + ZEND_VM_C_GOTO(pre_incdec_object); + } + if (OP1_TYPE == IS_CV + && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { + ZVAL_UNDEFINED_OP1(); } - if (UNEXPECTED(!make_real_object(object, property OPLINE_CC EXECUTE_DATA_CC))) { + object = make_real_object(object, property OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(!object)) { break; } } - /* here we are sure we are dealing with an object */ ZEND_VM_C_LABEL(pre_incdec_object): - if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) - && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL))) != NULL)) { + /* here we are sure we are dealing with an object */ + cache_slot = (OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL; + if (EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, cache_slot)) != NULL)) { if (UNEXPECTED(Z_ISERROR_P(zptr))) { if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - if (EXPECTED(Z_TYPE_P(zptr) == IS_LONG)) { - if (inc) { - fast_long_increment_function(zptr); - } else { - fast_long_decrement_function(zptr); - } + if (OP2_TYPE == IS_CONST) { + prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2); } else { - ZVAL_DEREF(zptr); - - if (inc) { - increment_function(zptr); - } else { - decrement_function(zptr); - } - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), zptr); + prop_info = zend_object_fetch_property_type_info(Z_OBJ_P(object), zptr); } + zend_pre_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); } } else { - zend_pre_incdec_overloaded_property(object, property, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), inc OPLINE_CC EXECUTE_DATA_CC); + zend_pre_incdec_overloaded_property(object, property, cache_slot OPLINE_CC EXECUTE_DATA_CC); } } while (0); @@ -1122,26 +1383,23 @@ ZEND_VM_C_LABEL(pre_incdec_object): ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(132, ZEND_PRE_INC_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_SLOT) -{ - ZEND_VM_DISPATCH_TO_HELPER(zend_pre_incdec_property_helper, inc, 1); -} - ZEND_VM_HANDLER(133, ZEND_PRE_DEC_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_SLOT) { - ZEND_VM_DISPATCH_TO_HELPER(zend_pre_incdec_property_helper, inc, 0); + ZEND_VM_DISPATCH_TO_HANDLER(ZEND_PRE_INC_OBJ); } -ZEND_VM_HELPER(zend_post_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR|CV, int inc) +ZEND_VM_HANDLER(134, ZEND_POST_INC_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_SLOT) { USE_OPLINE zend_free_op free_op1, free_op2; zval *object; zval *property; zval *zptr; + void **cache_slot; + zend_property_info *prop_info; SAVE_OPLINE(); - object = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW); + object = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { ZEND_VM_DISPATCH_TO_HELPER(zend_this_not_in_object_context_helper); @@ -1151,43 +1409,37 @@ ZEND_VM_HELPER(zend_post_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR|CV, do { if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { - if (Z_ISREF_P(object)) { + if (Z_ISREF_P(object) && Z_TYPE_P(Z_REFVAL_P(object)) == IS_OBJECT) { object = Z_REFVAL_P(object); - if (EXPECTED(Z_TYPE_P(object) == IS_OBJECT)) { - ZEND_VM_C_GOTO(post_incdec_object); - } + ZEND_VM_C_GOTO(post_incdec_object); } - if (UNEXPECTED(!make_real_object(object, property OPLINE_CC EXECUTE_DATA_CC))) { + if (OP1_TYPE == IS_CV + && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { + ZVAL_UNDEFINED_OP1(); + } + object = make_real_object(object, property OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(!object)) { break; } } - /* here we are sure we are dealing with an object */ ZEND_VM_C_LABEL(post_incdec_object): - if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) - && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL))) != NULL)) { + /* here we are sure we are dealing with an object */ + cache_slot = (OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL; + if (EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, cache_slot)) != NULL)) { if (UNEXPECTED(Z_ISERROR_P(zptr))) { ZVAL_NULL(EX_VAR(opline->result.var)); } else { - if (EXPECTED(Z_TYPE_P(zptr) == IS_LONG)) { - ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(zptr)); - if (inc) { - fast_long_increment_function(zptr); - } else { - fast_long_decrement_function(zptr); - } + if (OP2_TYPE == IS_CONST) { + prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); } else { - ZVAL_DEREF(zptr); - ZVAL_COPY(EX_VAR(opline->result.var), zptr); - if (inc) { - increment_function(zptr); - } else { - decrement_function(zptr); - } + prop_info = zend_object_fetch_property_type_info(Z_OBJ_P(object), zptr); } + + zend_post_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); } } else { - zend_post_incdec_overloaded_property(object, property, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), inc OPLINE_CC EXECUTE_DATA_CC); + zend_post_incdec_overloaded_property(object, property, cache_slot OPLINE_CC EXECUTE_DATA_CC); } } while (0); @@ -1196,17 +1448,62 @@ ZEND_VM_C_LABEL(post_incdec_object): ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(134, ZEND_POST_INC_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_SLOT) +ZEND_VM_HANDLER(135, ZEND_POST_DEC_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_SLOT) { - ZEND_VM_DISPATCH_TO_HELPER(zend_post_incdec_property_helper, inc, 1); + ZEND_VM_DISPATCH_TO_HANDLER(ZEND_POST_INC_OBJ); } -ZEND_VM_HANDLER(135, ZEND_POST_DEC_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_SLOT) +/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CONST|VAR) */ +ZEND_VM_HANDLER(38, ZEND_PRE_INC_STATIC_PROP, ANY, ANY, CACHE_SLOT) { - ZEND_VM_DISPATCH_TO_HELPER(zend_post_incdec_property_helper, inc, 0); + USE_OPLINE + zval *prop; + zend_property_info *prop_info; + + SAVE_OPLINE(); + + if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) { + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } + + zend_pre_incdec_property_zval(prop, prop_info->type ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + +/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CONST|VAR) */ +ZEND_VM_HANDLER(39, ZEND_PRE_DEC_STATIC_PROP, ANY, ANY, CACHE_SLOT) +{ + ZEND_VM_DISPATCH_TO_HANDLER(ZEND_PRE_INC_STATIC_PROP); } -ZEND_VM_HANDLER(34, ZEND_PRE_INC, VAR|CV, ANY, SPEC(RETVAL)) +/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CONST|VAR) */ +ZEND_VM_HANDLER(40, ZEND_POST_INC_STATIC_PROP, ANY, ANY, CACHE_SLOT) +{ + USE_OPLINE + zval *prop; + zend_property_info *prop_info; + + SAVE_OPLINE(); + + if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) { + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } + + zend_post_incdec_property_zval(prop, prop_info->type ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + +/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CONST|VAR) */ +ZEND_VM_HANDLER(41, ZEND_POST_DEC_STATIC_PROP, ANY, ANY, CACHE_SLOT) +{ + ZEND_VM_DISPATCH_TO_HANDLER(ZEND_POST_INC_STATIC_PROP); +} + +ZEND_VM_HELPER(zend_pre_inc_helper, VAR|CV, ANY) { USE_OPLINE zend_free_op free_op1; @@ -1214,14 +1511,6 @@ ZEND_VM_HANDLER(34, ZEND_PRE_INC, VAR|CV, ANY, SPEC(RETVAL)) var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); - if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { - fast_long_increment_function(var_ptr); - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); - } - ZEND_VM_NEXT_OPCODE(); - } - if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_ISERROR_P(var_ptr))) { if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); @@ -1231,11 +1520,21 @@ ZEND_VM_HANDLER(34, ZEND_PRE_INC, VAR|CV, ANY, SPEC(RETVAL)) SAVE_OPLINE(); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_UNDEF)) { - var_ptr = GET_OP1_UNDEF_CV(var_ptr, BP_VAR_RW); + ZVAL_NULL(var_ptr); + ZVAL_UNDEFINED_OP1(); } - ZVAL_DEREF(var_ptr); - increment_function(var_ptr); + do { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_REFERENCE)) { + zend_reference *ref = Z_REF_P(var_ptr); + var_ptr = Z_REFVAL_P(var_ptr); + if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) { + zend_incdec_typed_ref(ref, NULL OPLINE_CC EXECUTE_DATA_CC); + break; + } + } + increment_function(var_ptr); + } while (0); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); @@ -1245,7 +1544,7 @@ ZEND_VM_HANDLER(34, ZEND_PRE_INC, VAR|CV, ANY, SPEC(RETVAL)) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(35, ZEND_PRE_DEC, VAR|CV, ANY, SPEC(RETVAL)) +ZEND_VM_HOT_HANDLER(34, ZEND_PRE_INC, VAR|CV, ANY, SPEC(RETVAL)) { USE_OPLINE zend_free_op free_op1; @@ -1254,13 +1553,24 @@ ZEND_VM_HANDLER(35, ZEND_PRE_DEC, VAR|CV, ANY, SPEC(RETVAL)) var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { - fast_long_decrement_function(var_ptr); + fast_long_increment_function(var_ptr); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); } ZEND_VM_NEXT_OPCODE(); } + ZEND_VM_DISPATCH_TO_HELPER(zend_pre_inc_helper); +} + +ZEND_VM_HELPER(zend_pre_dec_helper, VAR|CV, ANY) +{ + USE_OPLINE + zend_free_op free_op1; + zval *var_ptr; + + var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); + if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_ISERROR_P(var_ptr))) { if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); @@ -1270,11 +1580,22 @@ ZEND_VM_HANDLER(35, ZEND_PRE_DEC, VAR|CV, ANY, SPEC(RETVAL)) SAVE_OPLINE(); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_UNDEF)) { - var_ptr = GET_OP1_UNDEF_CV(var_ptr, BP_VAR_RW); + ZVAL_NULL(var_ptr); + ZVAL_UNDEFINED_OP1(); } - ZVAL_DEREF(var_ptr); - decrement_function(var_ptr); + do { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_REFERENCE)) { + zend_reference *ref = Z_REF_P(var_ptr); + var_ptr = Z_REFVAL_P(var_ptr); + + if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) { + zend_incdec_typed_ref(ref, NULL OPLINE_CC EXECUTE_DATA_CC); + break; + } + } + decrement_function(var_ptr); + } while (0); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); @@ -1284,7 +1605,7 @@ ZEND_VM_HANDLER(35, ZEND_PRE_DEC, VAR|CV, ANY, SPEC(RETVAL)) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(36, ZEND_POST_INC, VAR|CV, ANY) +ZEND_VM_HOT_HANDLER(35, ZEND_PRE_DEC, VAR|CV, ANY, SPEC(RETVAL)) { USE_OPLINE zend_free_op free_op1; @@ -1293,11 +1614,24 @@ ZEND_VM_HANDLER(36, ZEND_POST_INC, VAR|CV, ANY) var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { - ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr)); - fast_long_increment_function(var_ptr); + fast_long_decrement_function(var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); + } ZEND_VM_NEXT_OPCODE(); } + ZEND_VM_DISPATCH_TO_HELPER(zend_pre_dec_helper); +} + +ZEND_VM_HELPER(zend_post_inc_helper, VAR|CV, ANY) +{ + USE_OPLINE + zend_free_op free_op1; + zval *var_ptr; + + var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); + if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_ISERROR_P(var_ptr))) { ZVAL_NULL(EX_VAR(opline->result.var)); ZEND_VM_NEXT_OPCODE(); @@ -1305,18 +1639,30 @@ ZEND_VM_HANDLER(36, ZEND_POST_INC, VAR|CV, ANY) SAVE_OPLINE(); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_UNDEF)) { - var_ptr = GET_OP1_UNDEF_CV(var_ptr, BP_VAR_RW); + ZVAL_NULL(var_ptr); + ZVAL_UNDEFINED_OP1(); } - ZVAL_DEREF(var_ptr); - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); - increment_function(var_ptr); + do { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_REFERENCE)) { + zend_reference *ref = Z_REF_P(var_ptr); + var_ptr = Z_REFVAL_P(var_ptr); + + if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) { + zend_incdec_typed_ref(ref, EX_VAR(opline->result.var) OPLINE_CC EXECUTE_DATA_CC); + break; + } + } + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + + increment_function(var_ptr); + } while (0); FREE_OP1_VAR_PTR(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(37, ZEND_POST_DEC, VAR|CV, ANY) +ZEND_VM_HOT_HANDLER(36, ZEND_POST_INC, VAR|CV, ANY) { USE_OPLINE zend_free_op free_op1; @@ -1326,10 +1672,21 @@ ZEND_VM_HANDLER(37, ZEND_POST_DEC, VAR|CV, ANY) if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr)); - fast_long_decrement_function(var_ptr); + fast_long_increment_function(var_ptr); ZEND_VM_NEXT_OPCODE(); } + ZEND_VM_DISPATCH_TO_HELPER(zend_post_inc_helper); +} + +ZEND_VM_HELPER(zend_post_dec_helper, VAR|CV, ANY) +{ + USE_OPLINE + zend_free_op free_op1; + zval *var_ptr; + + var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); + if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_ISERROR_P(var_ptr))) { ZVAL_NULL(EX_VAR(opline->result.var)); ZEND_VM_NEXT_OPCODE(); @@ -1337,18 +1694,47 @@ ZEND_VM_HANDLER(37, ZEND_POST_DEC, VAR|CV, ANY) SAVE_OPLINE(); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_UNDEF)) { - var_ptr = GET_OP1_UNDEF_CV(var_ptr, BP_VAR_RW); + ZVAL_NULL(var_ptr); + ZVAL_UNDEFINED_OP1(); } - ZVAL_DEREF(var_ptr); - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); - decrement_function(var_ptr); + do { + if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_REFERENCE)) { + zend_reference *ref = Z_REF_P(var_ptr); + var_ptr = Z_REFVAL_P(var_ptr); + + if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) { + zend_incdec_typed_ref(ref, EX_VAR(opline->result.var) OPLINE_CC EXECUTE_DATA_CC); + break; + } + } + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + + decrement_function(var_ptr); + } while (0); FREE_OP1_VAR_PTR(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(40, ZEND_ECHO, CONST|TMPVAR|CV, ANY) +ZEND_VM_HOT_HANDLER(37, ZEND_POST_DEC, VAR|CV, ANY) +{ + USE_OPLINE + zend_free_op free_op1; + zval *var_ptr; + + var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); + + if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { + ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr)); + fast_long_decrement_function(var_ptr); + ZEND_VM_NEXT_OPCODE(); + } + + ZEND_VM_DISPATCH_TO_HELPER(zend_post_dec_helper); +} + +ZEND_VM_HANDLER(136, ZEND_ECHO, CONST|TMPVAR|CV, ANY) { USE_OPLINE zend_free_op free_op1; @@ -1369,7 +1755,7 @@ ZEND_VM_HANDLER(40, ZEND_ECHO, CONST|TMPVAR|CV, ANY) if (ZSTR_LEN(str) != 0) { zend_write(ZSTR_VAL(str), ZSTR_LEN(str)); } else if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(z) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(z, BP_VAR_R); + ZVAL_UNDEFINED_OP1(); } zend_string_release_ex(str, 0); } @@ -1397,9 +1783,14 @@ ZEND_VM_HELPER(zend_fetch_var_address_helper, CONST|TMPVAR|CV, UNUSED, int type) tmp_name = NULL; } else { if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(varname) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(varname, BP_VAR_R); + ZVAL_UNDEFINED_OP1(); + } + name = zval_try_get_tmp_string(varname, &tmp_name); + if (UNEXPECTED(!name)) { + FREE_OP1(); + ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); } - name = zval_get_tmp_string(varname, &tmp_name); } target_symbol_table = zend_get_target_symbol_table(opline->extended_value EXECUTE_DATA_CC); @@ -1497,115 +1888,47 @@ ZEND_VM_HANDLER(89, ZEND_FETCH_IS, CONST|TMPVAR|CV, UNUSED, VAR_FETCH) ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_var_address_helper, type, BP_VAR_IS); } -ZEND_VM_HELPER(zend_fetch_static_prop_helper, CONST|TMPVAR|CV, UNUSED|CONST|VAR, int type) +/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CONST|VAR) */ +ZEND_VM_HELPER(zend_fetch_static_prop_helper, ANY, ANY, int type) { USE_OPLINE - zend_free_op free_op1; - zval *varname; - zval *retval; - zend_string *name, *tmp_name; - zend_class_entry *ce; + zval *prop; SAVE_OPLINE(); - do { - if (OP2_TYPE == IS_CONST) { - if (OP1_TYPE == IS_CONST && EXPECTED((ce = CACHED_PTR(opline->extended_value)) != NULL)) { - retval = CACHED_PTR(opline->extended_value + sizeof(void*)); - break; - } else { - zval *class_name = RT_CONSTANT(opline, opline->op2); - - if (UNEXPECTED((ce = CACHED_PTR(opline->extended_value)) == NULL)) { - ce = zend_fetch_class_by_name(Z_STR_P(class_name), class_name + 1, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); - if (UNEXPECTED(ce == NULL)) { - FREE_UNFETCHED_OP1(); - retval = NULL; - break; - } - if (OP1_TYPE != IS_CONST) { - CACHE_PTR(opline->extended_value, ce); - } - } - } - } else { - if (OP2_TYPE == IS_UNUSED) { - ce = zend_fetch_class(NULL, opline->op2.num); - if (UNEXPECTED(ce == NULL)) { - FREE_UNFETCHED_OP1(); - retval = NULL; - break; - } - } else { - ce = Z_CE_P(EX_VAR(opline->op2.var)); - } - if (OP1_TYPE == IS_CONST && - EXPECTED(CACHED_PTR(opline->extended_value) == ce)) { - retval = CACHED_PTR(opline->extended_value + sizeof(void*)); - break; - } - } - - varname = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); - if (OP1_TYPE == IS_CONST) { - name = Z_STR_P(varname); - } else if (EXPECTED(Z_TYPE_P(varname) == IS_STRING)) { - name = Z_STR_P(varname); - tmp_name = NULL; - } else { - if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(varname) == IS_UNDEF)) { - zval_undefined_cv(EX(opline)->op1.var EXECUTE_DATA_CC); - } - name = zval_get_tmp_string(varname, &tmp_name); - } - - retval = zend_std_get_static_property(ce, name, type == BP_VAR_IS); - - if (OP1_TYPE != IS_CONST) { - zend_tmp_string_release(tmp_name); - } - - if (OP1_TYPE == IS_CONST && EXPECTED(retval)) { - CACHE_POLYMORPHIC_PTR(opline->extended_value, ce, retval); - } - - FREE_OP1(); - } while (0); - - if (UNEXPECTED(retval == NULL)) { - if (EG(exception)) { - ZVAL_UNDEF(EX_VAR(opline->result.var)); - HANDLE_EXCEPTION(); - } else { - ZEND_ASSERT(type == BP_VAR_IS); - retval = &EG(uninitialized_zval); - } + if (UNEXPECTED(zend_fetch_static_property_address(&prop, NULL, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, opline->extended_value & ZEND_FETCH_OBJ_FLAGS OPLINE_CC EXECUTE_DATA_CC) != SUCCESS)) { + ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS)); + prop = &EG(uninitialized_zval); } if (type == BP_VAR_R || type == BP_VAR_IS) { - ZVAL_COPY_DEREF(EX_VAR(opline->result.var), retval); + ZVAL_COPY_DEREF(EX_VAR(opline->result.var), prop); } else { - ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); + ZVAL_INDIRECT(EX_VAR(opline->result.var), prop); } ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(173, ZEND_FETCH_STATIC_PROP_R, CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR, CACHE_SLOT) +/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */ +ZEND_VM_HANDLER(173, ZEND_FETCH_STATIC_PROP_R, ANY, CLASS_FETCH, CACHE_SLOT) { ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_R); } -ZEND_VM_HANDLER(174, ZEND_FETCH_STATIC_PROP_W, CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR, CACHE_SLOT) +/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */ +ZEND_VM_HANDLER(174, ZEND_FETCH_STATIC_PROP_W, ANY, CLASS_FETCH, FETCH_REF|DIM_OBJ_WRITE|CACHE_SLOT) { ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_W); } -ZEND_VM_HANDLER(175, ZEND_FETCH_STATIC_PROP_RW, CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR, CACHE_SLOT) +/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */ +ZEND_VM_HANDLER(175, ZEND_FETCH_STATIC_PROP_RW, ANY, CLASS_FETCH, CACHE_SLOT) { ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_RW); } -ZEND_VM_HANDLER(177, ZEND_FETCH_STATIC_PROP_FUNC_ARG, CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR, CACHE_SLOT) +/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */ +ZEND_VM_HANDLER(177, ZEND_FETCH_STATIC_PROP_FUNC_ARG, ANY, CLASS_FETCH, FETCH_REF|CACHE_SLOT) { int fetch_type = (UNEXPECTED(ZEND_CALL_INFO(EX(call)) & ZEND_CALL_SEND_ARG_BY_REF)) ? @@ -1613,12 +1936,14 @@ ZEND_VM_HANDLER(177, ZEND_FETCH_STATIC_PROP_FUNC_ARG, CONST|TMPVAR|CV, UNUSED|CL ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, fetch_type); } -ZEND_VM_HANDLER(178, ZEND_FETCH_STATIC_PROP_UNSET, CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR, CACHE_SLOT) +/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */ +ZEND_VM_HANDLER(178, ZEND_FETCH_STATIC_PROP_UNSET, ANY, CLASS_FETCH, CACHE_SLOT) { ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_UNSET); } -ZEND_VM_HANDLER(176, ZEND_FETCH_STATIC_PROP_IS, CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR, CACHE_SLOT) +/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */ +ZEND_VM_HANDLER(176, ZEND_FETCH_STATIC_PROP_IS, ANY, CLASS_FETCH, CACHE_SLOT) { ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_IS); } @@ -1627,7 +1952,7 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(81, ZEND_FETCH_DIM_R, CONST|TMPVAR|CV, CONST|TMP { USE_OPLINE zend_free_op free_op1, free_op2; - zval *container, *dim, *value, *result; + zval *container, *dim, *value; SAVE_OPLINE(); container = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); @@ -1636,8 +1961,7 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(81, ZEND_FETCH_DIM_R, CONST|TMPVAR|CV, CONST|TMP if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { ZEND_VM_C_LABEL(fetch_dim_r_array): value = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, OP2_TYPE, BP_VAR_R EXECUTE_DATA_CC); - result = EX_VAR(opline->result.var); - ZVAL_COPY_DEREF(result, value); + ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) { container = Z_REFVAL_P(container); if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { @@ -1734,6 +2058,10 @@ ZEND_VM_COLD_HELPER(zend_use_undef_in_read_context_helper, ANY, ANY) ZEND_VM_COLD_CONSTCONST_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, CONST|TMP|VAR|CV, CONST|TMPVAR|UNUSED|NEXT|CV) { +#if !ZEND_VM_SPEC + USE_OPLINE +#endif + if (UNEXPECTED(ZEND_CALL_INFO(EX(call)) & ZEND_CALL_SEND_ARG_BY_REF)) { if ((OP1_TYPE & (IS_CONST|IS_TMP_VAR))) { ZEND_VM_DISPATCH_TO_HELPER(zend_use_tmp_in_write_context_helper); @@ -1792,12 +2120,14 @@ ZEND_VM_HOT_OBJ_HANDLER(82, ZEND_FETCH_OBJ_R, CONST|TMPVAR|UNUSED|THIS|CV, CONST } } if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(container, BP_VAR_R); + ZVAL_UNDEFINED_OP1(); } if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(offset) == IS_UNDEF)) { - GET_OP2_UNDEF_CV(offset, BP_VAR_R); + ZVAL_UNDEFINED_OP2(); } - ZEND_VM_C_GOTO(fetch_obj_r_no_object); + zend_wrong_property_read(offset); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_C_GOTO(fetch_obj_r_finish); } while (0); } @@ -1807,7 +2137,7 @@ ZEND_VM_HOT_OBJ_HANDLER(82, ZEND_FETCH_OBJ_R, CONST|TMPVAR|UNUSED|THIS|CV, CONST zval *retval; if (OP2_TYPE == IS_CONST) { - cache_slot = CACHE_ADDR(opline->extended_value); + cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_REF /* FUNC_ARG fetch may contain it */); if (EXPECTED(zobj->ce == CACHED_PTR_EX(cache_slot))) { uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); @@ -1815,8 +2145,13 @@ ZEND_VM_HOT_OBJ_HANDLER(82, ZEND_FETCH_OBJ_R, CONST|TMPVAR|UNUSED|THIS|CV, CONST if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { retval = OBJ_PROP(zobj, prop_offset); if (EXPECTED(Z_TYPE_INFO_P(retval) != IS_UNDEF)) { - ZVAL_COPY_DEREF(EX_VAR(opline->result.var), retval); - break; + if (!ZEND_VM_SPEC || (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) != 0) { + ZEND_VM_C_GOTO(fetch_obj_r_copy); + } else { +ZEND_VM_C_LABEL(fetch_obj_r_fast_copy): + ZVAL_COPY_DEREF(EX_VAR(opline->result.var), retval); + ZEND_VM_NEXT_OPCODE(); + } } } else if (EXPECTED(zobj->properties != NULL)) { if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(prop_offset)) { @@ -1830,8 +2165,12 @@ ZEND_VM_HOT_OBJ_HANDLER(82, ZEND_FETCH_OBJ_R, CONST|TMPVAR|UNUSED|THIS|CV, CONST (EXPECTED(p->h == ZSTR_H(Z_STR_P(offset))) && EXPECTED(p->key != NULL) && EXPECTED(zend_string_equal_content(p->key, Z_STR_P(offset)))))) { - ZVAL_COPY_DEREF(EX_VAR(opline->result.var), &p->val); - break; + retval = &p->val; + if (!ZEND_VM_SPEC || (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) != 0) { + ZEND_VM_C_GOTO(fetch_obj_r_copy); + } else { + ZEND_VM_C_GOTO(fetch_obj_r_fast_copy); + } } } CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET); @@ -1840,36 +2179,35 @@ ZEND_VM_HOT_OBJ_HANDLER(82, ZEND_FETCH_OBJ_R, CONST|TMPVAR|UNUSED|THIS|CV, CONST if (EXPECTED(retval)) { uintptr_t idx = (char*)retval - (char*)zobj->properties->arData; CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx)); - ZVAL_COPY_DEREF(EX_VAR(opline->result.var), retval); - break; + if (!ZEND_VM_SPEC || (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) != 0) { + ZEND_VM_C_GOTO(fetch_obj_r_copy); + } else { + ZEND_VM_C_GOTO(fetch_obj_r_fast_copy); + } } } } } else if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(offset) == IS_UNDEF)) { - GET_OP2_UNDEF_CV(offset, BP_VAR_R); + ZVAL_UNDEFINED_OP2(); } - if (UNEXPECTED(zobj->handlers->read_property == NULL)) { -ZEND_VM_C_LABEL(fetch_obj_r_no_object): - zend_wrong_property_read(offset); - ZVAL_NULL(EX_VAR(opline->result.var)); - } else { - retval = zobj->handlers->read_property(container, offset, BP_VAR_R, cache_slot, EX_VAR(opline->result.var)); + retval = zobj->handlers->read_property(container, offset, BP_VAR_R, cache_slot, EX_VAR(opline->result.var)); - if (retval != EX_VAR(opline->result.var)) { - ZVAL_COPY_DEREF(EX_VAR(opline->result.var), retval); - } else if (UNEXPECTED(Z_ISREF_P(retval))) { - zend_unwrap_reference(retval); - } + if (retval != EX_VAR(opline->result.var)) { +ZEND_VM_C_LABEL(fetch_obj_r_copy): + ZVAL_COPY_DEREF(EX_VAR(opline->result.var), retval); + } else if (UNEXPECTED(Z_ISREF_P(retval))) { + zend_unwrap_reference(retval); } } while (0); +ZEND_VM_C_LABEL(fetch_obj_r_finish): FREE_OP2(); FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(85, ZEND_FETCH_OBJ_W, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_SLOT) +ZEND_VM_HANDLER(85, ZEND_FETCH_OBJ_W, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, FETCH_REF|DIM_OBJ_WRITE|CACHE_SLOT) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -1884,7 +2222,10 @@ ZEND_VM_HANDLER(85, ZEND_FETCH_OBJ_W, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE property = GET_OP2_ZVAL_PTR(BP_VAR_R); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_W OPLINE_CC); + zend_fetch_property_address( + result, container, OP1_TYPE, property, OP2_TYPE, + ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), + BP_VAR_W, opline->extended_value & ZEND_FETCH_OBJ_FLAGS, 1 OPLINE_CC EXECUTE_DATA_CC); FREE_OP2(); if (OP1_TYPE == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(free_op1, result); @@ -1899,14 +2240,14 @@ ZEND_VM_HANDLER(88, ZEND_FETCH_OBJ_RW, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACH zval *property, *container, *result; SAVE_OPLINE(); - container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW); + container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) { ZEND_VM_DISPATCH_TO_HELPER(zend_this_not_in_object_context_helper); } property = GET_OP2_ZVAL_PTR(BP_VAR_R); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW OPLINE_CC); + zend_fetch_property_address(result, container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0, 1 OPLINE_CC EXECUTE_DATA_CC); FREE_OP2(); if (OP1_TYPE == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(free_op1, result); @@ -1941,7 +2282,8 @@ ZEND_VM_COLD_CONST_HANDLER(91, ZEND_FETCH_OBJ_IS, CONST|TMPVAR|UNUSED|THIS|CV, C break; } } - ZEND_VM_C_GOTO(fetch_obj_is_no_object); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_C_GOTO(fetch_obj_is_finish); } while (0); } @@ -1959,8 +2301,13 @@ ZEND_VM_COLD_CONST_HANDLER(91, ZEND_FETCH_OBJ_IS, CONST|TMPVAR|UNUSED|THIS|CV, C if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { retval = OBJ_PROP(zobj, prop_offset); if (EXPECTED(Z_TYPE_P(retval) != IS_UNDEF)) { - ZVAL_COPY(EX_VAR(opline->result.var), retval); - break; + if (!ZEND_VM_SPEC || (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) != 0) { + ZEND_VM_C_GOTO(fetch_obj_is_copy); + } else { +ZEND_VM_C_LABEL(fetch_obj_is_fast_copy): + ZVAL_COPY_DEREF(EX_VAR(opline->result.var), retval); + ZEND_VM_NEXT_OPCODE(); + } } } else if (EXPECTED(zobj->properties != NULL)) { if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(prop_offset)) { @@ -1974,8 +2321,12 @@ ZEND_VM_COLD_CONST_HANDLER(91, ZEND_FETCH_OBJ_IS, CONST|TMPVAR|UNUSED|THIS|CV, C (EXPECTED(p->h == ZSTR_H(Z_STR_P(offset))) && EXPECTED(p->key != NULL) && EXPECTED(zend_string_equal_content(p->key, Z_STR_P(offset)))))) { - ZVAL_COPY(EX_VAR(opline->result.var), &p->val); - break; + retval = &p->val; + if (!ZEND_VM_SPEC || (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) != 0) { + ZEND_VM_C_GOTO(fetch_obj_is_copy); + } else { + ZEND_VM_C_GOTO(fetch_obj_is_fast_copy); + } } } CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET); @@ -1984,39 +2335,43 @@ ZEND_VM_COLD_CONST_HANDLER(91, ZEND_FETCH_OBJ_IS, CONST|TMPVAR|UNUSED|THIS|CV, C if (EXPECTED(retval)) { uintptr_t idx = (char*)retval - (char*)zobj->properties->arData; CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx)); - ZVAL_COPY(EX_VAR(opline->result.var), retval); - break; + if (!ZEND_VM_SPEC || (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) != 0) { + ZEND_VM_C_GOTO(fetch_obj_is_copy); + } else { + ZEND_VM_C_GOTO(fetch_obj_is_fast_copy); + } } } } } - if (UNEXPECTED(zobj->handlers->read_property == NULL)) { -ZEND_VM_C_LABEL(fetch_obj_is_no_object): - ZVAL_NULL(EX_VAR(opline->result.var)); - } else { - - retval = zobj->handlers->read_property(container, offset, BP_VAR_IS, cache_slot, EX_VAR(opline->result.var)); + retval = zobj->handlers->read_property(container, offset, BP_VAR_IS, cache_slot, EX_VAR(opline->result.var)); - if (retval != EX_VAR(opline->result.var)) { - ZVAL_COPY(EX_VAR(opline->result.var), retval); - } + if (retval != EX_VAR(opline->result.var)) { +ZEND_VM_C_LABEL(fetch_obj_is_copy): + ZVAL_COPY_DEREF(EX_VAR(opline->result.var), retval); + } else if (UNEXPECTED(Z_ISREF_P(retval))) { + zend_unwrap_reference(retval); } } while (0); +ZEND_VM_C_LABEL(fetch_obj_is_finish): FREE_OP2(); FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_CONST_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, CONST|TMP|VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_SLOT) +ZEND_VM_COLD_CONST_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, CONST|TMP|VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, FETCH_REF|CACHE_SLOT) { +#if !ZEND_VM_SPEC + USE_OPLINE +#endif + if (UNEXPECTED(ZEND_CALL_INFO(EX(call)) & ZEND_CALL_SEND_ARG_BY_REF)) { /* Behave like FETCH_OBJ_W */ if ((OP1_TYPE & (IS_CONST|IS_TMP_VAR))) { ZEND_VM_DISPATCH_TO_HELPER(zend_use_tmp_in_write_context_helper); } - ZEND_VM_DISPATCH_TO_HANDLER(ZEND_FETCH_OBJ_W); } else { ZEND_VM_DISPATCH_TO_HANDLER(ZEND_FETCH_OBJ_R); @@ -2030,7 +2385,7 @@ ZEND_VM_HANDLER(97, ZEND_FETCH_OBJ_UNSET, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, C zval *container, *property, *result; SAVE_OPLINE(); - container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_UNSET); + container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_UNSET); if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) { ZEND_VM_DISPATCH_TO_HELPER(zend_this_not_in_object_context_helper); @@ -2038,7 +2393,7 @@ ZEND_VM_HANDLER(97, ZEND_FETCH_OBJ_UNSET, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, C property = GET_OP2_ZVAL_PTR(BP_VAR_R); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET OPLINE_CC); + zend_fetch_property_address(result, container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0, 1 OPLINE_CC EXECUTE_DATA_CC); FREE_OP2(); if (OP1_TYPE == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(free_op1, result); @@ -2059,7 +2414,7 @@ ZEND_VM_HANDLER(98, ZEND_FETCH_LIST_R, CONST|TMPVARCV, CONST|TMPVAR|CV) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(198, ZEND_FETCH_LIST_W, VAR, CONST|TMPVAR|CV) +ZEND_VM_HANDLER(155, ZEND_FETCH_LIST_W, VAR, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -2083,7 +2438,7 @@ ZEND_VM_HANDLER(198, ZEND_FETCH_LIST_W, VAR, CONST|TMPVAR|CV) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(136, ZEND_ASSIGN_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_SLOT, SPEC(OP_DATA=CONST|TMP|VAR|CV)) +ZEND_VM_HANDLER(24, ZEND_ASSIGN_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_SLOT, SPEC(OP_DATA=CONST|TMP|VAR|CV)) { USE_OPLINE zend_free_op free_op1, free_op2, free_op_data; @@ -2100,34 +2455,52 @@ ZEND_VM_HANDLER(136, ZEND_ASSIGN_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R); if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { - if (Z_ISREF_P(object)) { + if (Z_ISREF_P(object) && Z_TYPE_P(Z_REFVAL_P(object)) == IS_OBJECT) { object = Z_REFVAL_P(object); - if (EXPECTED(Z_TYPE_P(object) == IS_OBJECT)) { - ZEND_VM_C_GOTO(assign_object); - } + ZEND_VM_C_GOTO(assign_object); } - if (UNEXPECTED(!make_real_object(object, property OPLINE_CC EXECUTE_DATA_CC))) { - FREE_OP_DATA(); - ZEND_VM_C_GOTO(exit_assign_obj); + object = make_real_object(object, property OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(!object)) { + value = &EG(uninitialized_zval); + ZEND_VM_C_GOTO(free_and_exit_assign_obj); } } ZEND_VM_C_LABEL(assign_object): if (OP2_TYPE == IS_CONST && EXPECTED(Z_OBJCE_P(object) == CACHED_PTR(opline->extended_value))) { - uintptr_t prop_offset = (uintptr_t)CACHED_PTR(opline->extended_value + sizeof(void*)); + void **cache_slot = CACHE_ADDR(opline->extended_value); + uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zend_object *zobj = Z_OBJ_P(object); zval *property_val; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { + zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + + if (UNEXPECTED(prop_info != NULL)) { + zend_uchar orig_type = IS_UNDEF; + + if (OP_DATA_TYPE == IS_CONST) { + orig_type = Z_TYPE_P(value); + } + + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + + /* will remain valid, thus no need to check prop_info in future here */ + if (OP_DATA_TYPE == IS_CONST && Z_TYPE_P(value) == orig_type) { + CACHE_PTR_EX(cache_slot + 2, NULL); + } + ZEND_VM_C_GOTO(free_and_exit_assign_obj); + } else { ZEND_VM_C_LABEL(fast_assign_obj): - value = zend_assign_to_variable(property_val, value, OP_DATA_TYPE); - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_variable(property_val, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES()); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + ZEND_VM_C_GOTO(exit_assign_obj); } - ZEND_VM_C_GOTO(exit_assign_obj); } } else { if (EXPECTED(zobj->properties != NULL)) { @@ -2181,18 +2554,13 @@ ZEND_VM_C_LABEL(fast_assign_obj): } } - if (!Z_OBJ_HT_P(object)->write_property) { - zend_wrong_property_assignment(property OPLINE_CC EXECUTE_DATA_CC); - FREE_OP_DATA(); - ZEND_VM_C_GOTO(exit_assign_obj); - } - if (OP_DATA_TYPE == IS_CV || OP_DATA_TYPE == IS_VAR) { ZVAL_DEREF(value); } - Z_OBJ_HT_P(object)->write_property(object, property, value, (OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL); + value = Z_OBJ_HT_P(object)->write_property(object, property, value, (OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL); +ZEND_VM_C_LABEL(free_and_exit_assign_obj): if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -2204,30 +2572,62 @@ ZEND_VM_C_LABEL(exit_assign_obj): ZEND_VM_NEXT_OPCODE_EX(1, 2); } -ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMPVAR|UNUSED|NEXT|CV, SPEC(OP_DATA=CONST|TMP|VAR|CV)) +/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CONST|VAR) */ +ZEND_VM_HANDLER(25, ZEND_ASSIGN_STATIC_PROP, ANY, ANY, CACHE_SLOT, SPEC(OP_DATA=CONST|TMP|VAR|CV)) +{ + USE_OPLINE + zend_free_op free_op_data; + zval *prop, *value; + zend_property_info *prop_info; + + SAVE_OPLINE(); + + if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) { + FREE_UNFETCHED_OP_DATA(); + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } + + value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R); + + if (UNEXPECTED(prop_info->type)) { + value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC); + FREE_OP_DATA(); + } else { + value = zend_assign_to_variable(prop, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES()); + } + + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + + /* assign_static_prop has two opcodes! */ + ZEND_VM_NEXT_OPCODE_EX(1, 2); +} + +ZEND_VM_HANDLER(23, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMPVAR|UNUSED|NEXT|CV, SPEC(OP_DATA=CONST|TMP|VAR|CV)) { USE_OPLINE zend_free_op free_op1; - zval *object_ptr; + zval *object_ptr, *orig_object_ptr; zend_free_op free_op2, free_op_data; zval *value; zval *variable_ptr; zval *dim; SAVE_OPLINE(); - object_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); + orig_object_ptr = object_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); if (EXPECTED(Z_TYPE_P(object_ptr) == IS_ARRAY)) { ZEND_VM_C_LABEL(try_assign_dim_array): + value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R); SEPARATE_ARRAY(object_ptr); if (OP2_TYPE == IS_UNUSED) { - value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R); if (OP_DATA_TYPE == IS_CV || OP_DATA_TYPE == IS_VAR) { ZVAL_DEREF(value); } variable_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(object_ptr), value); if (UNEXPECTED(variable_ptr == NULL)) { - FREE_OP_DATA(); zend_cannot_add_element(); ZEND_VM_C_GOTO(assign_dim_error); } else if (OP_DATA_TYPE == IS_CV) { @@ -2256,8 +2656,7 @@ ZEND_VM_C_LABEL(try_assign_dim_array): if (UNEXPECTED(variable_ptr == NULL)) { ZEND_VM_C_GOTO(assign_dim_error); } - value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R); - value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE); + value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES()); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); @@ -2283,9 +2682,7 @@ ZEND_VM_C_LABEL(try_assign_dim_array): if (OP2_TYPE == IS_UNUSED) { zend_use_new_element_for_string(); FREE_UNFETCHED_OP_DATA(); - FREE_OP1_VAR_PTR(); UNDEF_RESULT(); - HANDLE_EXCEPTION(); } else { dim = GET_OP2_ZVAL_PTR(BP_VAR_R); value = GET_OP_DATA_ZVAL_PTR_DEREF(BP_VAR_R); @@ -2293,8 +2690,16 @@ ZEND_VM_C_LABEL(try_assign_dim_array): FREE_OP_DATA(); } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - ZVAL_ARR(object_ptr, zend_new_array(8)); - ZEND_VM_C_GOTO(try_assign_dim_array); + if (Z_ISREF_P(orig_object_ptr) + && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) + && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { + dim = GET_OP2_ZVAL_PTR(BP_VAR_R); + FREE_UNFETCHED_OP_DATA(); + UNDEF_RESULT(); + } else { + ZVAL_ARR(object_ptr, zend_new_array(8)); + ZEND_VM_C_GOTO(try_assign_dim_array); + } } else { if (OP1_TYPE != IS_VAR || EXPECTED(!Z_ISERROR_P(object_ptr))) { zend_use_scalar_as_array(); @@ -2315,7 +2720,7 @@ ZEND_VM_C_LABEL(assign_dim_error): ZEND_VM_NEXT_OPCODE_EX(1, 2); } -ZEND_VM_HANDLER(38, ZEND_ASSIGN, VAR|CV, CONST|TMP|VAR|CV, SPEC(RETVAL)) +ZEND_VM_HANDLER(22, ZEND_ASSIGN, VAR|CV, CONST|TMP|VAR|CV, SPEC(RETVAL)) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -2332,7 +2737,7 @@ ZEND_VM_HANDLER(38, ZEND_ASSIGN, VAR|CV, CONST|TMP|VAR|CV, SPEC(RETVAL)) ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - value = zend_assign_to_variable(variable_ptr, value, OP2_TYPE); + value = zend_assign_to_variable(variable_ptr, value, OP2_TYPE, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -2343,7 +2748,7 @@ ZEND_VM_HANDLER(38, ZEND_ASSIGN, VAR|CV, CONST|TMP|VAR|CV, SPEC(RETVAL)) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV, SRC) +ZEND_VM_HANDLER(30, ZEND_ASSIGN_REF, VAR|CV, VAR|CV, SRC) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -2359,26 +2764,17 @@ ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV, SRC) } else if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT)) { - zend_throw_error(NULL, "Cannot assign by reference to overloaded object"); - FREE_OP1_VAR_PTR(); - FREE_OP2_VAR_PTR(); - UNDEF_RESULT(); - HANDLE_EXCEPTION(); + zend_throw_error(NULL, "Cannot assign by reference to an array dimension of an object"); + variable_ptr = &EG(uninitialized_zval); } else if (OP2_TYPE == IS_VAR && UNEXPECTED(Z_ISERROR_P(value_ptr))) { variable_ptr = &EG(uninitialized_zval); } else if (OP2_TYPE == IS_VAR && opline->extended_value == ZEND_RETURNS_FUNCTION && UNEXPECTED(!Z_ISREF_P(value_ptr))) { - if (UNEXPECTED(!zend_wrong_assign_to_variable_reference(variable_ptr, value_ptr, OP2_TYPE OPLINE_CC EXECUTE_DATA_CC))) { - FREE_OP2_VAR_PTR(); - UNDEF_RESULT(); - HANDLE_EXCEPTION(); + if (UNEXPECTED(!zend_wrong_assign_to_variable_reference(variable_ptr, value_ptr OPLINE_CC EXECUTE_DATA_CC))) { + variable_ptr = &EG(uninitialized_zval); } - - /* op2 freed by assign_to_variable */ - FREE_OP1_VAR_PTR(); - ZEND_VM_NEXT_OPCODE(); } else { zend_assign_to_variable_reference(variable_ptr, value_ptr); } @@ -2392,26 +2788,101 @@ ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV, SRC) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +ZEND_VM_HANDLER(32, ZEND_ASSIGN_OBJ_REF, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_SLOT|SRC, SPEC(OP_DATA=VAR|CV)) +{ + USE_OPLINE + zend_free_op free_op1, free_op2, free_op_data; + zval *property, *container, *value_ptr; + + SAVE_OPLINE(); + + container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); + + if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) { + ZEND_VM_DISPATCH_TO_HELPER(zend_this_not_in_object_context_helper); + } + + property = GET_OP2_ZVAL_PTR(BP_VAR_R); + + value_ptr = GET_OP_DATA_ZVAL_PTR_PTR(BP_VAR_W); + + if (ZEND_VM_SPEC) { + if (OP1_TYPE == IS_UNUSED) { + if (OP2_TYPE == IS_CONST) { + zend_assign_to_property_reference_this_const(container, property, value_ptr OPLINE_CC EXECUTE_DATA_CC); + } else { + zend_assign_to_property_reference_this_var(container, property, value_ptr OPLINE_CC EXECUTE_DATA_CC); + } + } else { + if (OP2_TYPE == IS_CONST) { + zend_assign_to_property_reference_var_const(container, property, value_ptr OPLINE_CC EXECUTE_DATA_CC); + } else { + zend_assign_to_property_reference_var_var(container, property, value_ptr OPLINE_CC EXECUTE_DATA_CC); + } + } + } else { + zend_assign_to_property_reference(container, OP1_TYPE, property, OP2_TYPE, value_ptr OPLINE_CC EXECUTE_DATA_CC); + } + + FREE_OP1_VAR_PTR(); + FREE_OP2(); + FREE_OP_DATA_VAR_PTR(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); +} + +/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CONST|VAR) */ +ZEND_VM_HANDLER(33, ZEND_ASSIGN_STATIC_PROP_REF, ANY, ANY, CACHE_SLOT|SRC) +{ + USE_OPLINE + zend_free_op free_op_data; + zval *prop, *value_ptr; + zend_property_info *prop_info; + + SAVE_OPLINE(); + + if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value & ~ZEND_RETURNS_FUNCTION, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) { + FREE_UNFETCHED_OP_DATA(); + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } + + value_ptr = GET_OP_DATA_ZVAL_PTR_PTR(BP_VAR_W); + + if (OP_DATA_TYPE == IS_VAR && UNEXPECTED(Z_ISERROR_P(value_ptr))) { + prop = &EG(uninitialized_zval); + } else if (OP_DATA_TYPE == IS_VAR && (opline->extended_value & ZEND_RETURNS_FUNCTION) && UNEXPECTED(!Z_ISREF_P(value_ptr))) { + if (UNEXPECTED(!zend_wrong_assign_to_variable_reference(prop, value_ptr OPLINE_CC EXECUTE_DATA_CC))) { + prop = &EG(uninitialized_zval); + } + } else if (UNEXPECTED(prop_info->type)) { + prop = zend_assign_to_typed_property_reference(prop_info, prop, value_ptr EXECUTE_DATA_CC); + } else { + zend_assign_to_variable_reference(prop, value_ptr); + } + + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), prop); + } + + FREE_OP_DATA_VAR_PTR(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); +} + ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) { zend_execute_data *old_execute_data; uint32_t call_info = EX_CALL_INFO(); + SAVE_OPLINE(); if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED)) == 0)) { EG(current_execute_data) = EX(prev_execute_data); i_free_compiled_variables(execute_data); - if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) { - zend_object *object = Z_OBJ(execute_data->This); -#if 0 - if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) { -#else - if (UNEXPECTED(EG(exception) != NULL) && (call_info & ZEND_CALL_CTOR)) { +#ifdef ZEND_PREFER_RELOAD + call_info = EX_CALL_INFO(); #endif - GC_DELREF(object); - zend_object_store_ctor_failed(object); - } - OBJ_RELEASE(object); + if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) { + OBJ_RELEASE(Z_OBJ(execute_data->This)); } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } @@ -2429,6 +2900,9 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) EG(current_execute_data) = EX(prev_execute_data); i_free_compiled_variables(execute_data); +#ifdef ZEND_PREFER_RELOAD + call_info = EX_CALL_INFO(); +#endif if (UNEXPECTED(call_info & ZEND_CALL_HAS_SYMBOL_TABLE)) { zend_clean_and_cache_symbol_table(EX(symbol_table)); } @@ -2438,16 +2912,7 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) zend_vm_stack_free_extra_args_ex(call_info, execute_data); if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) { - zend_object *object = Z_OBJ(execute_data->This); -#if 0 - if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) { -#else - if (UNEXPECTED(EG(exception) != NULL) && (call_info & ZEND_CALL_CTOR)) { -#endif - GC_DELREF(object); - zend_object_store_ctor_failed(object); - } - OBJ_RELEASE(object); + OBJ_RELEASE(Z_OBJ(execute_data->This)); } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } @@ -2467,6 +2932,9 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) zend_detach_symbol_table(execute_data); destroy_op_array(&EX(func)->op_array); efree_size(EX(func), sizeof(zend_op_array)); +#ifdef ZEND_PREFER_RELOAD + call_info = EX_CALL_INFO(); +#endif old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); @@ -2483,6 +2951,9 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) if (EXPECTED((call_info & ZEND_CALL_CODE) == 0)) { EG(current_execute_data) = EX(prev_execute_data); i_free_compiled_variables(execute_data); +#ifdef ZEND_PREFER_RELOAD + call_info = EX_CALL_INFO(); +#endif if (UNEXPECTED(call_info & (ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS))) { if (UNEXPECTED(call_info & ZEND_CALL_HAS_SYMBOL_TABLE)) { zend_clean_and_cache_symbol_table(EX(symbol_table)); @@ -2533,7 +3004,7 @@ ZEND_VM_HOT_NOCONST_HANDLER(43, ZEND_JMPZ, CONST|TMPVAR|CV, JMP_ADDR) } else if (EXPECTED(Z_TYPE_INFO_P(val) <= IS_TRUE)) { if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(val) == IS_UNDEF)) { SAVE_OPLINE(); - GET_OP1_UNDEF_CV(val, BP_VAR_R); + ZVAL_UNDEFINED_OP1(); if (UNEXPECTED(EG(exception))) { HANDLE_EXCEPTION(); } @@ -2564,7 +3035,7 @@ ZEND_VM_HOT_NOCONST_HANDLER(44, ZEND_JMPNZ, CONST|TMPVAR|CV, JMP_ADDR) } else if (EXPECTED(Z_TYPE_INFO_P(val) <= IS_TRUE)) { if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(val) == IS_UNDEF)) { SAVE_OPLINE(); - GET_OP1_UNDEF_CV(val, BP_VAR_R); + ZVAL_UNDEFINED_OP1(); if (UNEXPECTED(EG(exception))) { HANDLE_EXCEPTION(); } @@ -2582,7 +3053,7 @@ ZEND_VM_HOT_NOCONST_HANDLER(44, ZEND_JMPNZ, CONST|TMPVAR|CV, JMP_ADDR) ZEND_VM_JMP(opline); } -ZEND_VM_HOT_NOCONST_HANDLER(45, ZEND_JMPZNZ, CONST|TMPVAR|CV, JMP_ADDR, JMP_ADDR) +ZEND_VM_HANDLER(45, ZEND_JMPZNZ, CONST|TMPVAR|CV, JMP_ADDR, JMP_ADDR) { USE_OPLINE zend_free_op free_op1; @@ -2596,7 +3067,7 @@ ZEND_VM_HOT_NOCONST_HANDLER(45, ZEND_JMPZNZ, CONST|TMPVAR|CV, JMP_ADDR, JMP_ADDR } else if (EXPECTED(Z_TYPE_INFO_P(val) <= IS_TRUE)) { if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(val) == IS_UNDEF)) { SAVE_OPLINE(); - GET_OP1_UNDEF_CV(val, BP_VAR_R); + ZVAL_UNDEFINED_OP1(); if (UNEXPECTED(EG(exception))) { HANDLE_EXCEPTION(); } @@ -2630,7 +3101,7 @@ ZEND_VM_COLD_CONST_HANDLER(46, ZEND_JMPZ_EX, CONST|TMPVAR|CV, JMP_ADDR) ZVAL_FALSE(EX_VAR(opline->result.var)); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(val) == IS_UNDEF)) { SAVE_OPLINE(); - GET_OP1_UNDEF_CV(val, BP_VAR_R); + ZVAL_UNDEFINED_OP1(); if (UNEXPECTED(EG(exception))) { HANDLE_EXCEPTION(); } @@ -2667,7 +3138,7 @@ ZEND_VM_COLD_CONST_HANDLER(47, ZEND_JMPNZ_EX, CONST|TMPVAR|CV, JMP_ADDR) ZVAL_FALSE(EX_VAR(opline->result.var)); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(val) == IS_UNDEF)) { SAVE_OPLINE(); - GET_OP1_UNDEF_CV(val, BP_VAR_R); + ZVAL_UNDEFINED_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } else { ZEND_VM_NEXT_OPCODE(); @@ -2732,14 +3203,18 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP } else { ZVAL_STR(EX_VAR(opline->result.var), op2_str); } - FREE_OP1(); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zend_string_release_ex(op1_str, 0); + } } else if (OP2_TYPE != IS_CONST && UNEXPECTED(ZSTR_LEN(op2_str) == 0)) { if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_CV) { ZVAL_STR_COPY(EX_VAR(opline->result.var), op1_str); } else { ZVAL_STR(EX_VAR(opline->result.var), op1_str); } - FREE_OP2(); + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zend_string_release_ex(op2_str, 0); + } } else if (OP1_TYPE != IS_CONST && OP1_TYPE != IS_CV && !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { size_t len = ZSTR_LEN(op1_str); @@ -2747,14 +3222,20 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - FREE_OP2(); + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zend_string_release_ex(op2_str, 0); + } } else { str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - FREE_OP1(); - FREE_OP2(); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zend_string_release_ex(op1_str, 0); + } + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zend_string_release_ex(op2_str, 0); + } } ZEND_VM_NEXT_OPCODE(); } @@ -2766,7 +3247,7 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP op1_str = zend_string_copy(Z_STR_P(op1)); } else { if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(op1, BP_VAR_R); + ZVAL_UNDEFINED_OP1(); } op1_str = zval_get_string_func(op1); } @@ -2776,7 +3257,7 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP op2_str = zend_string_copy(Z_STR_P(op2)); } else { if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { - GET_OP2_UNDEF_CV(op2, BP_VAR_R); + ZVAL_UNDEFINED_OP2(); } op2_str = zval_get_string_func(op2); } @@ -2847,7 +3328,7 @@ ZEND_VM_HANDLER(54, ZEND_ROPE_INIT, UNUSED, CONST|TMPVAR|CV, NUM) } else { SAVE_OPLINE(); if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(var) == IS_UNDEF)) { - GET_OP2_UNDEF_CV(var, BP_VAR_R); + ZVAL_UNDEFINED_OP2(); } rope[0] = zval_get_string_func(var); FREE_OP2(); @@ -2883,7 +3364,7 @@ ZEND_VM_HANDLER(55, ZEND_ROPE_ADD, TMP, CONST|TMPVAR|CV, NUM) } else { SAVE_OPLINE(); if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(var) == IS_UNDEF)) { - GET_OP2_UNDEF_CV(var, BP_VAR_R); + ZVAL_UNDEFINED_OP2(); } rope[opline->extended_value] = zval_get_string_func(var); FREE_OP2(); @@ -2921,7 +3402,7 @@ ZEND_VM_HANDLER(56, ZEND_ROPE_END, TMP, CONST|TMPVAR|CV, NUM) } else { SAVE_OPLINE(); if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(var) == IS_UNDEF)) { - GET_OP2_UNDEF_CV(var, BP_VAR_R); + ZVAL_UNDEFINED_OP2(); } rope[opline->extended_value] = zval_get_string_func(var); FREE_OP2(); @@ -2965,7 +3446,7 @@ ZEND_VM_HANDLER(109, ZEND_FETCH_CLASS, UNUSED|CLASS_FETCH, CONST|TMPVAR|UNUSED|C if (UNEXPECTED(ce == NULL)) { class_name = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); - ce = zend_fetch_class_by_name(Z_STR_P(class_name), class_name + 1, opline->op1.num); + ce = zend_fetch_class_by_name(Z_STR_P(class_name), Z_STR_P(class_name + 1), opline->op1.num); CACHE_PTR(opline->extended_value, ce); } Z_CE_P(EX_VAR(opline->result.var)) = ce; @@ -2981,7 +3462,7 @@ ZEND_VM_C_LABEL(try_class_name): ZEND_VM_C_GOTO(try_class_name); } else { if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(class_name) == IS_UNDEF)) { - GET_OP2_UNDEF_CV(class_name, BP_VAR_R); + ZVAL_UNDEFINED_OP2(); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -3027,7 +3508,7 @@ ZEND_VM_HOT_OBJ_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMPVAR|UNUSED|THIS|CV, break; } } else if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { - GET_OP2_UNDEF_CV(function_name, BP_VAR_R); + ZVAL_UNDEFINED_OP2(); if (UNEXPECTED(EG(exception) != NULL)) { FREE_OP1(); HANDLE_EXCEPTION(); @@ -3050,7 +3531,7 @@ ZEND_VM_HOT_OBJ_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMPVAR|UNUSED|THIS|CV, } } if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { - object = GET_OP1_UNDEF_CV(object, BP_VAR_R); + object = ZVAL_UNDEFINED_OP1(); if (UNEXPECTED(EG(exception) != NULL)) { if (OP2_TYPE != IS_CONST) { FREE_OP2(); @@ -3078,13 +3559,6 @@ ZEND_VM_HOT_OBJ_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMPVAR|UNUSED|THIS|CV, } else { zend_object *orig_obj = obj; - if (UNEXPECTED(obj->handlers->get_method == NULL)) { - zend_throw_error(NULL, "Object does not support method calls"); - FREE_OP2(); - FREE_OP1(); - HANDLE_EXCEPTION(); - } - if (OP2_TYPE == IS_CONST) { function_name = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); } @@ -3109,7 +3583,7 @@ ZEND_VM_HOT_OBJ_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMPVAR|UNUSED|THIS|CV, /* Reset "object" to trigger reference counting */ object = NULL; } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -3118,27 +3592,29 @@ ZEND_VM_HOT_OBJ_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMPVAR|UNUSED|THIS|CV, FREE_OP2(); } - call_info = ZEND_CALL_NESTED_FUNCTION; + call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_HAS_THIS; if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0)) { - obj = NULL; FREE_OP1(); if ((OP1_TYPE & (IS_VAR|IS_TMP_VAR)) && UNEXPECTED(EG(exception))) { HANDLE_EXCEPTION(); } + /* call static method */ + obj = (zend_object*)called_scope; + call_info = ZEND_CALL_NESTED_FUNCTION; } else if (OP1_TYPE & (IS_VAR|IS_TMP_VAR|IS_CV)) { - /* CV may be changed indirectly (e.g. when it's a reference) */ - call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_RELEASE_THIS; if (OP1_TYPE == IS_CV) { GC_ADDREF(obj); /* For $this pointer */ } else if (free_op1 != object) { GC_ADDREF(obj); /* For $this pointer */ FREE_OP1(); } + /* CV may be changed indirectly (e.g. when it's a reference) */ + call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS; } call = zend_vm_stack_push_call_frame(call_info, - fbc, opline->extended_value, called_scope, obj); + fbc, opline->extended_value, obj); call->prev_execute_data = EX(call); EX(call) = call; @@ -3150,7 +3626,7 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR, USE_OPLINE zval *function_name; zend_class_entry *ce; - zend_object *object; + uint32_t call_info; zend_function *fbc; zend_execute_data *call; @@ -3160,7 +3636,7 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR, /* no function found. try a static method in class */ ce = CACHED_PTR(opline->result.num); if (UNEXPECTED(ce == NULL)) { - ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), RT_CONSTANT(opline, opline->op1) + 1, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); + ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), Z_STR_P(RT_CONSTANT(opline, opline->op1) + 1), ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); if (UNEXPECTED(ce == NULL)) { ZEND_ASSERT(EG(exception)); FREE_UNFETCHED_OP2(); @@ -3202,7 +3678,7 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR, break; } } else if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { - GET_OP2_UNDEF_CV(function_name, BP_VAR_R); + ZVAL_UNDEFINED_OP2(); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -3231,7 +3707,7 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR, EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) { CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } if (OP2_TYPE != IS_CONST) { @@ -3247,38 +3723,39 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR, HANDLE_EXCEPTION(); } fbc = ce->constructor; - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } - object = NULL; if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { if (Z_TYPE(EX(This)) == IS_OBJECT && instanceof_function(Z_OBJCE(EX(This)), ce)) { - object = Z_OBJ(EX(This)); - ce = object->ce; + ce = (zend_class_entry*)Z_OBJ(EX(This)); + call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_HAS_THIS; } else { zend_non_static_method_call(fbc); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } + ZEND_VM_C_GOTO(check_parent_and_self); } - } - - if (OP1_TYPE == IS_UNUSED) { + } else { +ZEND_VM_C_LABEL(check_parent_and_self): /* previous opcode is ZEND_FETCH_CLASS */ - if ((opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_PARENT || - (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) { + if (OP1_TYPE == IS_UNUSED + && ((opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_PARENT || + (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF)) { if (Z_TYPE(EX(This)) == IS_OBJECT) { ce = Z_OBJCE(EX(This)); } else { ce = Z_CE(EX(This)); } } + call_info = ZEND_CALL_NESTED_FUNCTION; } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, - fbc, opline->extended_value, ce, object); + call = zend_vm_stack_push_call_frame(call_info, + fbc, opline->extended_value, ce); call->prev_execute_data = EX(call); EX(call) = call; @@ -3297,16 +3774,16 @@ ZEND_VM_HOT_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT) function_name = (zval*)RT_CONSTANT(opline, opline->op2); func = zend_hash_find_ex(EG(function_table), Z_STR_P(function_name+1), 1); if (UNEXPECTED(func == NULL)) { - ZEND_VM_DISPATCH_TO_HELPER(zend_undefined_function_helper, function_name, function_name); + ZEND_VM_DISPATCH_TO_HELPER(zend_undefined_function_helper); } fbc = Z_FUNC_P(func); - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { - fbc = init_func_run_time_cache_ex(func); + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { + init_func_run_time_cache(&fbc->op_array); } CACHE_PTR(opline->result.num, fbc); } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, - fbc, opline->extended_value, NULL, NULL); + call = _zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + fbc, opline->extended_value, NULL); call->prev_execute_data = EX(call); EX(call) = call; @@ -3335,7 +3812,7 @@ ZEND_VM_C_LABEL(try_function_name): ZEND_VM_C_GOTO(try_function_name); } else { if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { - GET_OP2_UNDEF_CV(function_name, BP_VAR_R); + ZVAL_UNDEFINED_OP2(); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -3376,8 +3853,7 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM) zend_fcall_info_cache fcc; char *error = NULL; zend_function *func; - zend_class_entry *called_scope; - zend_object *object; + void *object_or_called_scope; zend_execute_data *call; uint32_t call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC; @@ -3385,8 +3861,6 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM) function_name = GET_OP2_ZVAL_PTR(BP_VAR_R); if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) { func = fcc.function_handler; - called_scope = fcc.called_scope; - object = fcc.object; if (error) { efree(error); /* This is the only soft error is_callable() can generate */ @@ -3396,6 +3870,7 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM) HANDLE_EXCEPTION(); } } + object_or_called_scope = fcc.called_scope; if (func->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ GC_ADDREF(ZEND_CLOSURE_OBJECT(func)); @@ -3403,23 +3878,27 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM) if (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) { call_info |= ZEND_CALL_FAKE_CLOSURE; } - } else if (object) { - call_info |= ZEND_CALL_RELEASE_THIS; - GC_ADDREF(object); /* For $this pointer */ + if (fcc.object) { + object_or_called_scope = fcc.object; + call_info |= ZEND_CALL_HAS_THIS; + } + } else if (fcc.object) { + GC_ADDREF(fcc.object); /* For $this pointer */ + object_or_called_scope = fcc.object; + call_info |= ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS; } FREE_OP2(); if ((OP2_TYPE & (IS_TMP_VAR|IS_VAR)) && UNEXPECTED(EG(exception))) { if (call_info & ZEND_CALL_CLOSURE) { zend_object_release(ZEND_CLOSURE_OBJECT(func)); - } - if (call_info & ZEND_CALL_RELEASE_THIS) { - zend_object_release(object); + } else if (call_info & ZEND_CALL_RELEASE_THIS) { + zend_object_release(fcc.object); } HANDLE_EXCEPTION(); } - if (EXPECTED(func->type == ZEND_USER_FUNCTION) && UNEXPECTED(!func->op_array.run_time_cache)) { + if (EXPECTED(func->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&func->op_array))) { init_func_run_time_cache(&func->op_array); } } else { @@ -3430,12 +3909,11 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM) HANDLE_EXCEPTION(); } func = (zend_function*)&zend_pass_function; - called_scope = NULL; - object = NULL; + object_or_called_scope = NULL; } call = zend_vm_stack_push_call_frame(call_info, - func, opline->extended_value, called_scope, object); + func, opline->extended_value, object_or_called_scope); call->prev_execute_data = EX(call); EX(call) = call; @@ -3457,18 +3935,18 @@ ZEND_VM_HOT_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT) if (func == NULL) { func = zend_hash_find_ex(EG(function_table), Z_STR_P(func_name + 2), 1); if (UNEXPECTED(func == NULL)) { - ZEND_VM_DISPATCH_TO_HELPER(zend_undefined_function_helper, function_name, func_name); + ZEND_VM_DISPATCH_TO_HELPER(zend_undefined_function_helper); } } fbc = Z_FUNC_P(func); - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { - fbc = init_func_run_time_cache_ex(func); + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { + init_func_run_time_cache(&fbc->op_array); } CACHE_PTR(opline->result.num, fbc); } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, - fbc, opline->extended_value, NULL, NULL); + call = _zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + fbc, opline->extended_value, NULL); call->prev_execute_data = EX(call); EX(call) = call; @@ -3478,7 +3956,6 @@ ZEND_VM_HOT_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT) ZEND_VM_HOT_HANDLER(61, ZEND_INIT_FCALL, NUM, CONST, NUM|CACHE_SLOT) { USE_OPLINE - zend_free_op free_op2; zval *fname; zval *func; zend_function *fbc; @@ -3486,21 +3963,21 @@ ZEND_VM_HOT_HANDLER(61, ZEND_INIT_FCALL, NUM, CONST, NUM|CACHE_SLOT) fbc = CACHED_PTR(opline->result.num); if (UNEXPECTED(fbc == NULL)) { - fname = GET_OP2_ZVAL_PTR(BP_VAR_R); + fname = (zval*)RT_CONSTANT(opline, opline->op2); func = zend_hash_find_ex(EG(function_table), Z_STR_P(fname), 1); if (UNEXPECTED(func == NULL)) { - ZEND_VM_DISPATCH_TO_HELPER(zend_undefined_function_helper, function_name, fname); + ZEND_VM_DISPATCH_TO_HELPER(zend_undefined_function_helper); } fbc = Z_FUNC_P(func); - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { - fbc = init_func_run_time_cache_ex(func); + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { + init_func_run_time_cache(&fbc->op_array); } CACHE_PTR(opline->result.num, fbc); } - call = zend_vm_stack_push_call_frame_ex( + call = _zend_vm_stack_push_call_frame_ex( opline->op1.num, ZEND_CALL_NESTED_FUNCTION, - fbc, opline->extended_value, NULL, NULL); + fbc, opline->extended_value, NULL); call->prev_execute_data = EX(call); EX(call) = call; @@ -3540,7 +4017,7 @@ ZEND_VM_HOT_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL)) zend_vm_stack_free_call_frame(call); if (!RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(ret); + i_zval_ptr_dtor(ret); } if (UNEXPECTED(EG(exception) != NULL)) { @@ -3565,13 +4042,12 @@ ZEND_VM_HOT_HANDLER(130, ZEND_DO_UCALL, ANY, ANY, SPEC(RETVAL)) ret = NULL; if (RETURN_VALUE_USED(opline)) { ret = EX_VAR(opline->result.var); - ZVAL_NULL(ret); } call->prev_execute_data = execute_data; execute_data = call; i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); - LOAD_OPLINE(); + LOAD_OPLINE_EX(); ZEND_VM_ENTER_EX(); } @@ -3590,13 +4066,12 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL)) ret = NULL; if (RETURN_VALUE_USED(opline)) { ret = EX_VAR(opline->result.var); - ZVAL_NULL(ret); } call->prev_execute_data = execute_data; execute_data = call; i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); - LOAD_OPLINE(); + LOAD_OPLINE_EX(); ZEND_VM_ENTER_EX(); } else { @@ -3606,8 +4081,12 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL)) if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { zend_deprecated_function(fbc); if (UNEXPECTED(EG(exception) != NULL)) { - UNDEF_RESULT(); - HANDLE_EXCEPTION(); + UNDEF_RESULT(); + if (!RETURN_VALUE_USED(opline)) { + ret = &retval; + ZVAL_UNDEF(ret); + } + ZEND_VM_C_GOTO(fcall_by_name_end); } } @@ -3616,10 +4095,12 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL)) if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) && UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) { - zend_vm_stack_free_call_frame(call); - zend_rethrow_exception(execute_data); - UNDEF_RESULT(); - HANDLE_EXCEPTION(); + UNDEF_RESULT(); + if (!RETURN_VALUE_USED(opline)) { + ret = &retval; + ZVAL_UNDEF(ret); + } + ZEND_VM_C_GOTO(fcall_by_name_end); } ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval; @@ -3637,11 +4118,13 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL)) #endif EG(current_execute_data) = execute_data; + +ZEND_VM_C_LABEL(fcall_by_name_end): zend_vm_stack_free_args(call); zend_vm_stack_free_call_frame(call); if (!RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(ret); + i_zval_ptr_dtor(ret); } } @@ -3658,20 +4141,25 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL)) USE_OPLINE zend_execute_data *call = EX(call); zend_function *fbc = call->func; - zend_object *object; zval *ret; + zval retval; SAVE_OPLINE(); EX(call) = call->prev_execute_data; if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { - ZEND_VM_DISPATCH_TO_HELPER(zend_abstract_method_helper, fbc, fbc); - } - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { + zend_abstract_method(fbc); +ZEND_VM_C_LABEL(fcall_except): + UNDEF_RESULT(); + if (!RETURN_VALUE_USED(opline)) { + ret = &retval; + ZVAL_UNDEF(ret); + } + ZEND_VM_C_GOTO(fcall_end); + } else { zend_deprecated_function(fbc); if (UNEXPECTED(EG(exception) != NULL)) { - UNDEF_RESULT(); - HANDLE_EXCEPTION(); + ZEND_VM_C_GOTO(fcall_except); } } } @@ -3680,7 +4168,6 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL)) ret = NULL; if (RETURN_VALUE_USED(opline)) { ret = EX_VAR(opline->result.var); - ZVAL_NULL(ret); } call->prev_execute_data = execute_data; @@ -3688,24 +4175,22 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL)) i_init_func_execute_data(&fbc->op_array, ret, 1 EXECUTE_DATA_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { - LOAD_OPLINE(); + LOAD_OPLINE_EX(); ZEND_VM_ENTER_EX(); } else { + SAVE_OPLINE_EX(); execute_data = EX(prev_execute_data); LOAD_OPLINE(); ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); zend_execute_ex(call); } } else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) { - zval retval; - call->prev_execute_data = execute_data; EG(current_execute_data) = call; if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) && UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) { - UNDEF_RESULT(); - ZEND_VM_C_GOTO(fcall_end); + ZEND_VM_C_GOTO(fcall_except); } ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval; @@ -3728,15 +4213,13 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL)) #endif EG(current_execute_data) = execute_data; - zend_vm_stack_free_args(call); +ZEND_VM_C_LABEL(fcall_end): + zend_vm_stack_free_args(call); if (!RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(ret); + i_zval_ptr_dtor(ret); } - } else { /* ZEND_OVERLOADED_FUNCTION */ - zval retval; - ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval; call->prev_execute_data = execute_data; @@ -3751,18 +4234,8 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL)) } } -ZEND_VM_C_LABEL(fcall_end): if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) { - object = Z_OBJ(call->This); -#if 0 - if (UNEXPECTED(EG(exception) != NULL) && (opline->op1.num & ZEND_CALL_CTOR)) { -#else - if (UNEXPECTED(EG(exception) != NULL) && (ZEND_CALL_INFO(call) & ZEND_CALL_CTOR)) { -#endif - GC_DELREF(object); - zend_object_store_ctor_failed(object); - } - OBJ_RELEASE(object); + OBJ_RELEASE(Z_OBJ(call->This)); } zend_vm_stack_free_call_frame(call); @@ -3784,7 +4257,7 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV zend_verify_missing_return_type(EX(func), CACHE_ADDR(opline->op2.num)); } else { /* prevents "undefined variable opline" errors */ -#if !defined(ZEND_VM_SPEC) || (OP1_TYPE != IS_UNUSED) +#if !ZEND_VM_SPEC || (OP1_TYPE != IS_UNUSED) zval *retval_ref, *retval_ptr; zend_free_op free_op1; zend_arg_info *ret_info = EX(func)->common.arg_info - 1; @@ -3825,7 +4298,7 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HOT_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) +ZEND_VM_INLINE_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) { USE_OPLINE zval *retval_ptr; @@ -3836,7 +4309,7 @@ ZEND_VM_HOT_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) return_value = EX(return_value); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(retval_ptr) == IS_UNDEF)) { SAVE_OPLINE(); - retval_ptr = GET_OP1_UNDEF_CV(retval_ptr, BP_VAR_R); + retval_ptr = ZVAL_UNDEFINED_OP1(); if (return_value) { ZVAL_NULL(return_value); } @@ -3856,25 +4329,29 @@ ZEND_VM_HOT_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) } } } else if (OP1_TYPE == IS_CV) { - if (Z_OPT_REFCOUNTED_P(retval_ptr)) { - if (EXPECTED(!Z_OPT_ISREF_P(retval_ptr))) { - ZVAL_COPY_VALUE(return_value, retval_ptr); - if (EXPECTED(!(EX_CALL_INFO() & ZEND_CALL_CODE))) { - zend_refcounted *ref = Z_COUNTED_P(retval_ptr); - if (GC_MAY_LEAK(ref)) { - gc_possible_root(ref); + do { + if (Z_OPT_REFCOUNTED_P(retval_ptr)) { + if (EXPECTED(!Z_OPT_ISREF_P(retval_ptr))) { + if (EXPECTED(!(EX_CALL_INFO() & ZEND_CALL_CODE))) { + zend_refcounted *ref = Z_COUNTED_P(retval_ptr); + ZVAL_COPY_VALUE(return_value, retval_ptr); + if (GC_MAY_LEAK(ref)) { + gc_possible_root(ref); + } + ZVAL_NULL(retval_ptr); + break; + } else { + Z_ADDREF_P(retval_ptr); } - ZVAL_NULL(retval_ptr); } else { - Z_ADDREF_P(return_value); + retval_ptr = Z_REFVAL_P(retval_ptr); + if (Z_OPT_REFCOUNTED_P(retval_ptr)) { + Z_ADDREF_P(retval_ptr); + } } - } else { - retval_ptr = Z_REFVAL_P(retval_ptr); - ZVAL_COPY(return_value, retval_ptr); } - } else { ZVAL_COPY_VALUE(return_value, retval_ptr); - } + } while (0); } else /* if (OP1_TYPE == IS_VAR) */ { if (UNEXPECTED(Z_ISREF_P(retval_ptr))) { zend_refcounted *ref = Z_COUNTED_P(retval_ptr); @@ -3928,8 +4405,8 @@ ZEND_VM_COLD_CONST_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY, SRC) retval_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); if (OP1_TYPE == IS_VAR) { - if (retval_ptr == &EG(uninitialized_zval) || - (opline->extended_value == ZEND_RETURNS_FUNCTION && !Z_ISREF_P(retval_ptr))) { + ZEND_ASSERT(retval_ptr != &EG(uninitialized_zval)); + if (opline->extended_value == ZEND_RETURNS_FUNCTION && !Z_ISREF_P(retval_ptr)) { zend_error(E_NOTICE, "Only variable references should be returned by reference"); if (EX(return_value)) { ZVAL_NEW_REF(EX(return_value), retval_ptr); @@ -3955,7 +4432,7 @@ ZEND_VM_COLD_CONST_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY, SRC) ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); } -ZEND_VM_HANDLER(41, ZEND_GENERATOR_CREATE, ANY, ANY) +ZEND_VM_HANDLER(139, ZEND_GENERATOR_CREATE, ANY, ANY) { zval *return_value = EX(return_value); @@ -4000,7 +4477,7 @@ ZEND_VM_HANDLER(41, ZEND_GENERATOR_CREATE, ANY, ANY) gen_execute_data->return_value = (zval*)generator; call_info = Z_TYPE_INFO(EX(This)); if ((call_info & Z_TYPE_MASK) == IS_OBJECT - && (!(call_info & ((ZEND_CALL_CLOSURE|ZEND_CALL_RELEASE_THIS) << ZEND_CALL_INFO_SHIFT)) + && (!(call_info & (ZEND_CALL_CLOSURE|ZEND_CALL_RELEASE_THIS)) /* Bug #72523 */ || UNEXPECTED(zend_execute_ex != execute_ex))) { ZEND_ADD_CALL_FLAG_EX(call_info, ZEND_CALL_RELEASE_THIS); @@ -4093,7 +4570,7 @@ ZEND_VM_COLD_CONST_HANDLER(108, ZEND_THROW, CONST|TMP|VAR|CV, ANY) } } if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(value, BP_VAR_R); + ZVAL_UNDEFINED_OP1(); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -4130,7 +4607,7 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, JMP_ADDR, LAST_CATCH|CACHE_SLOT) } catch_ce = CACHED_PTR(opline->extended_value & ~ZEND_LAST_CATCH); if (UNEXPECTED(catch_ce == NULL)) { - catch_ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), RT_CONSTANT(opline, opline->op1) + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD); + catch_ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), Z_STR_P(RT_CONSTANT(opline, opline->op1) + 1), ZEND_FETCH_CLASS_NO_AUTOLOAD); CACHE_PTR(opline->extended_value & ~ZEND_LAST_CATCH, catch_ce); } @@ -4154,17 +4631,15 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, JMP_ADDR, LAST_CATCH|CACHE_SLOT) exception = EG(exception); ex = EX_VAR(opline->result.var); - if (UNEXPECTED(Z_ISREF_P(ex))) { - ex = Z_REFVAL_P(ex); - } - zval_ptr_dtor(ex); - ZVAL_OBJ(ex, EG(exception)); - if (UNEXPECTED(EG(exception) != exception)) { - GC_ADDREF(EG(exception)); - HANDLE_EXCEPTION(); - } else { + { + /* Always perform a strict assignment. There is a reasonable expectation that if you + * write "catch (Exception $e)" then $e will actually be instanceof Exception. As such, + * we should not permit coercion to string here. */ + zval tmp; + ZVAL_OBJ(&tmp, exception); EG(exception) = NULL; - ZEND_VM_NEXT_OPCODE(); + zend_assign_to_variable(ex, &tmp, IS_TMP_VAR, /* strict */ 1); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } } @@ -4234,7 +4709,7 @@ ZEND_VM_HOT_HANDLER(117, ZEND_SEND_VAR, VAR|CV, NUM) varptr = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(varptr) == IS_UNDEF)) { SAVE_OPLINE(); - GET_OP1_UNDEF_CV(varptr, BP_VAR_R); + ZVAL_UNDEFINED_OP1(); arg = ZEND_CALL_VAR(EX(call), opline->result.var); ZVAL_NULL(arg); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -4278,6 +4753,7 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR, NUM) } SAVE_OPLINE(); + ZVAL_NEW_REF(arg, arg); zend_error(E_NOTICE, "Only variables should be passed by reference"); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -4318,6 +4794,7 @@ ZEND_VM_HOT_SEND_HANDLER(50, ZEND_SEND_VAR_NO_REF_EX, VAR, NUM, SPEC(QUICK_ARG)) } SAVE_OPLINE(); + ZVAL_NEW_REF(arg, arg); zend_error(E_NOTICE, "Only variables should be passed by reference"); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -4368,7 +4845,7 @@ ZEND_VM_C_LABEL(send_var_by_ref): varptr = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(varptr) == IS_UNDEF)) { SAVE_OPLINE(); - GET_OP1_UNDEF_CV(varptr, BP_VAR_R); + ZVAL_UNDEFINED_OP1(); arg = ZEND_CALL_VAR(EX(call), opline->result.var); ZVAL_NULL(arg); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -4590,7 +5067,7 @@ ZEND_VM_C_LABEL(send_again): ZEND_VM_C_GOTO(send_again); } else { if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(args) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(args, BP_VAR_R); + ZVAL_UNDEFINED_OP1(); } zend_error(E_WARNING, "Only arrays and Traversables can be unpacked"); } @@ -4618,13 +5095,12 @@ ZEND_VM_HANDLER(119, ZEND_SEND_ARRAY, ANY, ANY, NUM) zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array, %s given", zend_get_type_by_const(Z_TYPE_P(args))); if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(call)->func)); - } - if (Z_TYPE(EX(call)->This) == IS_OBJECT) { + } else if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_RELEASE_THIS) { OBJ_RELEASE(Z_OBJ(EX(call)->This)); } EX(call)->func = (zend_function*)&zend_pass_function; Z_OBJ(EX(call)->This) = NULL; - ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS); + ZEND_CALL_INFO(EX(call)) &= ~(ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS); FREE_UNFETCHED_OP2(); } else { uint32_t arg_num; @@ -4636,7 +5112,7 @@ ZEND_VM_C_LABEL(send_array): ht = Z_ARRVAL_P(args); if (OP2_TYPE != IS_UNUSED) { zend_free_op free_op2; - zval *op2 = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R); + zval *op2 = GET_OP2_ZVAL_PTR(BP_VAR_R); uint32_t skip = opline->extended_value; uint32_t count = zend_hash_num_elements(ht); zend_long len = zval_get_long(op2); @@ -4652,6 +5128,7 @@ ZEND_VM_C_LABEL(send_array): arg_num = 1; param = ZEND_CALL_ARG(EX(call), 1); ZEND_HASH_FOREACH_VAL(ht, arg) { + zend_bool must_wrap = 0; if (skip > 0) { skip--; continue; @@ -4663,6 +5140,7 @@ ZEND_VM_C_LABEL(send_array): /* By-value send is not allowed -- emit a warning, * but still perform the call. */ zend_param_must_be_ref(EX(call)->func, arg_num); + must_wrap = 1; } } } else { @@ -4672,7 +5150,12 @@ ZEND_VM_C_LABEL(send_array): arg = Z_REFVAL_P(arg); } } - ZVAL_COPY(param, arg); + if (EXPECTED(!must_wrap)) { + ZVAL_COPY(param, arg); + } else { + Z_TRY_ADDREF_P(arg); + ZVAL_NEW_REF(param, arg); + } ZEND_CALL_NUM_ARGS(EX(call))++; arg_num++; param++; @@ -4684,12 +5167,14 @@ ZEND_VM_C_LABEL(send_array): arg_num = 1; param = ZEND_CALL_ARG(EX(call), 1); ZEND_HASH_FOREACH_VAL(ht, arg) { + zend_bool must_wrap = 0; if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { if (UNEXPECTED(!Z_ISREF_P(arg))) { if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { /* By-value send is not allowed -- emit a warning, * but still perform the call. */ zend_param_must_be_ref(EX(call)->func, arg_num); + must_wrap = 1; } } } else { @@ -4699,7 +5184,12 @@ ZEND_VM_C_LABEL(send_array): arg = Z_REFVAL_P(arg); } } - ZVAL_COPY(param, arg); + if (EXPECTED(!must_wrap)) { + ZVAL_COPY(param, arg); + } else { + Z_TRY_ADDREF_P(arg); + ZVAL_NEW_REF(param, arg); + } ZEND_CALL_NUM_ARGS(EX(call))++; arg_num++; param++; @@ -4717,15 +5207,14 @@ ZEND_VM_HANDLER(120, ZEND_SEND_USER, CONST|TMP|VAR|CV, NUM) zend_free_op free_op1; SAVE_OPLINE(); - arg = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); - param = ZEND_CALL_VAR(EX(call), opline->result.var); if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) { zend_param_must_be_ref(EX(call)->func, opline->op2.num); } + arg = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); + param = ZEND_CALL_VAR(EX(call), opline->result.var); ZVAL_COPY(param, arg); - FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -4739,11 +5228,11 @@ ZEND_VM_HOT_HANDLER(63, ZEND_RECV, NUM, UNUSED|CACHE_SLOT) SAVE_OPLINE(); zend_missing_arg_error(execute_data); HANDLE_EXCEPTION(); - } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { + } else { zval *param = EX_VAR(opline->result.var); SAVE_OPLINE(); - if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)) || EG(exception))) { + if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)))) { HANDLE_EXCEPTION(); } } @@ -4782,17 +5271,19 @@ ZEND_VM_HOT_HANDLER(64, ZEND_RECV_INIT, NUM, CONST, CACHE_SLOT) ZVAL_COPY_VALUE(cache_val, param); } } + ZEND_VM_C_GOTO(recv_init_check_type); } else { ZVAL_COPY(param, default_value); } - } - - if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - zval *default_value = RT_CONSTANT(opline, opline->op2); + } else { +ZEND_VM_C_LABEL(recv_init_check_type): + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { + zval *default_value = RT_CONSTANT(opline, opline->op2); - SAVE_OPLINE(); - if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, default_value, CACHE_ADDR(opline->extended_value)) || EG(exception))) { - HANDLE_EXCEPTION(); + SAVE_OPLINE(); + if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, default_value, CACHE_ADDR(opline->extended_value)))) { + HANDLE_EXCEPTION(); + } } } @@ -4821,7 +5312,7 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, NUM, UNUSED|CACHE_SLOT) if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_FREE_EXTRA_ARGS); do { - zend_verify_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)); + zend_verify_variadic_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)); if (Z_OPT_REFCOUNTED_P(param)) Z_ADDREF_P(param); ZEND_HASH_FILL_ADD(param); param++; @@ -4856,7 +5347,7 @@ ZEND_VM_COLD_CONST_HANDLER(52, ZEND_BOOL, CONST|TMPVAR|CV, ANY) ZVAL_FALSE(EX_VAR(opline->result.var)); if (OP1_TYPE == IS_CV && UNEXPECTED(orig_val_type == IS_UNDEF)) { SAVE_OPLINE(); - GET_OP1_UNDEF_CV(val, BP_VAR_R); + ZVAL_UNDEFINED_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } } else { @@ -4868,60 +5359,89 @@ ZEND_VM_COLD_CONST_HANDLER(52, ZEND_BOOL, CONST|TMPVAR|CV, ANY) ZEND_VM_NEXT_OPCODE(); } +ZEND_VM_HELPER(zend_case_helper, ANY, ANY, zval *op_1, zval *op_2) +{ + USE_OPLINE + + SAVE_OPLINE(); + if (UNEXPECTED(Z_TYPE_INFO_P(op_1) == IS_UNDEF)) { + op_1 = ZVAL_UNDEFINED_OP1(); + } + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } + compare_function(EX_VAR(opline->result.var), op_1, op_2); + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_2); + } + if (UNEXPECTED(EG(exception))) { + HANDLE_EXCEPTION(); + } + if (Z_LVAL_P(EX_VAR(opline->result.var)) == 0) { + ZEND_VM_SMART_BRANCH_TRUE(); + ZVAL_TRUE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); + } else { + ZEND_VM_SMART_BRANCH_FALSE(); + ZVAL_FALSE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); + } +} + ZEND_VM_HANDLER(48, ZEND_CASE, TMPVAR, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; - zval *op1, *op2, *result; + zval *op1, *op2; + double d1, d2; op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); - do { - int result; - - if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - result = (Z_LVAL_P(op1) == Z_LVAL_P(op2)); - } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - result = ((double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + if (EXPECTED(Z_LVAL_P(op1) == Z_LVAL_P(op2))) { +ZEND_VM_C_LABEL(case_true): + ZEND_VM_SMART_BRANCH_TRUE(); + ZVAL_TRUE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); } else { - break; +ZEND_VM_C_LABEL(case_false): + ZEND_VM_SMART_BRANCH_FALSE(); + ZVAL_FALSE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); } - } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - result = (Z_DVAL_P(op1) == Z_DVAL_P(op2)); - } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - result = (Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + d1 = (double)Z_LVAL_P(op1); + d2 = Z_DVAL_P(op2); + ZEND_VM_C_GOTO(case_double); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + d1 = Z_DVAL_P(op1); + d2 = Z_DVAL_P(op2); +ZEND_VM_C_LABEL(case_double): + if (d1 == d2) { + ZEND_VM_C_GOTO(case_true); } else { - break; + ZEND_VM_C_GOTO(case_false); } - } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { - result = zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2)); - FREE_OP2(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + d1 = Z_DVAL_P(op1); + d2 = (double)Z_LVAL_P(op2); + ZEND_VM_C_GOTO(case_double); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + int result = zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2)); + FREE_OP2(); + if (result) { + ZEND_VM_C_GOTO(case_true); } else { - break; + ZEND_VM_C_GOTO(case_false); } - } else { - break; } - ZEND_VM_SMART_BRANCH(result, 0); - ZVAL_BOOL(EX_VAR(opline->result.var), result); - ZEND_VM_NEXT_OPCODE(); - } while (0); - - SAVE_OPLINE(); - if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { - op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); - } - if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { - op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); } - result = EX_VAR(opline->result.var); - compare_function(result, op1, op2); - ZVAL_BOOL(result, Z_LVAL_P(result) == 0); - FREE_OP2(); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_DISPATCH_TO_HELPER(zend_case_helper, op_1, op1, op_2, op2); } ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CLASS_FETCH|CONST|VAR, UNUSED|CACHE_SLOT, NUM) @@ -4936,7 +5456,7 @@ ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CLASS_FETCH|CONST|VAR, UNUSED|CACHE_SLOT, N if (OP1_TYPE == IS_CONST) { ce = CACHED_PTR(opline->op2.num); if (UNEXPECTED(ce == NULL)) { - ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), RT_CONSTANT(opline, opline->op1) + 1, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); + ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), Z_STR_P(RT_CONSTANT(opline, opline->op1) + 1), ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); if (UNEXPECTED(ce == NULL)) { ZEND_ASSERT(EG(exception)); ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -4976,17 +5496,16 @@ ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CLASS_FETCH|CONST|VAR, UNUSED|CACHE_SLOT, N /* Perform a dummy function call */ call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, - opline->extended_value, NULL, NULL); + opline->extended_value, NULL); } else { - if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!constructor->op_array.run_time_cache)) { + if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); } /* We are not handling overloaded classes right now */ call = zend_vm_stack_push_call_frame( - ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR, + ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS, constructor, opline->extended_value, - ce, Z_OBJ_P(result)); Z_ADDREF_P(result); } @@ -5023,7 +5542,7 @@ ZEND_VM_COLD_CONST_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|THIS|CV, ANY) } ZVAL_UNDEF(EX_VAR(opline->result.var)); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(obj) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(obj, BP_VAR_R); + ZVAL_UNDEFINED_OP1(); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -5044,23 +5563,12 @@ ZEND_VM_COLD_CONST_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|THIS|CV, ANY) HANDLE_EXCEPTION(); } - if (clone) { - if (clone->op_array.fn_flags & ZEND_ACC_PRIVATE) { - /* Ensure that if we're calling a private function, we're allowed to do so. - */ - scope = EX(func)->op_array.scope; - if (!zend_check_private(clone, scope, clone->common.function_name)) { - zend_throw_error(NULL, "Call to private %s::__clone() from context '%s'", ZSTR_VAL(clone->common.scope->name), scope ? ZSTR_VAL(scope->name) : ""); - FREE_OP1(); - ZVAL_UNDEF(EX_VAR(opline->result.var)); - HANDLE_EXCEPTION(); - } - } else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) { - /* Ensure that if we're calling a protected function, we're allowed to do so. - */ - scope = EX(func)->op_array.scope; - if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), scope))) { - zend_throw_error(NULL, "Call to protected %s::__clone() from context '%s'", ZSTR_VAL(clone->common.scope->name), scope ? ZSTR_VAL(scope->name) : ""); + if (clone && !(clone->common.fn_flags & ZEND_ACC_PUBLIC)) { + scope = EX(func)->op_array.scope; + if (clone->common.scope != scope) { + if (UNEXPECTED(clone->common.fn_flags & ZEND_ACC_PRIVATE) + || UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), scope))) { + zend_wrong_clone_call(clone, scope); FREE_OP1(); ZVAL_UNDEF(EX_VAR(opline->result.var)); HANDLE_EXCEPTION(); @@ -5107,7 +5615,7 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO } else if (EXPECTED(CACHED_PTR(opline->extended_value))) { ce = CACHED_PTR(opline->extended_value); } else { - ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), RT_CONSTANT(opline, opline->op1) + 1, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); + ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), Z_STR_P(RT_CONSTANT(opline, opline->op1) + 1), ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); if (UNEXPECTED(ce == NULL)) { ZEND_ASSERT(EG(exception)); ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -5237,8 +5745,12 @@ ZEND_VM_C_LABEL(num_index): } else if (Z_TYPE_P(offset) == IS_TRUE) { hval = 1; ZEND_VM_C_GOTO(num_index); + } else if (Z_TYPE_P(offset) == IS_RESOURCE) { + zend_use_resource_as_offset(offset); + hval = Z_RES_HANDLE_P(offset); + ZEND_VM_C_GOTO(num_index); } else if (OP2_TYPE == IS_CV && Z_TYPE_P(offset) == IS_UNDEF) { - GET_OP2_UNDEF_CV(offset, BP_VAR_R); + ZVAL_UNDEFINED_OP2(); str = ZSTR_EMPTY_ALLOC(); ZEND_VM_C_GOTO(str_index); } else { @@ -5255,7 +5767,114 @@ ZEND_VM_C_LABEL(num_index): ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(71, ZEND_INIT_ARRAY, CONST|TMP|VAR|CV, CONST|TMPVAR|UNUSED|NEXT|CV, ARRAY_INIT|REF) +ZEND_VM_HANDLER(147, ZEND_ADD_ARRAY_UNPACK, ANY, ANY) +{ + USE_OPLINE + zend_free_op free_op1; + zval *op1; + + SAVE_OPLINE(); + op1 = GET_OP1_ZVAL_PTR(BP_VAR_R); + +ZEND_VM_C_LABEL(add_unpack_again): + if (EXPECTED(Z_TYPE_P(op1) == IS_ARRAY)) { + HashTable *ht = Z_ARRVAL_P(op1); + zval *val; + zend_string *key; + + ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) { + if (key) { + zend_throw_error(NULL, "Cannot unpack array with string keys"); + FREE_OP1(); + HANDLE_EXCEPTION(); + } else { + if (Z_ISREF_P(val) && Z_REFCOUNT_P(val) == 1) { + val = Z_REFVAL_P(val); + } + Z_TRY_ADDREF_P(val); + if (!zend_hash_next_index_insert(Z_ARRVAL_P(EX_VAR(opline->result.var)), val)) { + zend_cannot_add_element(); + zval_ptr_dtor_nogc(val); + break; + } + } + } ZEND_HASH_FOREACH_END(); + } else if (EXPECTED(Z_TYPE_P(op1) == IS_OBJECT)) { + zend_class_entry *ce = Z_OBJCE_P(op1); + zend_object_iterator *iter; + + if (!ce || !ce->get_iterator) { + zend_throw_error(NULL, "Only arrays and Traversables can be unpacked"); + } else { + iter = ce->get_iterator(ce, op1, 0); + if (UNEXPECTED(!iter)) { + FREE_OP1(); + if (!EG(exception)) { + zend_throw_exception_ex( + NULL, 0, "Object of type %s did not create an Iterator", ZSTR_VAL(ce->name) + ); + } + HANDLE_EXCEPTION(); + } + + if (iter->funcs->rewind) { + iter->funcs->rewind(iter); + } + + for (; iter->funcs->valid(iter) == SUCCESS; ) { + zval *val; + + if (UNEXPECTED(EG(exception) != NULL)) { + break; + } + + val = iter->funcs->get_current_data(iter); + if (UNEXPECTED(EG(exception) != NULL)) { + break; + } + + if (iter->funcs->get_current_key) { + zval key; + iter->funcs->get_current_key(iter, &key); + if (UNEXPECTED(EG(exception) != NULL)) { + break; + } + + if (UNEXPECTED(Z_TYPE(key) != IS_LONG)) { + zend_throw_error(NULL, + (Z_TYPE(key) == IS_STRING) ? + "Cannot unpack Traversable with string keys" : + "Cannot unpack Traversable with non-integer keys"); + zval_ptr_dtor(&key); + break; + } + } + + ZVAL_DEREF(val); + Z_TRY_ADDREF_P(val); + + if (!zend_hash_next_index_insert(Z_ARRVAL_P(EX_VAR(opline->result.var)), val)) { + zend_cannot_add_element(); + zval_ptr_dtor_nogc(val); + } + + iter->funcs->move_forward(iter); + } + + zend_iterator_dtor(iter); + } + } else if (EXPECTED(Z_ISREF_P(op1))) { + op1 = Z_REFVAL_P(op1); + ZEND_VM_C_GOTO(add_unpack_again); + } else { + zend_throw_error(NULL, "Only arrays and Traversables can be unpacked"); + } + + FREE_OP1(); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + +ZEND_VM_HANDLER(71, ZEND_INIT_ARRAY, CONST|TMP|VAR|CV|UNUSED, CONST|TMPVAR|UNUSED|NEXT|CV, ARRAY_INIT|REF) { zval *array; uint32_t size; @@ -5271,12 +5890,12 @@ ZEND_VM_HANDLER(71, ZEND_INIT_ARRAY, CONST|TMP|VAR|CV, CONST|TMPVAR|UNUSED|NEXT| } ZEND_VM_DISPATCH_TO_HANDLER(ZEND_ADD_ARRAY_ELEMENT); } else { - ZVAL_EMPTY_ARRAY(array); + ZVAL_ARR(array, zend_new_array(0)); ZEND_VM_NEXT_OPCODE(); } } -ZEND_VM_COLD_CONST_HANDLER(21, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE) +ZEND_VM_COLD_CONST_HANDLER(51, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE) { USE_OPLINE zend_free_op free_op1; @@ -5333,22 +5952,18 @@ ZEND_VM_COLD_CONST_HANDLER(21, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE) } else { ZVAL_EMPTY_ARRAY(result); } - } else if (Z_OBJ_HT_P(expr)->get_properties) { - HashTable *obj_ht = Z_OBJ_HT_P(expr)->get_properties(expr); + } else { + HashTable *obj_ht = zend_get_properties_for(expr, ZEND_PROP_PURPOSE_ARRAY_CAST); if (obj_ht) { /* fast copy */ - obj_ht = zend_proptable_to_symtable(obj_ht, + ZVAL_ARR(result, zend_proptable_to_symtable(obj_ht, (Z_OBJCE_P(expr)->default_properties_count || Z_OBJ_P(expr)->handlers != &std_object_handlers || - GC_IS_RECURSIVE(obj_ht))); - ZVAL_ARR(result, obj_ht); + GC_IS_RECURSIVE(obj_ht)))); + zend_release_properties(obj_ht); } else { ZVAL_EMPTY_ARRAY(result); } - } else { - ZVAL_COPY_VALUE(result, expr); - Z_ADDREF_P(result); - convert_to_array(result); } } else { ZVAL_OBJ(result, zend_objects_new(zend_standard_class_def)); @@ -5403,15 +6018,14 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMPVAR|CV, ANY, EVAL) if (RETURN_VALUE_USED(opline)) { return_value = EX_VAR(opline->result.var); - ZVAL_NULL(return_value); } new_op_array->scope = EX(func)->op_array.scope; - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_CODE | ZEND_CALL_HAS_SYMBOL_TABLE, + call = zend_vm_stack_push_call_frame( + (Z_TYPE_INFO(EX(This)) & ZEND_CALL_HAS_THIS) | ZEND_CALL_NESTED_CODE | ZEND_CALL_HAS_SYMBOL_TABLE, (zend_function*)new_op_array, 0, - Z_TYPE(EX(This)) != IS_OBJECT ? Z_CE(EX(This)) : NULL, - Z_TYPE(EX(This)) == IS_OBJECT ? Z_OBJ(EX(This)) : NULL); + Z_PTR(EX(This))); if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) { call->symbol_table = EX(symbol_table); @@ -5442,7 +6056,7 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMPVAR|CV, ANY, EVAL) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(196, ZEND_UNSET_CV, CV, UNUSED) +ZEND_VM_HANDLER(153, ZEND_UNSET_CV, CV, UNUSED) { USE_OPLINE zval *var = EX_VAR(opline->op1.var); @@ -5483,9 +6097,13 @@ ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMPVAR|CV, UNUSED, VAR_FETCH) tmp_name = NULL; } else { if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(varname) == IS_UNDEF)) { - varname = GET_OP1_UNDEF_CV(varname, BP_VAR_R); + varname = ZVAL_UNDEFINED_OP1(); + } + name = zval_try_get_tmp_string(varname, &tmp_name); + if (UNEXPECTED(!name)) { + FREE_OP1(); + HANDLE_EXCEPTION(); } - name = zval_get_tmp_string(varname, &tmp_name); } target_symbol_table = zend_get_target_symbol_table(opline->extended_value EXECUTE_DATA_CC); @@ -5498,11 +6116,12 @@ ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMPVAR|CV, UNUSED, VAR_FETCH) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_HANDLER(179, ZEND_UNSET_STATIC_PROP, CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR, CACHE_SLOT) +/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */ +ZEND_VM_COLD_HANDLER(179, ZEND_UNSET_STATIC_PROP, ANY, ANY, CACHE_SLOT) { USE_OPLINE zval *varname; - zend_string *name, *tmp_name; + zend_string *name, *tmp_name = NULL; zend_class_entry *ce; zend_free_op free_op1; @@ -5511,7 +6130,7 @@ ZEND_VM_COLD_HANDLER(179, ZEND_UNSET_STATIC_PROP, CONST|TMPVAR|CV, UNUSED|CLASS_ if (OP2_TYPE == IS_CONST) { ce = CACHED_PTR(opline->extended_value); if (UNEXPECTED(ce == NULL)) { - ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op2)), RT_CONSTANT(opline, opline->op2) + 1, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); + ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op2)), Z_STR_P(RT_CONSTANT(opline, opline->op2) + 1), ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); if (UNEXPECTED(ce == NULL)) { ZEND_ASSERT(EG(exception)); FREE_UNFETCHED_OP1(); @@ -5535,19 +6154,16 @@ ZEND_VM_COLD_HANDLER(179, ZEND_UNSET_STATIC_PROP, CONST|TMPVAR|CV, UNUSED|CLASS_ name = Z_STR_P(varname); } else if (EXPECTED(Z_TYPE_P(varname) == IS_STRING)) { name = Z_STR_P(varname); - tmp_name = NULL; } else { if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(varname) == IS_UNDEF)) { - varname = GET_OP1_UNDEF_CV(varname, BP_VAR_R); + varname = ZVAL_UNDEFINED_OP1(); } name = zval_get_tmp_string(varname, &tmp_name); } zend_std_unset_static_property(ce, name); - if (OP1_TYPE != IS_CONST) { - zend_tmp_string_release(tmp_name); - } + zend_tmp_string_release(tmp_name); FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -5609,7 +6225,7 @@ ZEND_VM_C_LABEL(num_index_dim): hval = Z_RES_HANDLE_P(offset); ZEND_VM_C_GOTO(num_index_dim); } else if (OP2_TYPE == IS_CV && Z_TYPE_P(offset) == IS_UNDEF) { - GET_OP2_UNDEF_CV(offset, BP_VAR_R); + ZVAL_UNDEFINED_OP2(); key = ZSTR_EMPTY_ALLOC(); ZEND_VM_C_GOTO(str_index_dim); } else { @@ -5623,20 +6239,16 @@ ZEND_VM_C_LABEL(num_index_dim): } } if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) { - container = GET_OP1_UNDEF_CV(container, BP_VAR_R); + container = ZVAL_UNDEFINED_OP1(); } if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(offset) == IS_UNDEF)) { - offset = GET_OP2_UNDEF_CV(offset, BP_VAR_R); + offset = ZVAL_UNDEFINED_OP2(); } if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (UNEXPECTED(Z_OBJ_HT_P(container)->unset_dimension == NULL)) { - zend_use_object_as_array(); - } else { - if (OP2_TYPE == IS_CONST && Z_EXTRA_P(offset) == ZEND_EXTRA_VALUE) { - offset++; - } - Z_OBJ_HT_P(container)->unset_dimension(container, offset); + if (OP2_TYPE == IS_CONST && Z_EXTRA_P(offset) == ZEND_EXTRA_VALUE) { + offset++; } + Z_OBJ_HT_P(container)->unset_dimension(container, offset); } else if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { zend_throw_error(NULL, "Cannot unset string offsets"); } @@ -5655,7 +6267,7 @@ ZEND_VM_HANDLER(76, ZEND_UNSET_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_S zval *offset; SAVE_OPLINE(); - container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_UNSET); + container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_UNSET); if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) { ZEND_VM_DISPATCH_TO_HELPER(zend_this_not_in_object_context_helper); } @@ -5666,17 +6278,17 @@ ZEND_VM_HANDLER(76, ZEND_UNSET_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_S if (Z_ISREF_P(container)) { container = Z_REFVAL_P(container); if (Z_TYPE_P(container) != IS_OBJECT) { + if (OP1_TYPE == IS_CV + && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) { + ZVAL_UNDEFINED_OP1(); + } break; } } else { break; } } - if (Z_OBJ_HT_P(container)->unset_property) { - Z_OBJ_HT_P(container)->unset_property(container, offset, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL)); - } else { - zend_wrong_property_unset(offset); - } + Z_OBJ_HT_P(container)->unset_property(container, offset, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL)); } while (0); FREE_OP2(); @@ -5906,10 +6518,12 @@ ZEND_VM_C_LABEL(fe_fetch_r_exit): value = Z_INDIRECT_P(value); value_type = Z_TYPE_INFO_P(value); if (EXPECTED(value_type != IS_UNDEF) - && EXPECTED(zend_check_property_access(Z_OBJ_P(array), p->key) == SUCCESS)) { + && EXPECTED(zend_check_property_access(Z_OBJ_P(array), p->key, 0) == SUCCESS)) { break; } - } else { + } else if (EXPECTED(Z_OBJCE_P(array)->default_properties_count == 0) + || !p->key + || zend_check_property_access(Z_OBJ_P(array), p->key, 1) == SUCCESS) { break; } } @@ -5974,7 +6588,7 @@ ZEND_VM_C_LABEL(fe_fetch_r_exit): if (EXPECTED(OP2_TYPE == IS_CV)) { zval *variable_ptr = EX_VAR(opline->op2.var); - zend_assign_to_variable(variable_ptr, value, IS_CV); + zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); } else { zval *res = EX_VAR(opline->op2.var); zend_refcounted *gc = Z_COUNTED_P(value); @@ -6056,10 +6670,21 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY, JMP_ADDR) value = Z_INDIRECT_P(value); value_type = Z_TYPE_INFO_P(value); if (EXPECTED(value_type != IS_UNDEF) - && EXPECTED(zend_check_property_access(Z_OBJ_P(array), p->key) == SUCCESS)) { + && EXPECTED(zend_check_property_access(Z_OBJ_P(array), p->key, 0) == SUCCESS)) { + if ((value_type & Z_TYPE_MASK) != IS_REFERENCE) { + zend_property_info *prop_info = + zend_get_typed_property_info_for_slot(Z_OBJ_P(array), value); + if (UNEXPECTED(prop_info)) { + ZVAL_NEW_REF(value, value); + ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(value), prop_info); + value_type = IS_REFERENCE_EX; + } + } break; } - } else { + } else if (EXPECTED(Z_OBJCE_P(array)->default_properties_count == 0) + || !p->key + || zend_check_property_access(Z_OBJ_P(array), p->key, 1) == SUCCESS) { break; } } @@ -6145,7 +6770,7 @@ ZEND_VM_C_LABEL(fe_fetch_w_exit): ref = Z_REF_P(value); GC_ADDREF(ref); - zval_ptr_dtor(variable_ptr); + i_zval_ptr_dtor(variable_ptr); ZVAL_REF(variable_ptr, ref); } } else { @@ -6155,28 +6780,36 @@ ZEND_VM_C_LABEL(fe_fetch_w_exit): ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HOT_HANDLER(197, ZEND_ISSET_ISEMPTY_CV, CV, UNUSED, ISSET, SPEC(ISSET)) +ZEND_VM_HOT_HANDLER(154, ZEND_ISSET_ISEMPTY_CV, CV, UNUSED, ISSET, SPEC(ISSET)) { USE_OPLINE zval *value; - int result; value = EX_VAR(opline->op1.var); if (!(opline->extended_value & ZEND_ISEMPTY)) { - result = - Z_TYPE_P(value) > IS_NULL && - (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL); + if (Z_TYPE_P(value) > IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL)) { + ZEND_VM_SMART_BRANCH_TRUE(); + ZVAL_TRUE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); + } else { + ZEND_VM_SMART_BRANCH_FALSE(); + ZVAL_FALSE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); + } } else { + int result; + SAVE_OPLINE(); result = !i_zend_is_true(value); if (UNEXPECTED(EG(exception))) { ZVAL_UNDEF(EX_VAR(opline->result.var)); HANDLE_EXCEPTION(); } + ZEND_VM_SMART_BRANCH(result, 0); + ZVAL_BOOL(EX_VAR(opline->result.var), result); + ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_SMART_BRANCH(result, 0); - ZVAL_BOOL(EX_VAR(opline->result.var), result); - ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(114, ZEND_ISSET_ISEMPTY_VAR, CONST|TMPVAR|CV, UNUSED, VAR_FETCH|ISSET) @@ -6226,76 +6859,22 @@ ZEND_VM_HANDLER(114, ZEND_ISSET_ISEMPTY_VAR, CONST|TMPVAR|CV, UNUSED, VAR_FETCH| ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(180, ZEND_ISSET_ISEMPTY_STATIC_PROP, CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR, ISSET|CACHE_SLOT) +/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */ +ZEND_VM_HANDLER(180, ZEND_ISSET_ISEMPTY_STATIC_PROP, ANY, CLASS_FETCH, ISSET|CACHE_SLOT) { USE_OPLINE zval *value; int result; - zend_free_op free_op1; - zval *varname; - zend_string *name, *tmp_name; - zend_class_entry *ce; SAVE_OPLINE(); - if (OP2_TYPE == IS_CONST) { - if (OP1_TYPE == IS_CONST && EXPECTED((ce = CACHED_PTR(opline->extended_value & ~ZEND_ISEMPTY)) != NULL)) { - value = CACHED_PTR((opline->extended_value & ~ZEND_ISEMPTY) + sizeof(void*)); - ZEND_VM_C_GOTO(is_static_prop_return); - } else if (UNEXPECTED((ce = CACHED_PTR(opline->extended_value & ~ZEND_ISEMPTY)) == NULL)) { - ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op2)), RT_CONSTANT(opline, opline->op2) + 1, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); - if (UNEXPECTED(ce == NULL)) { - ZEND_ASSERT(EG(exception)); - ZVAL_UNDEF(EX_VAR(opline->result.var)); - HANDLE_EXCEPTION(); - } - if (OP1_TYPE != IS_CONST) { - CACHE_PTR(opline->extended_value & ~ZEND_ISEMPTY, ce); - } - } - } else { - if (OP2_TYPE == IS_UNUSED) { - ce = zend_fetch_class(NULL, opline->op2.num); - if (UNEXPECTED(ce == NULL)) { - ZEND_ASSERT(EG(exception)); - FREE_UNFETCHED_OP1(); - ZVAL_UNDEF(EX_VAR(opline->result.var)); - HANDLE_EXCEPTION(); - } - } else { - ce = Z_CE_P(EX_VAR(opline->op2.var)); - } - if (OP1_TYPE == IS_CONST && - EXPECTED(CACHED_PTR(opline->extended_value & ~ZEND_ISEMPTY) == ce)) { - - value = CACHED_PTR((opline->extended_value & ~ZEND_ISEMPTY) + sizeof(void*)); - ZEND_VM_C_GOTO(is_static_prop_return); - } - } - - varname = GET_OP1_ZVAL_PTR(BP_VAR_IS); - if (OP1_TYPE == IS_CONST) { - name = Z_STR_P(varname); - } else { - name = zval_get_tmp_string(varname, &tmp_name); - } - value = zend_std_get_static_property(ce, name, 1); + result = zend_fetch_static_property_address(&value, NULL, opline->extended_value & ~ZEND_ISEMPTY, BP_VAR_IS, 0 OPLINE_CC EXECUTE_DATA_CC); - if (OP1_TYPE == IS_CONST && value) { - CACHE_POLYMORPHIC_PTR(opline->extended_value & ~ZEND_ISEMPTY, ce, value); - } - - if (OP1_TYPE != IS_CONST) { - zend_tmp_string_release(tmp_name); - } - FREE_OP1(); - -ZEND_VM_C_LABEL(is_static_prop_return): if (!(opline->extended_value & ZEND_ISEMPTY)) { - result = value && Z_TYPE_P(value) > IS_NULL && + result = result == SUCCESS && Z_TYPE_P(value) > IS_NULL && (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL); } else { - result = !value || !i_zend_is_true(value); + result = result != SUCCESS || !i_zend_is_true(value); } ZEND_VM_SMART_BRANCH(result, 1); @@ -6347,6 +6926,14 @@ ZEND_VM_C_LABEL(num_index_prop): /* > IS_NULL means not IS_UNDEF and not IS_NULL */ result = value != NULL && Z_TYPE_P(value) > IS_NULL && (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL); + + if (OP1_TYPE & (IS_CONST|IS_CV)) { + /* avoid exception check */ + FREE_OP2(); + ZEND_VM_SMART_BRANCH(result, 0); + ZVAL_BOOL(EX_VAR(opline->result.var), result); + ZEND_VM_NEXT_OPCODE(); + } } else { result = (value == NULL || !i_zend_is_true(value)); } @@ -6397,22 +6984,20 @@ ZEND_VM_COLD_CONST_HANDLER(148, ZEND_ISSET_ISEMPTY_PROP_OBJ, CONST|TMPVAR|UNUSED if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_ISREF_P(container)) { container = Z_REFVAL_P(container); if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT)) { - ZEND_VM_C_GOTO(isset_no_object); + result = (opline->extended_value & ZEND_ISEMPTY); + ZEND_VM_C_GOTO(isset_object_finish); } } else { - ZEND_VM_C_GOTO(isset_no_object); + result = (opline->extended_value & ZEND_ISEMPTY); + ZEND_VM_C_GOTO(isset_object_finish); } } - if (UNEXPECTED(!Z_OBJ_HT_P(container)->has_property)) { - zend_wrong_property_check(offset); -ZEND_VM_C_LABEL(isset_no_object): - result = (opline->extended_value & ZEND_ISEMPTY); - } else { - result = - (opline->extended_value & ZEND_ISEMPTY) ^ - Z_OBJ_HT_P(container)->has_property(container, offset, (opline->extended_value & ZEND_ISEMPTY), ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_ISEMPTY) : NULL)); - } + result = + (opline->extended_value & ZEND_ISEMPTY) ^ + Z_OBJ_HT_P(container)->has_property(container, offset, (opline->extended_value & ZEND_ISEMPTY), ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_ISEMPTY) : NULL)); + +ZEND_VM_C_LABEL(isset_object_finish): FREE_OP2(); FREE_OP1(); ZEND_VM_SMART_BRANCH(result, 1); @@ -6420,7 +7005,43 @@ ZEND_VM_C_LABEL(isset_no_object): ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_HANDLER(79, ZEND_EXIT, CONST|TMPVAR|UNUSED|CV, ANY) +ZEND_VM_HANDLER(194, ZEND_ARRAY_KEY_EXISTS, CV|TMPVAR|CONST, CV|TMPVAR|CONST) +{ + USE_OPLINE + + zend_free_op free_op1, free_op2; + zval *key, *subject; + HashTable *ht; + uint32_t result; + + SAVE_OPLINE(); + + key = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + subject = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); + + if (EXPECTED(Z_TYPE_P(subject) == IS_ARRAY)) { +ZEND_VM_C_LABEL(array_key_exists_array): + ht = Z_ARRVAL_P(subject); + result = zend_array_key_exists_fast(ht, key OPLINE_CC EXECUTE_DATA_CC); + } else { + if ((OP2_TYPE & (IS_VAR|IS_CV)) && EXPECTED(Z_ISREF_P(subject))) { + subject = Z_REFVAL_P(subject); + if (EXPECTED(Z_TYPE_P(subject) == IS_ARRAY)) { + ZEND_VM_C_GOTO(array_key_exists_array); + } + } + result = zend_array_key_exists_slow(subject, key OPLINE_CC EXECUTE_DATA_CC); + } + + FREE_OP2(); + FREE_OP1(); + ZEND_VM_SMART_BRANCH(result == IS_TRUE, 1); + Z_TYPE_INFO_P(EX_VAR(opline->result.var)) = result; + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + +/* No specialization for op_types (CONST|TMPVAR|UNUSED|CV, ANY) */ +ZEND_VM_COLD_HANDLER(79, ZEND_EXIT, ANY, ANY) { USE_OPLINE @@ -6542,7 +7163,7 @@ ZEND_VM_COLD_CONST_HANDLER(152, ZEND_JMP_SET, CONST|TMP|VAR|CV, JMP_ADDR) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_COLD_CONST_HANDLER(169, ZEND_COALESCE, CONST|TMPVAR|CV, JMP_ADDR) +ZEND_VM_COLD_CONST_HANDLER(169, ZEND_COALESCE, CONST|TMP|VAR|CV, JMP_ADDR) { USE_OPLINE zend_free_op free_op1; @@ -6582,7 +7203,7 @@ ZEND_VM_COLD_CONST_HANDLER(169, ZEND_COALESCE, CONST|TMPVAR|CV, JMP_ADDR) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HOT_HANDLER(22, ZEND_QM_ASSIGN, CONST|TMP|VAR|CV, ANY) +ZEND_VM_HOT_HANDLER(31, ZEND_QM_ASSIGN, CONST|TMP|VAR|CV, ANY) { USE_OPLINE zend_free_op free_op1; @@ -6592,7 +7213,7 @@ ZEND_VM_HOT_HANDLER(22, ZEND_QM_ASSIGN, CONST|TMP|VAR|CV, ANY) value = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) { SAVE_OPLINE(); - GET_OP1_UNDEF_CV(value, BP_VAR_R); + ZVAL_UNDEFINED_OP1(); ZVAL_NULL(result); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -6657,106 +7278,81 @@ ZEND_VM_COLD_HANDLER(103, ZEND_EXT_FCALL_END, ANY, ANY) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(139, ZEND_DECLARE_CLASS, CONST, ANY) +ZEND_VM_HANDLER(144, ZEND_DECLARE_CLASS, CONST, ANY) { USE_OPLINE SAVE_OPLINE(); - Z_CE_P(EX_VAR(opline->result.var)) = do_bind_class(&EX(func)->op_array, opline, EG(class_table), 0); + do_bind_class(RT_CONSTANT(opline, opline->op1), (OP2_TYPE == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(140, ZEND_DECLARE_INHERITED_CLASS, CONST, CONST) +ZEND_VM_HANDLER(145, ZEND_DECLARE_CLASS_DELAYED, CONST, CONST) { - zend_class_entry *parent; USE_OPLINE + zval *lcname, *zv; + zend_class_entry *ce; - SAVE_OPLINE(); - parent = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op2)), - RT_CONSTANT(opline, opline->op2) + 1, - ZEND_FETCH_CLASS_EXCEPTION); - if (UNEXPECTED(parent == NULL)) { - ZEND_ASSERT(EG(exception)); - HANDLE_EXCEPTION(); - } - Z_CE_P(EX_VAR(opline->result.var)) = do_bind_inherited_class(&EX(func)->op_array, opline, EG(class_table), parent, 0); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); -} - -ZEND_VM_HANDLER(145, ZEND_DECLARE_INHERITED_CLASS_DELAYED, CONST, CONST) -{ - USE_OPLINE - zval *zce, *orig_zce; - zend_class_entry *parent; - - SAVE_OPLINE(); - if ((zce = zend_hash_find_ex(EG(class_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1)) == NULL || - ((orig_zce = zend_hash_find_ex(EG(class_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)+1), 1)) != NULL && - Z_CE_P(zce) != Z_CE_P(orig_zce))) { - parent = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op2)), - RT_CONSTANT(opline, opline->op2) + 1, - ZEND_FETCH_CLASS_EXCEPTION); - if (UNEXPECTED(parent == NULL)) { - ZEND_ASSERT(EG(exception)); - HANDLE_EXCEPTION(); + ce = CACHED_PTR(opline->extended_value); + if (ce == NULL) { + lcname = RT_CONSTANT(opline, opline->op1); + zv = zend_hash_find_ex(EG(class_table), Z_STR_P(lcname + 1), 1); + if (zv) { + SAVE_OPLINE(); + ce = Z_CE_P(zv); + zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, Z_STR_P(lcname)); + if (UNEXPECTED(!zv)) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name)); + } else { + if (zend_do_link_class(ce, Z_STR_P(RT_CONSTANT(opline, opline->op2))) == FAILURE) { + /* Reload bucket pointer, the hash table may have been reallocated */ + zv = zend_hash_find(EG(class_table), Z_STR_P(lcname)); + zend_hash_set_bucket_key(EG(class_table), (Bucket *) zv, Z_STR_P(lcname + 1)); + HANDLE_EXCEPTION(); + } + } } - do_bind_inherited_class(&EX(func)->op_array, opline, EG(class_table), parent, 0); + CACHE_PTR(opline->extended_value, ce); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(171, ZEND_DECLARE_ANON_CLASS, ANY, ANY, JMP_ADDR) +ZEND_VM_HANDLER(146, ZEND_DECLARE_ANON_CLASS, ANY, ANY, CACHE_SLOT) { zval *zv; zend_class_entry *ce; USE_OPLINE - SAVE_OPLINE(); - zv = zend_hash_find_ex(EG(class_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1); - ZEND_ASSERT(zv != NULL); - ce = Z_CE_P(zv); - Z_CE_P(EX_VAR(opline->result.var)) = ce; - - if (ce->ce_flags & ZEND_ACC_ANON_BOUND) { - ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value); - ZEND_VM_CONTINUE(); - } - - if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) { - zend_verify_abstract_class(ce); + ce = CACHED_PTR(opline->extended_value); + if (UNEXPECTED(ce == NULL)) { + zend_string *rtd_key = Z_STR_P(RT_CONSTANT(opline, opline->op1)); + zv = zend_hash_find_ex(EG(class_table), rtd_key, 1); + if (UNEXPECTED(zv == NULL)) { + SAVE_OPLINE(); + do { + ZEND_ASSERT(EX(func)->op_array.fn_flags & ZEND_ACC_PRELOADED); + if (zend_preload_autoload + && zend_preload_autoload(EX(func)->op_array.filename) == SUCCESS) { + zv = zend_hash_find_ex(EG(class_table), rtd_key, 1); + if (EXPECTED(zv != NULL)) { + break; + } + } + zend_error_noreturn(E_ERROR, "Anonymous class wasn't preloaded"); + } while (0); + } + ZEND_ASSERT(zv != NULL); + ce = Z_CE_P(zv); + if (!(ce->ce_flags & ZEND_ACC_LINKED)) { + SAVE_OPLINE(); + if (zend_do_link_class(ce, (OP2_TYPE == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL) == FAILURE) { + HANDLE_EXCEPTION(); + } + } + CACHE_PTR(opline->extended_value, ce); } - ce->ce_flags |= ZEND_ACC_ANON_BOUND; - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); -} - -ZEND_VM_HANDLER(172, ZEND_DECLARE_ANON_INHERITED_CLASS, CONST, CONST, JMP_ADDR) -{ - zval *zv; - zend_class_entry *ce, *parent; - USE_OPLINE - - SAVE_OPLINE(); - zv = zend_hash_find_ex(EG(class_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1); - ZEND_ASSERT(zv != NULL); - ce = Z_CE_P(zv); Z_CE_P(EX_VAR(opline->result.var)) = ce; - - if (ce->ce_flags & ZEND_ACC_ANON_BOUND) { - ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value); - ZEND_VM_CONTINUE(); - } - - parent = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op2)), - RT_CONSTANT(opline, opline->op2) + 1, - ZEND_FETCH_CLASS_EXCEPTION); - if (UNEXPECTED(parent == NULL)) { - ZEND_ASSERT(EG(exception)); - HANDLE_EXCEPTION(); - } - - zend_do_inheritance(ce, parent); - ce->ce_flags |= ZEND_ACC_ANON_BOUND; - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(141, ZEND_DECLARE_FUNCTION, ANY, ANY) @@ -6764,7 +7360,7 @@ ZEND_VM_HANDLER(141, ZEND_DECLARE_FUNCTION, ANY, ANY) USE_OPLINE SAVE_OPLINE(); - do_bind_function(&EX(func)->op_array, opline, EG(function_table), 0); + do_bind_function(RT_CONSTANT(opline, opline->op1)); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -6800,7 +7396,7 @@ ZEND_VM_C_LABEL(try_instanceof): if (OP2_TYPE == IS_CONST) { ce = CACHED_PTR(opline->extended_value); if (UNEXPECTED(ce == NULL)) { - ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op2)), RT_CONSTANT(opline, opline->op2) + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD); + ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op2)), Z_STR_P(RT_CONSTANT(opline, opline->op2) + 1), ZEND_FETCH_CLASS_NO_AUTOLOAD); if (EXPECTED(ce)) { CACHE_PTR(opline->extended_value, ce); } @@ -6822,7 +7418,7 @@ ZEND_VM_C_LABEL(try_instanceof): ZEND_VM_C_GOTO(try_instanceof); } else { if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(expr) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(expr, BP_VAR_R); + ZVAL_UNDEFINED_OP1(); } result = 0; } @@ -6846,60 +7442,6 @@ ZEND_VM_HOT_HANDLER(0, ZEND_NOP, ANY, ANY) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(144, ZEND_ADD_INTERFACE, ANY, CONST, CACHE_SLOT) -{ - USE_OPLINE - zend_class_entry *ce = Z_CE_P(EX_VAR(opline->op1.var)); - zend_class_entry *iface; - - SAVE_OPLINE(); - iface = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op2)), RT_CONSTANT(opline, opline->op2) + 1, ZEND_FETCH_CLASS_INTERFACE); - if (UNEXPECTED(iface == NULL)) { - ZEND_ASSERT(EG(exception)); - HANDLE_EXCEPTION(); - } - - if (UNEXPECTED((iface->ce_flags & ZEND_ACC_INTERFACE) == 0)) { - zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name)); - } - zend_do_implement_interface(ce, iface); - - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); -} - -ZEND_VM_HANDLER(154, ZEND_ADD_TRAIT, ANY, ANY, CACHE_SLOT) -{ - USE_OPLINE - zend_class_entry *ce = Z_CE_P(EX_VAR(opline->op1.var)); - zend_class_entry *trait; - - SAVE_OPLINE(); - trait = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op2)), - RT_CONSTANT(opline, opline->op2) + 1, - ZEND_FETCH_CLASS_TRAIT); - if (UNEXPECTED(trait == NULL)) { - ZEND_ASSERT(EG(exception)); - HANDLE_EXCEPTION(); - } - if (!(trait->ce_flags & ZEND_ACC_TRAIT)) { - zend_error_noreturn(E_ERROR, "%s cannot use %s - it is not a trait", ZSTR_VAL(ce->name), ZSTR_VAL(trait->name)); - } - - zend_do_implement_trait(ce, trait); - - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); -} - -ZEND_VM_HANDLER(155, ZEND_BIND_TRAITS, ANY, ANY) -{ - USE_OPLINE - zend_class_entry *ce = Z_CE_P(EX_VAR(opline->op1.var)); - - SAVE_OPLINE(); - zend_do_bind_traits(ce); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); -} - ZEND_VM_HELPER(zend_dispatch_try_catch_finally_helper, ANY, ANY, uint32_t try_catch_offset, uint32_t op_num) { /* May be NULL during generator closing (only finally blocks are executed) */ @@ -6956,6 +7498,10 @@ ZEND_VM_HELPER(zend_dispatch_try_catch_finally_helper, ANY, ANY, uint32_t try_ca zend_generator_close(generator, 1); ZEND_VM_RETURN(); } else { + /* We didn't execute RETURN, and have to initialize return_value */ + if (EX(return_value)) { + ZVAL_UNDEF(EX(return_value)); + } ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); } } @@ -6994,15 +7540,13 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) if (throw_op->result_type & (IS_VAR | IS_TMP_VAR)) { switch (throw_op->opcode) { case ZEND_ADD_ARRAY_ELEMENT: + case ZEND_ADD_ARRAY_UNPACK: case ZEND_ROPE_INIT: case ZEND_ROPE_ADD: break; /* exception while building structures, live range handling will free those */ case ZEND_FETCH_CLASS: - case ZEND_DECLARE_CLASS: - case ZEND_DECLARE_INHERITED_CLASS: case ZEND_DECLARE_ANON_CLASS: - case ZEND_DECLARE_ANON_INHERITED_CLASS: break; /* return value is zend_class_entry pointer */ default: @@ -7013,15 +7557,6 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper, try_catch_offset, current_try_catch_offset, op_num, throw_op_num); } -ZEND_VM_HANDLER(146, ZEND_VERIFY_ABSTRACT_CLASS, ANY, ANY) -{ - USE_OPLINE - - SAVE_OPLINE(); - zend_verify_abstract_class(Z_CE_P(EX_VAR(opline->op1.var))); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); -} - ZEND_VM_HANDLER(150, ZEND_USER_OPCODE, ANY, ANY) { USE_OPLINE @@ -7086,29 +7621,26 @@ ZEND_VM_HANDLER(143, ZEND_DECLARE_CONST, CONST, CONST) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED) +ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED, CACHE_SLOT) { USE_OPLINE + zend_function *func; zval *zfunc; zval *object; zend_class_entry *called_scope; - zend_function *fbc; - - zfunc = zend_hash_find_ex(EG(function_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1); - ZEND_ASSERT(zfunc != NULL && Z_FUNC_P(zfunc)->type == ZEND_USER_FUNCTION); - fbc = Z_PTR_P(zfunc); - if (fbc->common.fn_flags & ZEND_ACC_IMMUTABLE) { - zend_function *new_func = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); - - memcpy(new_func, fbc, sizeof(zend_op_array)); - new_func->common.fn_flags &= ~ZEND_ACC_IMMUTABLE; - Z_PTR_P(zfunc) = fbc = new_func; + func = CACHED_PTR(opline->extended_value); + if (UNEXPECTED(func == NULL)) { + zfunc = zend_hash_find_ex(EG(function_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1); + ZEND_ASSERT(zfunc != NULL); + func = Z_FUNC_P(zfunc); + ZEND_ASSERT(func->type == ZEND_USER_FUNCTION); + CACHE_PTR(opline->extended_value, func); } if (Z_TYPE(EX(This)) == IS_OBJECT) { called_scope = Z_OBJCE(EX(This)); - if (UNEXPECTED((Z_FUNC_P(zfunc)->common.fn_flags & ZEND_ACC_STATIC) || + if (UNEXPECTED((func->common.fn_flags & ZEND_ACC_STATIC) || (EX(func)->common.fn_flags & ZEND_ACC_STATIC))) { object = NULL; } else { @@ -7118,7 +7650,7 @@ ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED) called_scope = Z_CE(EX(This)); object = NULL; } - zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc), + zend_create_closure(EX_VAR(opline->result.var), func, EX(func)->op_array.scope, called_scope, object); ZEND_VM_NEXT_OPCODE(); @@ -7192,20 +7724,23 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (OP1_TYPE == IS_VAR && - (value_ptr == &EG(uninitialized_zval) || - (opline->extended_value == ZEND_RETURNS_FUNCTION && - !Z_ISREF_P(value_ptr)))) { - zend_error(E_NOTICE, "Only variable references should be yielded by reference"); - ZVAL_COPY(&generator->value, value_ptr); - } else { + do { + if (OP1_TYPE == IS_VAR) { + ZEND_ASSERT(value_ptr != &EG(uninitialized_zval)); + if (opline->extended_value == ZEND_RETURNS_FUNCTION + && !Z_ISREF_P(value_ptr)) { + zend_error(E_NOTICE, "Only variable references should be yielded by reference"); + ZVAL_COPY(&generator->value, value_ptr); + break; + } + } if (Z_ISREF_P(value_ptr)) { Z_ADDREF_P(value_ptr); } else { ZVAL_MAKE_REF_EX(value_ptr, 2); } ZVAL_REF(&generator->value, Z_REF_P(value_ptr)); - } + } while (0); FREE_OP1_VAR_PTR(); } @@ -7289,7 +7824,7 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE ZEND_VM_RETURN(); } -ZEND_VM_HANDLER(142, ZEND_YIELD_FROM, CONST|TMP|VAR|CV, ANY) +ZEND_VM_HANDLER(166, ZEND_YIELD_FROM, CONST|TMP|VAR|CV, ANY) { USE_OPLINE @@ -7456,7 +7991,7 @@ ZEND_VM_HOT_HANDLER(168, ZEND_BIND_GLOBAL, CV, CONST, CACHE_SLOT) { USE_OPLINE zend_free_op free_op1, free_op2; - zval *varname; + zend_string *varname; zval *value; zval *variable_ptr; uintptr_t idx; @@ -7464,7 +7999,7 @@ ZEND_VM_HOT_HANDLER(168, ZEND_BIND_GLOBAL, CV, CONST, CACHE_SLOT) ZEND_VM_REPEATABLE_OPCODE - varname = GET_OP2_ZVAL_PTR(BP_VAR_R); + varname = Z_STR_P(GET_OP2_ZVAL_PTR(BP_VAR_R)); /* We store "hash slot index" + 1 (NULL is a mark of uninitialized cache slot) */ idx = (uintptr_t)CACHED_PTR(opline->extended_value) - 1; @@ -7472,19 +8007,19 @@ ZEND_VM_HOT_HANDLER(168, ZEND_BIND_GLOBAL, CV, CONST, CACHE_SLOT) Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx); if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == Z_STR_P(varname)) || - (EXPECTED(p->h == ZSTR_H(Z_STR_P(varname))) && + (EXPECTED(p->key == varname) || + (EXPECTED(p->h == ZSTR_H(varname)) && EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, Z_STR_P(varname)))))) { + EXPECTED(zend_string_equal_content(p->key, varname))))) { value = (zval*)p; /* value = &p->val; */ ZEND_VM_C_GOTO(check_indirect); } } - value = zend_hash_find_ex(&EG(symbol_table), Z_STR_P(varname), 1); + value = zend_hash_find_ex(&EG(symbol_table), varname, 1); if (UNEXPECTED(value == NULL)) { - value = zend_hash_add_new(&EG(symbol_table), Z_STR_P(varname), &EG(uninitialized_zval)); + value = zend_hash_add_new(&EG(symbol_table), varname, &EG(uninitialized_zval)); idx = (char*)value - (char*)EG(symbol_table).arData; /* Store "hash slot index" + 1 (NULL is a mark of uninitialized cache slot) */ CACHE_PTR(opline->extended_value, (void*)(idx + 1)); @@ -7560,7 +8095,7 @@ ZEND_VM_COLD_CONST_HANDLER(121, ZEND_STRLEN, CONST|TMPVAR|CV, ANY) SAVE_OPLINE(); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) { - value = GET_OP1_UNDEF_CV(value, BP_VAR_R); + value = ZVAL_UNDEFINED_OP1(); } strict = EX_USES_STRICT_TYPES(); do { @@ -7576,7 +8111,9 @@ ZEND_VM_COLD_CONST_HANDLER(121, ZEND_STRLEN, CONST|TMPVAR|CV, ANY) } zval_ptr_dtor(&tmp); } - zend_internal_type_error(strict, "strlen() expects parameter 1 to be string, %s given", zend_get_type_by_const(Z_TYPE_P(value))); + if (!EG(exception)) { + zend_internal_type_error(strict, "strlen() expects parameter 1 to be string, %s given", zend_get_type_by_const(Z_TYPE_P(value))); + } ZVAL_NULL(EX_VAR(opline->result.var)); } while (0); } @@ -7606,10 +8143,11 @@ ZEND_VM_C_LABEL(type_check_resource): } else if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) { result = ((1 << IS_NULL) & opline->extended_value) != 0; SAVE_OPLINE(); - GET_OP1_UNDEF_CV(value, BP_VAR_R); - ZEND_VM_SMART_BRANCH(result, 1); - ZVAL_BOOL(EX_VAR(opline->result.var), result); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZVAL_UNDEFINED_OP1(); + if (UNEXPECTED(EG(exception))) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); + } } if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { SAVE_OPLINE(); @@ -7628,29 +8166,27 @@ ZEND_VM_HOT_HANDLER(122, ZEND_DEFINED, CONST, ANY, CACHE_SLOT) { USE_OPLINE zend_constant *c; - int result; c = CACHED_PTR(opline->extended_value); - do { - if (EXPECTED(c != NULL)) { - if (!IS_SPECIAL_CACHE_VAL(c)) { - result = 1; - break; - } else if (EXPECTED(zend_hash_num_elements(EG(zend_constants)) == DECODE_SPECIAL_CACHE_NUM(c))) { - result = 0; - break; - } - } - if (zend_quick_check_constant(RT_CONSTANT(opline, opline->op1) OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) { - CACHE_PTR(opline->extended_value, ENCODE_SPECIAL_CACHE_NUM(zend_hash_num_elements(EG(zend_constants)))); - result = 0; - } else { - result = 1; + if (EXPECTED(c != NULL)) { + if (!IS_SPECIAL_CACHE_VAL(c)) { +ZEND_VM_C_LABEL(defined_true): + ZEND_VM_SMART_BRANCH_TRUE(); + ZVAL_TRUE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(zend_hash_num_elements(EG(zend_constants)) == DECODE_SPECIAL_CACHE_NUM(c))) { +ZEND_VM_C_LABEL(defined_false): + ZEND_VM_SMART_BRANCH_FALSE(); + ZVAL_FALSE(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE(); } - } while (0); - ZEND_VM_SMART_BRANCH(result, 0); - ZVAL_BOOL(EX_VAR(opline->result.var), result); - ZEND_VM_NEXT_OPCODE(); + } + if (zend_quick_check_constant(RT_CONSTANT(opline, opline->op1) OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) { + CACHE_PTR(opline->extended_value, ENCODE_SPECIAL_CACHE_NUM(zend_hash_num_elements(EG(zend_constants)))); + ZEND_VM_C_GOTO(defined_false); + } else { + ZEND_VM_C_GOTO(defined_true); + } } ZEND_VM_HANDLER(151, ZEND_ASSERT_CHECK, ANY, JMP_ADDR) @@ -7715,7 +8251,7 @@ ZEND_VM_HANDLER(157, ZEND_FETCH_CLASS_NAME, UNUSED|CLASS_FETCH, ANY) ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY) { - zend_array *args; + zend_array *args = NULL; zend_function *fbc = EX(func); zval *ret = EX(return_value); uint32_t call_info = EX_CALL_INFO() & (ZEND_CALL_NESTED | ZEND_CALL_TOP | ZEND_CALL_RELEASE_THIS); @@ -7746,7 +8282,7 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY) ZEND_CALL_NUM_ARGS(call) = 2; ZVAL_STR(ZEND_CALL_ARG(call, 1), fbc->common.function_name); - if (num_args) { + if (args) { ZVAL_ARR(ZEND_CALL_ARG(call, 2), args); } else { ZVAL_EMPTY_ARRAY(ZEND_CALL_ARG(call, 2)); @@ -7755,15 +8291,16 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY) fbc = call->func; if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { - if (UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } execute_data = call; i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { - LOAD_OPLINE(); + LOAD_OPLINE_EX(); ZEND_VM_ENTER_EX(); } else { + SAVE_OPLINE_EX(); execute_data = EX(prev_execute_data); LOAD_OPLINE(); ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); @@ -7786,10 +8323,10 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY) } if (ret == NULL) { - ZVAL_NULL(&retval); ret = &retval; } + ZVAL_NULL(ret); if (!zend_execute_internal) { /* saves one function call if zend_execute_internal is not used */ fbc->internal_function.handler(call, ret); @@ -7808,14 +8345,13 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY) EG(current_execute_data) = call->prev_execute_data; +ZEND_VM_C_LABEL(call_trampoline_end): zend_vm_stack_free_args(call); - if (ret == &retval) { zval_ptr_dtor(ret); } } -ZEND_VM_C_LABEL(call_trampoline_end): execute_data = EG(current_execute_data); if (!EX(func) || !ZEND_USER_CODE(EX(func)->type) || (call_info & ZEND_CALL_TOP)) { @@ -7855,9 +8391,9 @@ ZEND_VM_HANDLER(182, ZEND_BIND_LEXICAL, TMP, CV, REF) } } else { var = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); - if (UNEXPECTED(Z_ISUNDEF_P(var))) { + if (UNEXPECTED(Z_ISUNDEF_P(var)) && !(opline->extended_value & ZEND_BIND_IMPLICIT)) { SAVE_OPLINE(); - var = GET_OP2_UNDEF_CV(var, BP_VAR_R); + var = ZVAL_UNDEFINED_OP2(); if (UNEXPECTED(EG(exception))) { HANDLE_EXCEPTION(); } @@ -7866,11 +8402,12 @@ ZEND_VM_HANDLER(182, ZEND_BIND_LEXICAL, TMP, CV, REF) Z_TRY_ADDREF_P(var); } - zend_closure_bind_var_ex(closure, (opline->extended_value & ~ZEND_BIND_REF), var); + zend_closure_bind_var_ex(closure, + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT)), var); ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, CONST, REF) +ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, UNUSED, REF) { USE_OPLINE zend_free_op free_op1; @@ -7879,18 +8416,22 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, CONST, REF) zval *variable_ptr; variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); - zval_ptr_dtor(variable_ptr); - - ht = EX(func)->op_array.static_variables; - ZEND_ASSERT(ht != NULL); - if (GC_REFCOUNT(ht) > 1) { + i_zval_ptr_dtor(variable_ptr); + + ht = ZEND_MAP_PTR_GET(EX(func)->op_array.static_variables_ptr); + if (!ht) { + ZEND_ASSERT(EX(func)->op_array.fn_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED)); + ht = zend_array_dup(EX(func)->op_array.static_variables); + ZEND_MAP_PTR_SET(EX(func)->op_array.static_variables_ptr, ht); + } else if (GC_REFCOUNT(ht) > 1) { if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) { GC_DELREF(ht); } - EX(func)->op_array.static_variables = ht = zend_array_dup(ht); + ht = zend_array_dup(ht); + ZEND_MAP_PTR_SET(EX(func)->op_array.static_variables_ptr, ht); } - value = (zval*)((char*)ht->arData + (opline->extended_value & ~ZEND_BIND_REF)); + value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT))); if (opline->extended_value & ZEND_BIND_REF) { if (Z_TYPE_P(value) == IS_CONSTANT_AST) { @@ -7905,6 +8446,7 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, CONST, REF) GC_SET_REFCOUNT(ref, 2); GC_TYPE_INFO(ref) = IS_REFERENCE; ZVAL_COPY_VALUE(&ref->val, value); + ref->sources.ptr = NULL; Z_REF_P(value) = ref; Z_TYPE_INFO_P(value) = IS_REFERENCE_EX; ZVAL_REF(variable_ptr, ref); @@ -7951,13 +8493,13 @@ ZEND_VM_HANDLER(49, ZEND_CHECK_VAR, CV, UNUSED) if (UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) { SAVE_OPLINE(); - GET_OP1_UNDEF_CV(op1, BP_VAR_R); + ZVAL_UNDEFINED_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(51, ZEND_MAKE_REF, VAR|CV, UNUSED) +ZEND_VM_HANDLER(140, ZEND_MAKE_REF, VAR|CV, UNUSED) { USE_OPLINE zval *op1 = EX_VAR(opline->op1.var); @@ -8059,41 +8601,41 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(189, ZEND_IN_ARRAY, CONST|TMP|VAR|CV, CONST, NUM zend_free_op free_op1; zval *op1; HashTable *ht = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2)); - int result; + zval *result; SAVE_OPLINE(); op1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { - result = zend_hash_exists(ht, Z_STR_P(op1)); + result = zend_hash_find_ex(ht, Z_STR_P(op1), OP1_TYPE == IS_CONST); } else if (opline->extended_value) { if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { - result = zend_hash_index_exists(ht, Z_LVAL_P(op1)); + result = zend_hash_index_find(ht, Z_LVAL_P(op1)); } else { - result = 0; + result = NULL; } } else if (Z_TYPE_P(op1) <= IS_FALSE) { - result = zend_hash_exists(ht, ZSTR_EMPTY_ALLOC()); + result = zend_hash_find_ex(ht, ZSTR_EMPTY_ALLOC(), 1); } else { zend_string *key; - zval key_tmp, result_tmp; + zval key_tmp, result_tmp, *val; - result = 0; - ZEND_HASH_FOREACH_STR_KEY(ht, key) { + result = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) { ZVAL_STR(&key_tmp, key); compare_function(&result_tmp, op1, &key_tmp); if (Z_LVAL(result_tmp) == 0) { - result = 1; + result = val; break; } } ZEND_HASH_FOREACH_END(); } FREE_OP1(); ZEND_VM_SMART_BRANCH(result, 1); - ZVAL_BOOL(EX_VAR(opline->result.var), result); + ZVAL_BOOL(EX_VAR(opline->result.var), result != NULL); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_CONST_HANDLER(190, ZEND_COUNT, CONST|TMP|VAR|CV, UNUSED) +ZEND_VM_COLD_CONST_HANDLER(190, ZEND_COUNT, CONST|TMPVAR|CV, UNUSED) { USE_OPLINE zend_free_op free_op1; @@ -8101,8 +8643,8 @@ ZEND_VM_COLD_CONST_HANDLER(190, ZEND_COUNT, CONST|TMP|VAR|CV, UNUSED) zend_long count; SAVE_OPLINE(); - op1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); - do { + op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + while (1) { if (Z_TYPE_P(op1) == IS_ARRAY) { count = zend_array_count(Z_ARRVAL_P(op1)); break; @@ -8112,6 +8654,10 @@ ZEND_VM_COLD_CONST_HANDLER(190, ZEND_COUNT, CONST|TMP|VAR|CV, UNUSED) if (SUCCESS == Z_OBJ_HT_P(op1)->count_elements(op1, &count)) { break; } + if (UNEXPECTED(EG(exception))) { + count = 0; + break; + } } /* if not and the object implements Countable we call its count() method */ @@ -8126,20 +8672,27 @@ ZEND_VM_COLD_CONST_HANDLER(190, ZEND_COUNT, CONST|TMP|VAR|CV, UNUSED) /* If There's no handler and it doesn't implement Countable then add a warning */ count = 1; - } else if (Z_TYPE_P(op1) == IS_NULL) { + } else if ((OP1_TYPE & (IS_VAR|IS_CV)) != 0 && Z_TYPE_P(op1) == IS_REFERENCE) { + op1 = Z_REFVAL_P(op1); + continue; + } else if (Z_TYPE_P(op1) <= IS_NULL) { + if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + ZVAL_UNDEFINED_OP1(); + } count = 0; } else { count = 1; } - zend_error(E_WARNING, "count(): Parameter must be an array or an object that implements Countable"); - } while (0); + zend_error(E_WARNING, "%s(): Parameter must be an array or an object that implements Countable", opline->extended_value ? "sizeof" : "count"); + break; + } ZVAL_LONG(EX_VAR(opline->result.var), count); FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_CONST_HANDLER(191, ZEND_GET_CLASS, UNUSED|CONST|TMP|VAR|CV, UNUSED) +ZEND_VM_COLD_CONST_HANDLER(191, ZEND_GET_CLASS, UNUSED|CONST|TMPVAR|CV, UNUSED) { USE_OPLINE @@ -8158,12 +8711,21 @@ ZEND_VM_COLD_CONST_HANDLER(191, ZEND_GET_CLASS, UNUSED|CONST|TMP|VAR|CV, UNUSED) zval *op1; SAVE_OPLINE(); - op1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); - if (Z_TYPE_P(op1) == IS_OBJECT) { - ZVAL_STR_COPY(EX_VAR(opline->result.var), Z_OBJCE_P(op1)->name); - } else { - zend_error(E_WARNING, "get_class() expects parameter 1 to be object, %s given", zend_get_type_by_const(Z_TYPE_P(op1))); - ZVAL_FALSE(EX_VAR(opline->result.var)); + op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + while (1) { + if (Z_TYPE_P(op1) == IS_OBJECT) { + ZVAL_STR_COPY(EX_VAR(opline->result.var), Z_OBJCE_P(op1)->name); + } else if ((OP1_TYPE & (IS_VAR|IS_CV)) != 0 && Z_TYPE_P(op1) == IS_REFERENCE) { + op1 = Z_REFVAL_P(op1); + continue; + } else { + if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + ZVAL_UNDEFINED_OP1(); + } + zend_error(E_WARNING, "get_class() expects parameter 1 to be object, %s given", zend_get_type_by_const(Z_TYPE_P(op1))); + ZVAL_FALSE(EX_VAR(opline->result.var)); + } + break; } FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -8208,7 +8770,7 @@ ZEND_VM_COLD_CONST_HANDLER(193, ZEND_GET_TYPE, CONST|TMP|VAR|CV, UNUSED) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(194, ZEND_FUNC_NUM_ARGS, UNUSED, UNUSED) +ZEND_VM_HANDLER(171, ZEND_FUNC_NUM_ARGS, UNUSED, UNUSED) { USE_OPLINE @@ -8216,7 +8778,7 @@ ZEND_VM_HANDLER(194, ZEND_FUNC_NUM_ARGS, UNUSED, UNUSED) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(195, ZEND_FUNC_GET_ARGS, UNUSED|CONST, UNUSED) +ZEND_VM_HANDLER(172, ZEND_FUNC_GET_ARGS, UNUSED|CONST, UNUSED) { USE_OPLINE zend_array *ht; @@ -8253,10 +8815,11 @@ ZEND_VM_HANDLER(195, ZEND_FUNC_GET_ARGS, UNUSED|CONST, UNUSED) if (Z_OPT_REFCOUNTED_P(q)) { Z_ADDREF_P(q); } + ZEND_HASH_FILL_SET(q); } else { - q = &EG(uninitialized_zval); + ZEND_HASH_FILL_SET_NULL(); } - ZEND_HASH_FILL_ADD(q); + ZEND_HASH_FILL_NEXT(); p++; i++; } @@ -8274,10 +8837,11 @@ ZEND_VM_HANDLER(195, ZEND_FUNC_GET_ARGS, UNUSED|CONST, UNUSED) if (Z_OPT_REFCOUNTED_P(q)) { Z_ADDREF_P(q); } + ZEND_HASH_FILL_SET(q); } else { - q = &EG(uninitialized_zval); + ZEND_HASH_FILL_SET_NULL(); } - ZEND_HASH_FILL_ADD(q); + ZEND_HASH_FILL_NEXT(); p++; i++; } @@ -8289,6 +8853,16 @@ ZEND_VM_HANDLER(195, ZEND_FUNC_GET_ARGS, UNUSED|CONST, UNUSED) ZEND_VM_NEXT_OPCODE(); } +ZEND_VM_HANDLER(167, ZEND_COPY_TMP, TMPVAR, UNUSED) +{ + USE_OPLINE + zend_free_op free_op1; + zval *value = GET_OP1_ZVAL_PTR(BP_VAR_R); + zval *result = EX_VAR(opline->result.var); + ZVAL_COPY(result, value); + ZEND_VM_NEXT_OPCODE(); +} + ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_JMP, (OP_JMP_ADDR(op, op->op1) > op), ZEND_JMP_FORWARD, JMP_ADDR, ANY) { USE_OPLINE @@ -8545,23 +9119,6 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_PRE_INC, (op1_info == MAY_BE_LONG), ZEND_PRE_ ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_PRE_INC, (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)), ZEND_PRE_INC_LONG_OR_DOUBLE, CV, ANY, SPEC(RETVAL)) -{ - USE_OPLINE - zval *var_ptr; - - var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); - if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { - fast_long_increment_function(var_ptr); - } else { - Z_DVAL_P(var_ptr)++; - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); - } - ZEND_VM_NEXT_OPCODE(); -} - ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_PRE_DEC, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG), ZEND_PRE_DEC_LONG_NO_OVERFLOW, CV, ANY, SPEC(RETVAL)) { USE_OPLINE @@ -8588,23 +9145,6 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_PRE_DEC, (op1_info == MAY_BE_LONG), ZEND_PRE_ ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_PRE_DEC, (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)), ZEND_PRE_DEC_LONG_OR_DOUBLE, CV, ANY, SPEC(RETVAL)) -{ - USE_OPLINE - zval *var_ptr; - - var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); - if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { - fast_long_decrement_function(var_ptr); - } else { - Z_DVAL_P(var_ptr)--; - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); - } - ZEND_VM_NEXT_OPCODE(); -} - ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_POST_INC, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG), ZEND_POST_INC_LONG_NO_OVERFLOW, CV, ANY) { USE_OPLINE @@ -8627,22 +9167,6 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_POST_INC, (op1_info == MAY_BE_LONG), ZEND_POS ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_POST_INC, (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)), ZEND_POST_INC_LONG_OR_DOUBLE, CV, ANY) -{ - USE_OPLINE - zval *var_ptr; - - var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); - if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { - ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr)); - fast_long_increment_function(var_ptr); - } else { - ZVAL_DOUBLE(EX_VAR(opline->result.var), Z_DVAL_P(var_ptr)); - Z_DVAL_P(var_ptr)++; - } - ZEND_VM_NEXT_OPCODE(); -} - ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_POST_DEC, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG), ZEND_POST_DEC_LONG_NO_OVERFLOW, CV, ANY) { USE_OPLINE @@ -8665,19 +9189,14 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_POST_DEC, (op1_info == MAY_BE_LONG), ZEND_POS ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_POST_DEC, (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)), ZEND_POST_DEC_LONG_OR_DOUBLE, CV, ANY) +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_QM_ASSIGN, (op1_info == MAY_BE_LONG), ZEND_QM_ASSIGN_LONG, CONST|TMPVARCV, ANY) { USE_OPLINE - zval *var_ptr; + zend_free_op free_op1; + zval *value; - var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); - if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { - ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr)); - fast_long_decrement_function(var_ptr); - } else { - ZVAL_DOUBLE(EX_VAR(opline->result.var), Z_DVAL_P(var_ptr)); - Z_DVAL_P(var_ptr)--; - } + value = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(value)); ZEND_VM_NEXT_OPCODE(); } @@ -8872,7 +9391,7 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_FE_FETCH_R, op->op2_type == IS_CV && (op1_inf } variable_ptr = EX_VAR(opline->op2.var); - zend_assign_to_variable(variable_ptr, value, IS_CV); + zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } |