diff --git a/Zend/tests/bug70785.phpt b/Zend/tests/bug70785.phpt index f48bc3cdb99e..87955880e106 100644 --- a/Zend/tests/bug70785.phpt +++ b/Zend/tests/bug70785.phpt @@ -19,6 +19,16 @@ try { undefined_function(); } catch (Exception $e) { } +try { + $d === $f; // ZEND_VM_NEXT_OPCODE + undefined_function(); +} catch (Exception $e) { +} +try { + $h !== $g; // ZEND_VM_NEXT_OPCODE + undefined_function(); +} catch (Exception $e) { +} ?> okey --EXPECT-- diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index a1f3024d4e9b..7214b87ccb12 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -2118,6 +2118,12 @@ ZEND_API zend_bool ZEND_FASTCALL zend_is_identical(zval *op1, zval *op2) /* {{{ } /* }}} */ +ZEND_API zend_bool ZEND_FASTCALL zend_is_identical_array(HashTable *h1, HashTable *h2) /* {{{ */ +{ + return (h1 == h2 || + zend_hash_compare(h1, h2, (compare_func_t) hash_zval_identical_function, 1) == 0); +} + ZEND_API int ZEND_FASTCALL is_identical_function(zval *result, zval *op1, zval *op2) /* {{{ */ { ZVAL_BOOL(result, zend_is_identical(op1, op2)); diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index ee7c951c7d51..2a7bd0a94102 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -55,6 +55,7 @@ ZEND_API int ZEND_FASTCALL shift_right_function(zval *result, zval *op1, zval *o ZEND_API int ZEND_FASTCALL concat_function(zval *result, zval *op1, zval *op2); ZEND_API zend_bool ZEND_FASTCALL zend_is_identical(zval *op1, zval *op2); +ZEND_API zend_bool ZEND_FASTCALL zend_is_identical_array(HashTable *h1, HashTable *h2); ZEND_API int ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2); ZEND_API int ZEND_FASTCALL is_identical_function(zval *result, zval *op1, zval *op2); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index a8ab1ff375c4..ef2ad13ea9aa 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -449,9 +449,95 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(16, ZEND_IS_IDENTICAL, CONST|TMP|VAR|CV, CONST|T zend_bool result; SAVE_OPLINE(); - op1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); - op2 = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R); - result = fast_is_identical_function(op1, op2); + op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); +ZEND_VM_C_LABEL(compare_values_any_type): + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((OP1_TYPE & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((OP2_TYPE & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + ZEND_VM_C_GOTO(compare_values_any_type); + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((OP1_TYPE & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((OP2_TYPE & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + ZEND_VM_C_GOTO(compare_values); + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((OP1_TYPE & IS_CV) && Z_ISUNDEF_P(op1)) || ((OP2_TYPE & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) == Z_TYPE_P(op2); + ZEND_VM_C_GOTO(return_result_maythrow); + } + /* They are not identical, return false. This has to check for __destruct errors */ + FREE_OP1(); + FREE_OP2(); + ZEND_VM_SMART_BRANCH(0, 1); + } +ZEND_VM_C_LABEL(compare_values): + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((OP1_TYPE & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((OP2_TYPE & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(1, 1); + } + /* They are identical, return true */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + FREE_OP1(); + FREE_OP2(); + ZEND_VM_SMART_BRANCH(1, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) == Z_LVAL_P(op2)); +ZEND_VM_C_LABEL(free_nothrow): + FREE_OP1(); + FREE_OP2(); + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) == Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_C_GOTO(free_nothrow); + case IS_STRING: + result = zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + ZEND_VM_C_GOTO(free_nothrow); + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) == Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + ZEND_VM_C_GOTO(compare_values_any_type); + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + ZEND_VM_C_GOTO(compare_values_any_type); + default: + result = 1; + } +ZEND_VM_C_LABEL(return_result_maythrow): + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ FREE_OP1(); FREE_OP2(); ZEND_VM_SMART_BRANCH(result, 1); @@ -464,9 +550,95 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(17, ZEND_IS_NOT_IDENTICAL, CONST|TMP|VAR|CV, CON zend_bool result; SAVE_OPLINE(); - op1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); - op2 = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R); - result = fast_is_not_identical_function(op1, op2); + op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); +ZEND_VM_C_LABEL(compare_values_any_type): + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((OP1_TYPE & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((OP2_TYPE & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + ZEND_VM_C_GOTO(compare_values_any_type); + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((OP1_TYPE & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((OP2_TYPE & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + ZEND_VM_C_GOTO(compare_values); + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((OP1_TYPE & IS_CV) && Z_ISUNDEF_P(op1)) || ((OP2_TYPE & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're not identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) != Z_TYPE_P(op2); + ZEND_VM_C_GOTO(return_result_maythrow); + } + /* They are not identical, return true. This has to check for __destruct errors (and undefined variable errors when IS_NULL is possible) */ + FREE_OP1(); + FREE_OP2(); + ZEND_VM_SMART_BRANCH(1, 1); + } +ZEND_VM_C_LABEL(compare_values): + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((OP1_TYPE & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((OP2_TYPE & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(0, 1); + } + /* They are identical, return false. */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + FREE_OP1(); + FREE_OP2(); + ZEND_VM_SMART_BRANCH(0, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) != Z_LVAL_P(op2)); +ZEND_VM_C_LABEL(free_nothrow): + FREE_OP1(); + FREE_OP2(); + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) != Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_C_GOTO(free_nothrow); + case IS_STRING: + result = !zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + ZEND_VM_C_GOTO(free_nothrow); + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = !zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) != Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + ZEND_VM_C_GOTO(compare_values_any_type); + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + ZEND_VM_C_GOTO(compare_values_any_type); + default: + result = 1; + } +ZEND_VM_C_LABEL(return_result_maythrow): + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ FREE_OP1(); FREE_OP2(); ZEND_VM_SMART_BRANCH(result, 1); @@ -1496,7 +1668,7 @@ ZEND_VM_HELPER(zend_pre_dec_helper, VAR|CV, ANY) SAVE_OPLINE(); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_UNDEF)) { - ZVAL_NULL(var_ptr); + ZVAL_NULL(var_ptr); ZVAL_UNDEFINED_OP1(); } @@ -2234,7 +2406,7 @@ ZEND_VM_C_LABEL(fetch_obj_is_fast_copy): } retval = zobj->handlers->read_property(zobj, name, BP_VAR_IS, cache_slot, EX_VAR(opline->result.var)); - + if (OP2_TYPE != IS_CONST) { zend_tmp_string_release(tmp_name); } @@ -5528,10 +5700,10 @@ ZEND_VM_HANDLER(147, ZEND_ADD_ARRAY_UNPACK, ANY, ANY) { USE_OPLINE 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); @@ -5572,11 +5744,11 @@ ZEND_VM_C_LABEL(add_unpack_again): } HANDLE_EXCEPTION(); } - + if (iter->funcs->rewind) { iter->funcs->rewind(iter); } - + for (; iter->funcs->valid(iter) == SUCCESS; ) { zval *val; @@ -5625,7 +5797,7 @@ ZEND_VM_C_LABEL(add_unpack_again): } else { zend_throw_error(NULL, "Only arrays and Traversables can be unpacked"); } - + FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 5da5452b69be..dea202202969 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -4763,7 +4763,93 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_IDENTICAL_SPEC SAVE_OPLINE(); op1 = RT_CONSTANT(opline, opline->op1); op2 = RT_CONSTANT(opline, opline->op2); - result = fast_is_identical_function(op1, op2); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_CONST & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_CONST & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_CONST & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_CONST & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_CONST & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_CONST & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) == Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return false. This has to check for __destruct errors */ + + + ZEND_VM_SMART_BRANCH(0, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_CONST & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_CONST & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(1, 1); + } + /* They are identical, return true */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + + + ZEND_VM_SMART_BRANCH(1, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) == Z_LVAL_P(op2)); +free_nothrow: + + + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) == Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) == Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) == Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ ZEND_VM_SMART_BRANCH(result, 1); @@ -4778,7 +4864,93 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_IDENTICAL_ SAVE_OPLINE(); op1 = RT_CONSTANT(opline, opline->op1); op2 = RT_CONSTANT(opline, opline->op2); - result = fast_is_not_identical_function(op1, op2); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_CONST & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_CONST & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_CONST & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_CONST & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_CONST & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_CONST & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're not identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) != Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return true. This has to check for __destruct errors (and undefined variable errors when IS_NULL is possible) */ + + + ZEND_VM_SMART_BRANCH(1, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_CONST & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_CONST & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(0, 1); + } + /* They are identical, return false. */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + + + ZEND_VM_SMART_BRANCH(0, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) != Z_LVAL_P(op2)); +free_nothrow: + + + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) != Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) != Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = !zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = !zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) != Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ ZEND_VM_SMART_BRANCH(result, 1); @@ -17799,7 +17971,93 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_IDENTICAL_SPEC_TMP_CONST_HA SAVE_OPLINE(); op1 = _get_zval_ptr_tmp(opline->op1.var EXECUTE_DATA_CC); op2 = RT_CONSTANT(opline, opline->op2); - result = fast_is_identical_function(op1, op2); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_TMP_VAR & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_CONST & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_TMP_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_CONST & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_TMP_VAR & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_CONST & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) == Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return false. This has to check for __destruct errors */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + + ZEND_VM_SMART_BRANCH(0, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_TMP_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_CONST & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(1, 1); + } + /* They are identical, return true */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + + ZEND_VM_SMART_BRANCH(1, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) == Z_LVAL_P(op2)); +free_nothrow: + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) == Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) == Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) == Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_SMART_BRANCH(result, 1); @@ -17814,7 +18072,93 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_IDENTICAL_SPEC_TMP_CONS SAVE_OPLINE(); op1 = _get_zval_ptr_tmp(opline->op1.var EXECUTE_DATA_CC); op2 = RT_CONSTANT(opline, opline->op2); - result = fast_is_not_identical_function(op1, op2); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_TMP_VAR & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_CONST & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_TMP_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_CONST & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_TMP_VAR & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_CONST & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're not identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) != Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return true. This has to check for __destruct errors (and undefined variable errors when IS_NULL is possible) */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + + ZEND_VM_SMART_BRANCH(1, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_TMP_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_CONST & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(0, 1); + } + /* They are identical, return false. */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + + ZEND_VM_SMART_BRANCH(0, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) != Z_LVAL_P(op2)); +free_nothrow: + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) != Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) != Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = !zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = !zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) != Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_SMART_BRANCH(result, 1); @@ -18600,7 +18944,93 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_IDENTICAL_SPEC_TMP_TMP_HAND SAVE_OPLINE(); op1 = _get_zval_ptr_tmp(opline->op1.var EXECUTE_DATA_CC); op2 = _get_zval_ptr_tmp(opline->op2.var EXECUTE_DATA_CC); - result = fast_is_identical_function(op1, op2); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_TMP_VAR & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_TMP_VAR & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_TMP_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_TMP_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_TMP_VAR & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_TMP_VAR & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) == Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return false. This has to check for __destruct errors */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(0, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_TMP_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_TMP_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(1, 1); + } + /* They are identical, return true */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(1, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) == Z_LVAL_P(op2)); +free_nothrow: + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) == Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) == Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) == Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); ZEND_VM_SMART_BRANCH(result, 1); @@ -18615,7 +19045,93 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_IDENTICAL_SPEC_TMP_TMP_ SAVE_OPLINE(); op1 = _get_zval_ptr_tmp(opline->op1.var EXECUTE_DATA_CC); op2 = _get_zval_ptr_tmp(opline->op2.var EXECUTE_DATA_CC); - result = fast_is_not_identical_function(op1, op2); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_TMP_VAR & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_TMP_VAR & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_TMP_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_TMP_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_TMP_VAR & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_TMP_VAR & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're not identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) != Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return true. This has to check for __destruct errors (and undefined variable errors when IS_NULL is possible) */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(1, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_TMP_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_TMP_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(0, 1); + } + /* They are identical, return false. */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(0, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) != Z_LVAL_P(op2)); +free_nothrow: + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) != Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) != Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = !zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = !zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) != Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); ZEND_VM_SMART_BRANCH(result, 1); @@ -20807,9 +21323,95 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_IDENTICAL_SPEC_VAR_CONST_HA zend_bool result; SAVE_OPLINE(); - op1 = _get_zval_ptr_var_deref(opline->op1.var EXECUTE_DATA_CC); + op1 = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); op2 = RT_CONSTANT(opline, opline->op2); - result = fast_is_identical_function(op1, op2); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_VAR & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_CONST & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_CONST & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_VAR & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_CONST & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) == Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return false. This has to check for __destruct errors */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + + ZEND_VM_SMART_BRANCH(0, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_CONST & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(1, 1); + } + /* They are identical, return true */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + + ZEND_VM_SMART_BRANCH(1, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) == Z_LVAL_P(op2)); +free_nothrow: + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) == Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) == Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) == Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_SMART_BRANCH(result, 1); @@ -20822,9 +21424,95 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_IDENTICAL_SPEC_VAR_CONS zend_bool result; SAVE_OPLINE(); - op1 = _get_zval_ptr_var_deref(opline->op1.var EXECUTE_DATA_CC); + op1 = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); op2 = RT_CONSTANT(opline, opline->op2); - result = fast_is_not_identical_function(op1, op2); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_VAR & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_CONST & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_CONST & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_VAR & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_CONST & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're not identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) != Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return true. This has to check for __destruct errors (and undefined variable errors when IS_NULL is possible) */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + + ZEND_VM_SMART_BRANCH(1, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_CONST & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(0, 1); + } + /* They are identical, return false. */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + + ZEND_VM_SMART_BRANCH(0, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) != Z_LVAL_P(op2)); +free_nothrow: + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) != Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) != Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = !zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = !zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) != Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_SMART_BRANCH(result, 1); @@ -25178,9 +25866,95 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_IDENTICAL_SPEC_VAR_TMP_HAND zend_bool result; SAVE_OPLINE(); - op1 = _get_zval_ptr_var_deref(opline->op1.var EXECUTE_DATA_CC); + op1 = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); op2 = _get_zval_ptr_tmp(opline->op2.var EXECUTE_DATA_CC); - result = fast_is_identical_function(op1, op2); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_VAR & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_TMP_VAR & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_TMP_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_VAR & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_TMP_VAR & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) == Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return false. This has to check for __destruct errors */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(0, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_TMP_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(1, 1); + } + /* They are identical, return true */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(1, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) == Z_LVAL_P(op2)); +free_nothrow: + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) == Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) == Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) == Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); ZEND_VM_SMART_BRANCH(result, 1); @@ -25193,9 +25967,95 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_IDENTICAL_SPEC_VAR_TMP_ zend_bool result; SAVE_OPLINE(); - op1 = _get_zval_ptr_var_deref(opline->op1.var EXECUTE_DATA_CC); + op1 = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); op2 = _get_zval_ptr_tmp(opline->op2.var EXECUTE_DATA_CC); - result = fast_is_not_identical_function(op1, op2); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_VAR & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_TMP_VAR & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_TMP_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_VAR & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_TMP_VAR & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're not identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) != Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return true. This has to check for __destruct errors (and undefined variable errors when IS_NULL is possible) */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(1, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_TMP_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(0, 1); + } + /* They are identical, return false. */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(0, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) != Z_LVAL_P(op2)); +free_nothrow: + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) != Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) != Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = !zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = !zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) != Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); ZEND_VM_SMART_BRANCH(result, 1); @@ -25248,9 +26108,95 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_IDENTICAL_SPEC_VAR_VAR_HAND zend_bool result; SAVE_OPLINE(); - op1 = _get_zval_ptr_var_deref(opline->op1.var EXECUTE_DATA_CC); - op2 = _get_zval_ptr_var_deref(opline->op2.var EXECUTE_DATA_CC); - result = fast_is_identical_function(op1, op2); + op1 = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); + op2 = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_VAR & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_VAR & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_VAR & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_VAR & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) == Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return false. This has to check for __destruct errors */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(0, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(1, 1); + } + /* They are identical, return true */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(1, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) == Z_LVAL_P(op2)); +free_nothrow: + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) == Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) == Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) == Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); ZEND_VM_SMART_BRANCH(result, 1); @@ -25263,9 +26209,95 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_IDENTICAL_SPEC_VAR_VAR_ zend_bool result; SAVE_OPLINE(); - op1 = _get_zval_ptr_var_deref(opline->op1.var EXECUTE_DATA_CC); - op2 = _get_zval_ptr_var_deref(opline->op2.var EXECUTE_DATA_CC); - result = fast_is_not_identical_function(op1, op2); + op1 = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); + op2 = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_VAR & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_VAR & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_VAR & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_VAR & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're not identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) != Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return true. This has to check for __destruct errors (and undefined variable errors when IS_NULL is possible) */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(1, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(0, 1); + } + /* They are identical, return false. */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(0, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) != Z_LVAL_P(op2)); +free_nothrow: + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) != Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) != Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = !zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = !zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) != Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); ZEND_VM_SMART_BRANCH(result, 1); @@ -36727,9 +37759,95 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_IDENTICAL_SPEC_CV_CONST_HAN zend_bool result; SAVE_OPLINE(); - op1 = _get_zval_ptr_cv_deref_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC); + op1 = EX_VAR(opline->op1.var); op2 = RT_CONSTANT(opline, opline->op2); - result = fast_is_identical_function(op1, op2); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_CV & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_CONST & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_CV & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_CONST & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_CV & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_CONST & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) == Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return false. This has to check for __destruct errors */ + + + ZEND_VM_SMART_BRANCH(0, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_CV & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_CONST & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(1, 1); + } + /* They are identical, return true */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + + + ZEND_VM_SMART_BRANCH(1, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) == Z_LVAL_P(op2)); +free_nothrow: + + + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) == Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) == Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) == Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ ZEND_VM_SMART_BRANCH(result, 1); @@ -36742,9 +37860,95 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_IDENTICAL_SPEC_CV_CONST zend_bool result; SAVE_OPLINE(); - op1 = _get_zval_ptr_cv_deref_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC); + op1 = EX_VAR(opline->op1.var); op2 = RT_CONSTANT(opline, opline->op2); - result = fast_is_not_identical_function(op1, op2); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_CV & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_CONST & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_CV & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_CONST & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_CV & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_CONST & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're not identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) != Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return true. This has to check for __destruct errors (and undefined variable errors when IS_NULL is possible) */ + + + ZEND_VM_SMART_BRANCH(1, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_CV & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_CONST & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(0, 1); + } + /* They are identical, return false. */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + + + ZEND_VM_SMART_BRANCH(0, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) != Z_LVAL_P(op2)); +free_nothrow: + + + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) != Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) != Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = !zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = !zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) != Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ ZEND_VM_SMART_BRANCH(result, 1); @@ -43205,9 +44409,95 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_IDENTICAL_SPEC_CV_TMP_HANDL zend_bool result; SAVE_OPLINE(); - op1 = _get_zval_ptr_cv_deref_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC); + op1 = EX_VAR(opline->op1.var); op2 = _get_zval_ptr_tmp(opline->op2.var EXECUTE_DATA_CC); - result = fast_is_identical_function(op1, op2); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_CV & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_TMP_VAR & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_CV & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_TMP_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_CV & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_TMP_VAR & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) == Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return false. This has to check for __destruct errors */ + + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(0, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_CV & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_TMP_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(1, 1); + } + /* They are identical, return true */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(1, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) == Z_LVAL_P(op2)); +free_nothrow: + + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) == Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) == Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) == Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); ZEND_VM_SMART_BRANCH(result, 1); @@ -43220,9 +44510,95 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_IDENTICAL_SPEC_CV_TMP_H zend_bool result; SAVE_OPLINE(); - op1 = _get_zval_ptr_cv_deref_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC); + op1 = EX_VAR(opline->op1.var); op2 = _get_zval_ptr_tmp(opline->op2.var EXECUTE_DATA_CC); - result = fast_is_not_identical_function(op1, op2); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_CV & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_TMP_VAR & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_CV & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_TMP_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_CV & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_TMP_VAR & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're not identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) != Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return true. This has to check for __destruct errors (and undefined variable errors when IS_NULL is possible) */ + + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(1, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_CV & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_TMP_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(0, 1); + } + /* They are identical, return false. */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(0, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) != Z_LVAL_P(op2)); +free_nothrow: + + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) != Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) != Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = !zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = !zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) != Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); ZEND_VM_SMART_BRANCH(result, 1); @@ -43275,9 +44651,95 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_IDENTICAL_SPEC_CV_VAR_HANDL zend_bool result; SAVE_OPLINE(); - op1 = _get_zval_ptr_cv_deref_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC); - op2 = _get_zval_ptr_var_deref(opline->op2.var EXECUTE_DATA_CC); - result = fast_is_identical_function(op1, op2); + op1 = EX_VAR(opline->op1.var); + op2 = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_CV & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_VAR & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_CV & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_CV & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_VAR & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) == Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return false. This has to check for __destruct errors */ + + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(0, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_CV & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(1, 1); + } + /* They are identical, return true */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(1, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) == Z_LVAL_P(op2)); +free_nothrow: + + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) == Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) == Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) == Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); ZEND_VM_SMART_BRANCH(result, 1); @@ -43290,9 +44752,95 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_IDENTICAL_SPEC_CV_VAR_H zend_bool result; SAVE_OPLINE(); - op1 = _get_zval_ptr_cv_deref_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC); - op2 = _get_zval_ptr_var_deref(opline->op2.var EXECUTE_DATA_CC); - result = fast_is_not_identical_function(op1, op2); + op1 = EX_VAR(opline->op1.var); + op2 = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_CV & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_VAR & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_CV & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_CV & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_VAR & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're not identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) != Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return true. This has to check for __destruct errors (and undefined variable errors when IS_NULL is possible) */ + + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(1, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_CV & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_VAR & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(0, 1); + } + /* They are identical, return false. */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(0, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) != Z_LVAL_P(op2)); +free_nothrow: + + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) != Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) != Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = !zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = !zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) != Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); ZEND_VM_SMART_BRANCH(result, 1); @@ -44930,9 +46478,95 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_IDENTICAL_SPEC_CV_CV_HANDLE zend_bool result; SAVE_OPLINE(); - op1 = _get_zval_ptr_cv_deref_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC); - op2 = _get_zval_ptr_cv_deref_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); - result = fast_is_identical_function(op1, op2); + op1 = EX_VAR(opline->op1.var); + op2 = EX_VAR(opline->op2.var); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_CV & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_CV & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_CV & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_CV & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_CV & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_CV & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) == Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return false. This has to check for __destruct errors */ + + + ZEND_VM_SMART_BRANCH(0, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_CV & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_CV & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(1, 1); + } + /* They are identical, return true */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + + + ZEND_VM_SMART_BRANCH(1, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) == Z_LVAL_P(op2)); +free_nothrow: + + + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) == Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) == Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) == Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ ZEND_VM_SMART_BRANCH(result, 1); @@ -44945,9 +46579,95 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_IDENTICAL_SPEC_CV_CV_HA zend_bool result; SAVE_OPLINE(); - op1 = _get_zval_ptr_cv_deref_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC); - op2 = _get_zval_ptr_cv_deref_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); - result = fast_is_not_identical_function(op1, op2); + op1 = EX_VAR(opline->op1.var); + op2 = EX_VAR(opline->op2.var); +compare_values_any_type: + + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + /* Only VAR can be indirect */ + if (UNEXPECTED(((IS_CV & IS_VAR) && Z_TYPE_P(op1) == IS_INDIRECT) || ((IS_CV & IS_VAR) && Z_TYPE_P(op2) == IS_INDIRECT))) { + ZVAL_DEINDIRECT(op1); + ZVAL_DEINDIRECT(op2); + goto compare_values_any_type; + } + /* Only VAR and CV can be references */ + if (UNEXPECTED(((IS_CV & (IS_VAR|IS_CV)) && Z_ISREF_P(op1)) || ((IS_CV & (IS_VAR|IS_CV)) && Z_ISREF_P(op2)))) { + ZVAL_DEREF(op1); + ZVAL_DEREF(op2); + if (Z_TYPE_P(op1) == Z_TYPE_P(op2)) { + goto compare_values; + } + } + /* Only CV can be undef */ + if (UNEXPECTED(((IS_CV & IS_CV) && Z_ISUNDEF_P(op1)) || ((IS_CV & IS_CV) && Z_ISUNDEF_P(op2)) )) { + /* Convert undef to null, check if they're not identical */ + if (Z_TYPE_P(op1) == IS_UNDEF) { + op1 = ZVAL_UNDEFINED_OP1(); + } + if (Z_TYPE_P(op2) == IS_UNDEF) { + op2 = ZVAL_UNDEFINED_OP2(); + } + result = Z_TYPE_P(op1) != Z_TYPE_P(op2); + goto return_result_maythrow; + } + /* They are not identical, return true. This has to check for __destruct errors (and undefined variable errors when IS_NULL is possible) */ + + + ZEND_VM_SMART_BRANCH(1, 1); + } +compare_values: + if (Z_TYPE_P(op1) <= IS_TRUE) { + if (((IS_CV & IS_CV) && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) || ((IS_CV & IS_CV) && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF))) { + /* They are both undefined - fetch them to emit the undefined variable warnings. */ + op1 = ZVAL_UNDEFINED_OP1(); + op2 = ZVAL_UNDEFINED_OP2(); + ZEND_VM_SMART_BRANCH(0, 1); + } + /* They are identical, return false. */ + /* This has to check for undefined variable errors when IS_UNDEF is possible. (only warns for IS_CV) */ + + + ZEND_VM_SMART_BRANCH(0, 0); + } + switch (Z_TYPE_P(op1)) { + case IS_LONG: + result = (Z_LVAL_P(op1) != Z_LVAL_P(op2)); +free_nothrow: + + + ZEND_VM_SMART_BRANCH(result, 0); + break; + case IS_RESOURCE: + result = (Z_RES_P(op1) != Z_RES_P(op2)); + break; + case IS_DOUBLE: + result = (Z_DVAL_P(op1) != Z_DVAL_P(op2)); + goto free_nothrow; + case IS_STRING: + result = !zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); + goto free_nothrow; + case IS_ARRAY: + /* This may cause EG(exception) due to infinite nesting, but other zval types won't? */ + /* XXX hash_zval_identical_function is not static */ + result = !zend_is_identical_array(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2)); + break; + case IS_OBJECT: + result = (Z_OBJ_P(op1) != Z_OBJ_P(op2)); + break; + case IS_REFERENCE: + /* Both are references */ + op1 = Z_REFVAL_P(op1); + op2 = Z_REFVAL_P(op2); + goto compare_values_any_type; + case IS_INDIRECT: + op1 = Z_INDIRECT_P(op1); + op2 = Z_INDIRECT_P(op2); + goto compare_values_any_type; + default: + result = 1; + } +return_result_maythrow: + /* Check if freeing the operands (e.g. __destruct(), freeing resources (not sure about that), etc threw an exception before setting the result or branching */ ZEND_VM_SMART_BRANCH(result, 1);