diff options
author | Dmitry Stogov <dmitry@zend.com> | 2015-03-17 18:53:19 +0300 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2015-03-17 18:53:19 +0300 |
commit | 4d4a5336f149fc0d49ac8fa10f0f85fa364366ac (patch) | |
tree | 7a496c53ce0989c5aac1d396151713d7d52a80e8 | |
parent | fb4b7069842491eb66272587422a1f61d41eb869 (diff) | |
download | php-git-4d4a5336f149fc0d49ac8fa10f0f85fa364366ac.tar.gz |
Embed "fast" operator functions (add, sub, increment, etc) into executor with additional optimizations
-rw-r--r-- | Zend/zend_execute.c | 37 | ||||
-rw-r--r-- | Zend/zend_operators.c | 19 | ||||
-rw-r--r-- | Zend/zend_operators.h | 757 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 428 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 3530 | ||||
-rw-r--r-- | Zend/zend_vm_gen.php | 25 |
6 files changed, 3938 insertions, 858 deletions
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 17e68dc55d..42e9673744 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -53,6 +53,7 @@ typedef int (ZEND_FASTCALL *incdec_t)(zval *); #define get_zval_ptr(op_type, node, ex, should_free, type) _get_zval_ptr(op_type, node, ex, should_free, type) #define get_zval_ptr_deref(op_type, node, ex, should_free, type) _get_zval_ptr_deref(op_type, node, ex, should_free, type) +#define get_zval_ptr_undef(op_type, node, ex, should_free, type) _get_zval_ptr_undef(op_type, node, ex, should_free, type) #define get_zval_ptr_ptr(op_type, node, ex, should_free, type) _get_zval_ptr_ptr(op_type, node, ex, should_free, type) #define get_zval_ptr_ptr_undef(op_type, node, ex, should_free, type) _get_zval_ptr_ptr(op_type, node, ex, should_free, type) #define get_obj_zval_ptr(op_type, node, ex, should_free, type) _get_obj_zval_ptr(op_type, node, ex, should_free, type) @@ -283,6 +284,11 @@ static zend_always_inline zval *_get_zval_ptr_cv(const zend_execute_data *execut return ret; } +static zend_always_inline zval *_get_zval_ptr_cv_undef(const zend_execute_data *execute_data, uint32_t var) +{ + return EX_VAR(var); +} + static zend_always_inline zval *_get_zval_ptr_cv_deref(const zend_execute_data *execute_data, uint32_t var, int type) { zval *ret = EX_VAR(var); @@ -387,6 +393,11 @@ static zend_always_inline zval *_get_zval_ptr_cv_undef_BP_VAR_W(const zend_execu return EX_VAR(var); } +static zend_always_inline zval *_get_zval_ptr_cv_undef_BP_VAR_RW(const zend_execute_data *execute_data, uint32_t var) +{ + return EX_VAR(var); +} + static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_W(const zend_execute_data *execute_data, uint32_t var) { zval *ret = EX_VAR(var); @@ -440,6 +451,27 @@ static zend_always_inline zval *_get_zval_ptr_deref(int op_type, znode_op node, } } +static zend_always_inline zval *_get_zval_ptr_undef(int op_type, znode_op node, const zend_execute_data *execute_data, zend_free_op *should_free, int type) +{ + if (op_type & (IS_TMP_VAR|IS_VAR)) { + if (op_type == IS_TMP_VAR) { + return _get_zval_ptr_tmp(node.var, execute_data, should_free); + } else { + ZEND_ASSERT(op_type == IS_VAR); + return _get_zval_ptr_var(node.var, execute_data, should_free); + } + } else { + *should_free = NULL; + if (op_type == IS_CONST) { + return EX_CONSTANT(node); + } else if (op_type == IS_CV) { + return _get_zval_ptr_cv_undef(execute_data, node.var); + } else { + return NULL; + } + } +} + static zend_always_inline zval *_get_zval_ptr_ptr_var(uint32_t var, const zend_execute_data *execute_data, zend_free_op *should_free) { zval *ret = EX_VAR(var); @@ -2093,6 +2125,11 @@ static zend_always_inline void zend_vm_stack_extend_call_frame(zend_execute_data # define ZEND_VM_GUARD(name) #endif +#define GET_OP1_UNDEF_CV(ptr, type) \ + _get_zval_cv_lookup_ ## type(ptr, opline->op1.var, execute_data) +#define GET_OP2_UNDEF_CV(ptr, type) \ + _get_zval_cv_lookup_ ## type(ptr, opline->op2.var, execute_data) + #include "zend_vm_execute.h" ZEND_API int zend_set_user_opcode_handler(zend_uchar opcode, user_opcode_handler_t handler) diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 7c23489864..d8e92a97ad 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -2162,13 +2162,7 @@ ZEND_API int ZEND_FASTCALL increment_function(zval *op1) /* {{{ */ try_again: switch (Z_TYPE_P(op1)) { case IS_LONG: - if (Z_LVAL_P(op1) == ZEND_LONG_MAX) { - /* switch to double */ - double d = (double)Z_LVAL_P(op1); - ZVAL_DOUBLE(op1, d+1); - } else { - Z_LVAL_P(op1)++; - } + fast_long_increment_function(op1); break; case IS_DOUBLE: Z_DVAL_P(op1) = Z_DVAL_P(op1) + 1; @@ -2211,7 +2205,7 @@ try_again: val = Z_OBJ_HANDLER_P(op1, get)(op1, &rv); Z_ADDREF_P(val); - fast_increment_function(val); + increment_function(val); Z_OBJ_HANDLER_P(op1, set)(op1, val); zval_ptr_dtor(val); } else if (Z_OBJ_HANDLER_P(op1, do_operation)) { @@ -2243,12 +2237,7 @@ ZEND_API int ZEND_FASTCALL decrement_function(zval *op1) /* {{{ */ try_again: switch (Z_TYPE_P(op1)) { case IS_LONG: - if (Z_LVAL_P(op1) == ZEND_LONG_MIN) { - double d = (double)Z_LVAL_P(op1); - ZVAL_DOUBLE(op1, d-1); - } else { - Z_LVAL_P(op1)--; - } + fast_long_decrement_function(op1); break; case IS_DOUBLE: Z_DVAL_P(op1) = Z_DVAL_P(op1) - 1; @@ -2284,7 +2273,7 @@ try_again: val = Z_OBJ_HANDLER_P(op1, get)(op1, &rv); Z_ADDREF_P(val); - fast_decrement_function(val); + decrement_function(val); Z_OBJ_HANDLER_P(op1, set)(op1, val); zval_ptr_dtor(val); } else if (Z_OBJ_HANDLER_P(op1, do_operation)) { diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index b656e435b2..e2e9abfaae 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -435,238 +435,235 @@ ZEND_API void zend_update_current_locale(void); #define ZVAL_OFFSETOF_TYPE \ (offsetof(zval, u1.type_info) - offsetof(zval, value)) -static zend_always_inline int fast_increment_function(zval *op1) +static zend_always_inline void fast_long_increment_function(zval *op1) { - if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { #if defined(__GNUC__) && defined(__i386__) - __asm__( - "incl (%0)\n\t" - "jno 0f\n\t" - "movl $0x0, (%0)\n\t" - "movl $0x41e00000, 0x4(%0)\n\t" - "movl %1, %c2(%0)\n" - "0:" - : - : "r"(&op1->value), - "n"(IS_DOUBLE), - "n"(ZVAL_OFFSETOF_TYPE) - : "cc"); + __asm__( + "incl (%0)\n\t" + "jno 0f\n\t" + "movl $0x0, (%0)\n\t" + "movl $0x41e00000, 0x4(%0)\n\t" + "movl %1, %c2(%0)\n" + "0:" + : + : "r"(&op1->value), + "n"(IS_DOUBLE), + "n"(ZVAL_OFFSETOF_TYPE) + : "cc"); #elif defined(__GNUC__) && defined(__x86_64__) - __asm__( - "incq (%0)\n\t" - "jno 0f\n\t" - "movl $0x0, (%0)\n\t" - "movl $0x43e00000, 0x4(%0)\n\t" - "movl %1, %c2(%0)\n" - "0:" - : - : "r"(&op1->value), - "n"(IS_DOUBLE), - "n"(ZVAL_OFFSETOF_TYPE) - : "cc"); + __asm__( + "incq (%0)\n\t" + "jno 0f\n\t" + "movl $0x0, (%0)\n\t" + "movl $0x43e00000, 0x4(%0)\n\t" + "movl %1, %c2(%0)\n" + "0:" + : + : "r"(&op1->value), + "n"(IS_DOUBLE), + "n"(ZVAL_OFFSETOF_TYPE) + : "cc"); #elif defined(__GNUC__) && defined(__powerpc64__) - __asm__( - "ld 14, 0(%0)\n\t" - "li 15, 1\n\t" - "li 16, 0\n\t" - "mtxer 16\n\t" - "addo. 14, 14, 15\n\t" - "std 14, 0(%0)\n\t" - "bns+ 0f\n\t" - "xor 14, 14, 14\n\t" - "lis 15, 0x43e00000@h\n\t" - "ori 15, 15, 0x43e00000@l\n\t" + __asm__( + "ld 14, 0(%0)\n\t" + "li 15, 1\n\t" + "li 16, 0\n\t" + "mtxer 16\n\t" + "addo. 14, 14, 15\n\t" + "std 14, 0(%0)\n\t" + "bns+ 0f\n\t" + "xor 14, 14, 14\n\t" + "lis 15, 0x43e00000@h\n\t" + "ori 15, 15, 0x43e00000@l\n\t" #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - "stw 14, 0(%0)\n\t" - "stw 15, 0x4(%0)\n\t" + "stw 14, 0(%0)\n\t" + "stw 15, 0x4(%0)\n\t" #else - "stw 14, 0x4(%0)\n\t" - "stw 15, 0(%0)\n\t" + "stw 14, 0x4(%0)\n\t" + "stw 15, 0(%0)\n\t" #endif - "li 14, %1\n\t" - "stw 14, %c2(%0)\n" - "0:" - : - : "r"(&op1->value), - "n"(IS_DOUBLE), - "n"(ZVAL_OFFSETOF_TYPE) - : "r14", "r15", "r16", "cc"); + "li 14, %1\n\t" + "stw 14, %c2(%0)\n" + "0:" + : + : "r"(&op1->value), + "n"(IS_DOUBLE), + "n"(ZVAL_OFFSETOF_TYPE) + : "r14", "r15", "r16", "cc"); #else - if (UNEXPECTED(Z_LVAL_P(op1) == ZEND_LONG_MAX)) { - /* switch to double */ - ZVAL_DOUBLE(op1, (double)ZEND_LONG_MAX + 1.0); - } else { - Z_LVAL_P(op1)++; - } -#endif - return SUCCESS; + if (UNEXPECTED(Z_LVAL_P(op1) == ZEND_LONG_MAX)) { + /* switch to double */ + ZVAL_DOUBLE(op1, (double)ZEND_LONG_MAX + 1.0); + } else { + Z_LVAL_P(op1)++; } - return increment_function(op1); +#endif } -static zend_always_inline int fast_decrement_function(zval *op1) +static zend_always_inline void fast_long_decrement_function(zval *op1) { - if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { #if defined(__GNUC__) && defined(__i386__) - __asm__( - "decl (%0)\n\t" - "jno 0f\n\t" - "movl $0x00200000, (%0)\n\t" - "movl $0xc1e00000, 0x4(%0)\n\t" - "movl %1,%c2(%0)\n" - "0:" - : - : "r"(&op1->value), - "n"(IS_DOUBLE), - "n"(ZVAL_OFFSETOF_TYPE) - : "cc"); + __asm__( + "decl (%0)\n\t" + "jno 0f\n\t" + "movl $0x00200000, (%0)\n\t" + "movl $0xc1e00000, 0x4(%0)\n\t" + "movl %1,%c2(%0)\n" + "0:" + : + : "r"(&op1->value), + "n"(IS_DOUBLE), + "n"(ZVAL_OFFSETOF_TYPE) + : "cc"); #elif defined(__GNUC__) && defined(__x86_64__) - __asm__( - "decq (%0)\n\t" - "jno 0f\n\t" - "movl $0x00000000, (%0)\n\t" - "movl $0xc3e00000, 0x4(%0)\n\t" - "movl %1,%c2(%0)\n" - "0:" - : - : "r"(&op1->value), - "n"(IS_DOUBLE), - "n"(ZVAL_OFFSETOF_TYPE) - : "cc"); + __asm__( + "decq (%0)\n\t" + "jno 0f\n\t" + "movl $0x00000000, (%0)\n\t" + "movl $0xc3e00000, 0x4(%0)\n\t" + "movl %1,%c2(%0)\n" + "0:" + : + : "r"(&op1->value), + "n"(IS_DOUBLE), + "n"(ZVAL_OFFSETOF_TYPE) + : "cc"); #elif defined(__GNUC__) && defined(__powerpc64__) - __asm__( - "ld 14, 0(%0)\n\t" - "li 15, 1\n\t" - "li 16, 0\n\t" - "mtxer 16\n\t" - "subo. 14, 14, 15\n\t" - "std 14, 0(%0)\n\t" - "bns+ 0f\n\t" - "xor 14, 14, 14\n\t" - "lis 15, 0xc3e00000@h\n\t" - "ori 15, 15, 0xc3e00000@l\n\t" + __asm__( + "ld 14, 0(%0)\n\t" + "li 15, 1\n\t" + "li 16, 0\n\t" + "mtxer 16\n\t" + "subo. 14, 14, 15\n\t" + "std 14, 0(%0)\n\t" + "bns+ 0f\n\t" + "xor 14, 14, 14\n\t" + "lis 15, 0xc3e00000@h\n\t" + "ori 15, 15, 0xc3e00000@l\n\t" #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - "stw 14, 0(%0)\n\t" - "stw 15, 0x4(%0)\n\t" + "stw 14, 0(%0)\n\t" + "stw 15, 0x4(%0)\n\t" #else - "stw 14, 0x4(%0)\n\t" - "stw 15, 0(%0)\n\t" + "stw 14, 0x4(%0)\n\t" + "stw 15, 0(%0)\n\t" #endif - "li 14, %1\n\t" - "stw 14, %c2(%0)\n" - "0:" - : - : "r"(&op1->value), - "n"(IS_DOUBLE), - "n"(ZVAL_OFFSETOF_TYPE) - : "r14", "r15", "r16", "cc"); + "li 14, %1\n\t" + "stw 14, %c2(%0)\n" + "0:" + : + : "r"(&op1->value), + "n"(IS_DOUBLE), + "n"(ZVAL_OFFSETOF_TYPE) + : "r14", "r15", "r16", "cc"); #else - if (UNEXPECTED(Z_LVAL_P(op1) == ZEND_LONG_MIN)) { - /* switch to double */ - ZVAL_DOUBLE(op1, (double)ZEND_LONG_MIN - 1.0); - } else { - Z_LVAL_P(op1)--; - } -#endif - return SUCCESS; + if (UNEXPECTED(Z_LVAL_P(op1) == ZEND_LONG_MIN)) { + /* switch to double */ + ZVAL_DOUBLE(op1, (double)ZEND_LONG_MIN - 1.0); + } else { + Z_LVAL_P(op1)--; } - return decrement_function(op1); +#endif } -static zend_always_inline int fast_add_function(zval *result, zval *op1, zval *op2) +static zend_always_inline void fast_long_add_function(zval *result, zval *op1, zval *op2) { - if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { #if defined(__GNUC__) && defined(__i386__) - __asm__( - "movl (%1), %%eax\n\t" - "addl (%2), %%eax\n\t" - "jo 0f\n\t" - "movl %%eax, (%0)\n\t" - "movl %3, %c5(%0)\n\t" - "jmp 1f\n" - "0:\n\t" - "fildl (%1)\n\t" - "fildl (%2)\n\t" - "faddp %%st, %%st(1)\n\t" - "movl %4, %c5(%0)\n\t" - "fstpl (%0)\n" - "1:" - : - : "r"(&result->value), - "r"(&op1->value), - "r"(&op2->value), - "n"(IS_LONG), - "n"(IS_DOUBLE), - "n"(ZVAL_OFFSETOF_TYPE) - : "eax","cc"); + __asm__( + "movl (%1), %%eax\n\t" + "addl (%2), %%eax\n\t" + "jo 0f\n\t" + "movl %%eax, (%0)\n\t" + "movl %3, %c5(%0)\n\t" + "jmp 1f\n" + "0:\n\t" + "fildl (%1)\n\t" + "fildl (%2)\n\t" + "faddp %%st, %%st(1)\n\t" + "movl %4, %c5(%0)\n\t" + "fstpl (%0)\n" + "1:" + : + : "r"(&result->value), + "r"(&op1->value), + "r"(&op2->value), + "n"(IS_LONG), + "n"(IS_DOUBLE), + "n"(ZVAL_OFFSETOF_TYPE) + : "eax","cc"); #elif defined(__GNUC__) && defined(__x86_64__) - __asm__( - "movq (%1), %%rax\n\t" - "addq (%2), %%rax\n\t" - "jo 0f\n\t" - "movq %%rax, (%0)\n\t" - "movl %3, %c5(%0)\n\t" - "jmp 1f\n" - "0:\n\t" - "fildq (%1)\n\t" - "fildq (%2)\n\t" - "faddp %%st, %%st(1)\n\t" - "movl %4, %c5(%0)\n\t" - "fstpl (%0)\n" - "1:" - : - : "r"(&result->value), - "r"(&op1->value), - "r"(&op2->value), - "n"(IS_LONG), - "n"(IS_DOUBLE), - "n"(ZVAL_OFFSETOF_TYPE) - : "rax","cc"); + __asm__( + "movq (%1), %%rax\n\t" + "addq (%2), %%rax\n\t" + "jo 0f\n\t" + "movq %%rax, (%0)\n\t" + "movl %3, %c5(%0)\n\t" + "jmp 1f\n" + "0:\n\t" + "fildq (%1)\n\t" + "fildq (%2)\n\t" + "faddp %%st, %%st(1)\n\t" + "movl %4, %c5(%0)\n\t" + "fstpl (%0)\n" + "1:" + : + : "r"(&result->value), + "r"(&op1->value), + "r"(&op2->value), + "n"(IS_LONG), + "n"(IS_DOUBLE), + "n"(ZVAL_OFFSETOF_TYPE) + : "rax","cc"); #elif defined(__GNUC__) && defined(__powerpc64__) - __asm__( - "ld 14, 0(%1)\n\t" - "ld 15, 0(%2)\n\t" - "li 16, 0 \n\t" - "mtxer 16\n\t" - "addo. 14, 14, 15\n\t" - "bso- 0f\n\t" - "std 14, 0(%0)\n\t" - "li 14, %3\n\t" - "stw 14, %c5(%0)\n\t" - "b 1f\n" - "0:\n\t" - "lfd 0, 0(%1)\n\t" - "lfd 1, 0(%2)\n\t" - "fcfid 0, 0\n\t" - "fcfid 1, 1\n\t" - "fadd 0, 0, 1\n\t" - "li 14, %4\n\t" - "stw 14, %c5(%0)\n\t" - "stfd 0, 0(%0)\n" - "1:" - : - : "r"(&result->value), - "r"(&op1->value), - "r"(&op2->value), - "n"(IS_LONG), - "n"(IS_DOUBLE), - "n"(ZVAL_OFFSETOF_TYPE) - : "r14","r15","r16","fr0","fr1","cc"); + __asm__( + "ld 14, 0(%1)\n\t" + "ld 15, 0(%2)\n\t" + "li 16, 0 \n\t" + "mtxer 16\n\t" + "addo. 14, 14, 15\n\t" + "bso- 0f\n\t" + "std 14, 0(%0)\n\t" + "li 14, %3\n\t" + "stw 14, %c5(%0)\n\t" + "b 1f\n" + "0:\n\t" + "lfd 0, 0(%1)\n\t" + "lfd 1, 0(%2)\n\t" + "fcfid 0, 0\n\t" + "fcfid 1, 1\n\t" + "fadd 0, 0, 1\n\t" + "li 14, %4\n\t" + "stw 14, %c5(%0)\n\t" + "stfd 0, 0(%0)\n" + "1:" + : + : "r"(&result->value), + "r"(&op1->value), + "r"(&op2->value), + "n"(IS_LONG), + "n"(IS_DOUBLE), + "n"(ZVAL_OFFSETOF_TYPE) + : "r14","r15","r16","fr0","fr1","cc"); #else - /* - * 'result' may alias with op1 or op2, so we need to - * ensure that 'result' is not updated until after we - * have read the values of op1 and op2. - */ - - if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK) - && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != ((Z_LVAL_P(op1) + Z_LVAL_P(op2)) & LONG_SIGN_MASK))) { - ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2)); - } else { - ZVAL_LONG(result, Z_LVAL_P(op1) + Z_LVAL_P(op2)); - } + /* + * 'result' may alias with op1 or op2, so we need to + * ensure that 'result' is not updated until after we + * have read the values of op1 and op2. + */ + + if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK) + && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != ((Z_LVAL_P(op1) + Z_LVAL_P(op2)) & LONG_SIGN_MASK))) { + ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2)); + } else { + ZVAL_LONG(result, Z_LVAL_P(op1) + Z_LVAL_P(op2)); + } #endif +} + +static zend_always_inline int fast_add_function(zval *result, zval *op1, zval *op2) +{ + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + fast_long_add_function(result, op1, op2); return SUCCESS; } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2)); @@ -684,142 +681,100 @@ static zend_always_inline int fast_add_function(zval *result, zval *op1, zval *o return add_function(result, op1, op2); } -static zend_always_inline int fast_sub_function(zval *result, zval *op1, zval *op2) +static zend_always_inline void fast_long_sub_function(zval *result, zval *op1, zval *op2) { - if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { #if defined(__GNUC__) && defined(__i386__) - __asm__( - "movl (%1), %%eax\n\t" - "subl (%2), %%eax\n\t" - "jo 0f\n\t" - "movl %%eax, (%0)\n\t" - "movl %3, %c5(%0)\n\t" - "jmp 1f\n" - "0:\n\t" - "fildl (%2)\n\t" - "fildl (%1)\n\t" + __asm__( + "movl (%1), %%eax\n\t" + "subl (%2), %%eax\n\t" + "jo 0f\n\t" + "movl %%eax, (%0)\n\t" + "movl %3, %c5(%0)\n\t" + "jmp 1f\n" + "0:\n\t" + "fildl (%2)\n\t" + "fildl (%1)\n\t" #if defined(__clang__) && (__clang_major__ < 2 || (__clang_major__ == 2 && __clang_minor__ < 10)) - "fsubp %%st(1), %%st\n\t" /* LLVM bug #9164 */ + "fsubp %%st(1), %%st\n\t" /* LLVM bug #9164 */ #else - "fsubp %%st, %%st(1)\n\t" + "fsubp %%st, %%st(1)\n\t" #endif - "movl %4, %c5(%0)\n\t" - "fstpl (%0)\n" - "1:" - : - : "r"(&result->value), - "r"(&op1->value), - "r"(&op2->value), - "n"(IS_LONG), - "n"(IS_DOUBLE), - "n"(ZVAL_OFFSETOF_TYPE) - : "eax","cc"); + "movl %4, %c5(%0)\n\t" + "fstpl (%0)\n" + "1:" + : + : "r"(&result->value), + "r"(&op1->value), + "r"(&op2->value), + "n"(IS_LONG), + "n"(IS_DOUBLE), + "n"(ZVAL_OFFSETOF_TYPE) + : "eax","cc"); #elif defined(__GNUC__) && defined(__x86_64__) - __asm__( - "movq (%1), %%rax\n\t" - "subq (%2), %%rax\n\t" - "jo 0f\n\t" - "movq %%rax, (%0)\n\t" - "movl %3, %c5(%0)\n\t" - "jmp 1f\n" - "0:\n\t" - "fildq (%2)\n\t" - "fildq (%1)\n\t" + __asm__( + "movq (%1), %%rax\n\t" + "subq (%2), %%rax\n\t" + "jo 0f\n\t" + "movq %%rax, (%0)\n\t" + "movl %3, %c5(%0)\n\t" + "jmp 1f\n" + "0:\n\t" + "fildq (%2)\n\t" + "fildq (%1)\n\t" #if defined(__clang__) && (__clang_major__ < 2 || (__clang_major__ == 2 && __clang_minor__ < 10)) - "fsubp %%st(1), %%st\n\t" /* LLVM bug #9164 */ + "fsubp %%st(1), %%st\n\t" /* LLVM bug #9164 */ #else - "fsubp %%st, %%st(1)\n\t" + "fsubp %%st, %%st(1)\n\t" #endif - "movl %4, %c5(%0)\n\t" - "fstpl (%0)\n" - "1:" - : - : "r"(&result->value), - "r"(&op1->value), - "r"(&op2->value), - "n"(IS_LONG), - "n"(IS_DOUBLE), - "n"(ZVAL_OFFSETOF_TYPE) - : "rax","cc"); + "movl %4, %c5(%0)\n\t" + "fstpl (%0)\n" + "1:" + : + : "r"(&result->value), + "r"(&op1->value), + "r"(&op2->value), + "n"(IS_LONG), + "n"(IS_DOUBLE), + "n"(ZVAL_OFFSETOF_TYPE) + : "rax","cc"); #elif defined(__GNUC__) && defined(__powerpc64__) - __asm__( - "ld 14, 0(%1)\n\t" - "ld 15, 0(%2)\n\t" - "li 16, 0\n\t" - "mtxer 16\n\t" - "subo. 14, 14, 15\n\t" - "bso- 0f\n\t" - "std 14, 0(%0)\n\t" - "li 14, %3\n\t" - "stw 14, %c5(%0)\n\t" - "b 1f\n" - "0:\n\t" - "lfd 0, 0(%1)\n\t" - "lfd 1, 0(%2)\n\t" - "fcfid 0, 0\n\t" - "fcfid 1, 1\n\t" - "fsub 0, 0, 1\n\t" - "li 14, %4\n\t" - "stw 14, %c5(%0)\n\t" - "stfd 0, 0(%0)\n" - "1:" - : - : "r"(&result->value), - "r"(&op1->value), - "r"(&op2->value), - "n"(IS_LONG), - "n"(IS_DOUBLE), - "n"(ZVAL_OFFSETOF_TYPE) - : "r14","r15","r16","fr0","fr1","cc"); + __asm__( + "ld 14, 0(%1)\n\t" + "ld 15, 0(%2)\n\t" + "li 16, 0\n\t" + "mtxer 16\n\t" + "subo. 14, 14, 15\n\t" + "bso- 0f\n\t" + "std 14, 0(%0)\n\t" + "li 14, %3\n\t" + "stw 14, %c5(%0)\n\t" + "b 1f\n" + "0:\n\t" + "lfd 0, 0(%1)\n\t" + "lfd 1, 0(%2)\n\t" + "fcfid 0, 0\n\t" + "fcfid 1, 1\n\t" + "fsub 0, 0, 1\n\t" + "li 14, %4\n\t" + "stw 14, %c5(%0)\n\t" + "stfd 0, 0(%0)\n" + "1:" + : + : "r"(&result->value), + "r"(&op1->value), + "r"(&op2->value), + "n"(IS_LONG), + "n"(IS_DOUBLE), + "n"(ZVAL_OFFSETOF_TYPE) + : "r14","r15","r16","fr0","fr1","cc"); #else - ZVAL_LONG(result, Z_LVAL_P(op1) - Z_LVAL_P(op2)); + ZVAL_LONG(result, Z_LVAL_P(op1) - Z_LVAL_P(op2)); - if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(op2) & LONG_SIGN_MASK) - && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(result) & LONG_SIGN_MASK))) { - ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2)); - } -#endif - return SUCCESS; - } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2)); - return SUCCESS; - } - } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2)); - return SUCCESS; - } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - ZVAL_DOUBLE(result, Z_DVAL_P(op1) - ((double)Z_LVAL_P(op2))); - return SUCCESS; - } - } - return sub_function(result, op1, op2); -} - -static zend_always_inline int fast_mul_function(zval *result, zval *op1, zval *op2) -{ - if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - zend_long overflow; - - ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1), Z_LVAL_P(op2), Z_LVAL_P(result), Z_DVAL_P(result), overflow); - Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG; - return SUCCESS; - } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2)); - return SUCCESS; - } - } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2)); - return SUCCESS; - } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2))); - return SUCCESS; - } + if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(op2) & LONG_SIGN_MASK) + && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(result) & LONG_SIGN_MASK))) { + ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2)); } - return mul_function(result, op1, op2); +#endif } static zend_always_inline int fast_div_function(zval *result, zval *op1, zval *op2) @@ -873,26 +828,6 @@ static zend_always_inline int fast_div_function(zval *result, zval *op1, zval *o return div_function(result, op1, op2); } -static zend_always_inline int fast_mod_function(zval *result, zval *op1, zval *op2) -{ - if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - if (UNEXPECTED(Z_LVAL_P(op2) == 0)) { - zend_error(E_WARNING, "Division by zero"); - ZVAL_FALSE(result); - return FAILURE; - } else if (UNEXPECTED(Z_LVAL_P(op2) == -1)) { - /* Prevent overflow error/crash if op1==ZEND_LONG_MIN */ - ZVAL_LONG(result, 0); - return SUCCESS; - } - ZVAL_LONG(result, Z_LVAL_P(op1) % Z_LVAL_P(op2)); - return SUCCESS; - } - } - return mod_function(result, op1, op2); -} - static zend_always_inline int fast_equal_check_function(zval *op1, zval *op2) { zval result; @@ -957,134 +892,6 @@ static zend_always_inline int fast_equal_check_string(zval *op1, zval *op2) return Z_LVAL(result) == 0; } -static zend_always_inline void fast_equal_function(zval *result, zval *op1, zval *op2) -{ - if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - ZVAL_BOOL(result, Z_LVAL_P(op1) == Z_LVAL_P(op2)); - return; - } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - ZVAL_BOOL(result, (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); - return; - } - } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - ZVAL_BOOL(result, Z_DVAL_P(op1) == Z_DVAL_P(op2)); - return; - } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - ZVAL_BOOL(result, Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); - return; - } - } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { - if (Z_STR_P(op1) == Z_STR_P(op2)) { - ZVAL_TRUE(result); - return; - } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { - if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { - ZVAL_FALSE(result); - return; - } else { - ZVAL_BOOL(result, memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); - return; - } - } else { - ZVAL_BOOL(result, zendi_smart_strcmp(op1, op2) == 0); - return; - } - } - } - compare_function(result, op1, op2); - ZVAL_BOOL(result, Z_LVAL_P(result) == 0); -} - -static zend_always_inline void fast_not_equal_function(zval *result, zval *op1, zval *op2) -{ - if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - ZVAL_BOOL(result, Z_LVAL_P(op1) != Z_LVAL_P(op2)); - return; - } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - ZVAL_BOOL(result, (double)Z_LVAL_P(op1) != Z_DVAL_P(op2)); - return; - } - } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - ZVAL_BOOL(result, Z_DVAL_P(op1) != Z_DVAL_P(op2)); - return; - } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - ZVAL_BOOL(result, Z_DVAL_P(op1) != ((double)Z_LVAL_P(op2))); - return; - } - } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { - if (Z_STR_P(op1) == Z_STR_P(op2)) { - ZVAL_FALSE(result); - return; - } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { - if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { - ZVAL_TRUE(result); - return; - } else { - ZVAL_BOOL(result, memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) != 0); - return; - } - } else { - ZVAL_BOOL(result, zendi_smart_strcmp(op1, op2) != 0); - return; - } - } - } - compare_function(result, op1, op2); - ZVAL_BOOL(result, Z_LVAL_P(result) != 0); -} - -static zend_always_inline void fast_is_smaller_function(zval *result, zval *op1, zval *op2) -{ - if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - ZVAL_BOOL(result, Z_LVAL_P(op1) < Z_LVAL_P(op2)); - return; - } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - ZVAL_BOOL(result, (double)Z_LVAL_P(op1) < Z_DVAL_P(op2)); - return; - } - } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - ZVAL_BOOL(result, Z_DVAL_P(op1) < Z_DVAL_P(op2)); - return; - } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - ZVAL_BOOL(result, Z_DVAL_P(op1) < ((double)Z_LVAL_P(op2))); - return; - } - } - compare_function(result, op1, op2); - ZVAL_BOOL(result, Z_LVAL_P(result) < 0); -} - -static zend_always_inline void fast_is_smaller_or_equal_function(zval *result, zval *op1, zval *op2) -{ - if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - ZVAL_BOOL(result, Z_LVAL_P(op1) <= Z_LVAL_P(op2)); - return; - } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - ZVAL_BOOL(result, (double)Z_LVAL_P(op1) <= Z_DVAL_P(op2)); - return; - } - } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - ZVAL_BOOL(result, Z_DVAL_P(op1) <= Z_DVAL_P(op2)); - return; - } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - ZVAL_BOOL(result, Z_DVAL_P(op1) <= ((double)Z_LVAL_P(op2))); - return; - } - } - compare_function(result, op1, op2); - ZVAL_BOOL(result, Z_LVAL_P(result) <= 0); -} - static zend_always_inline void fast_is_identical_function(zval *result, zval *op1, zval *op2) { if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index c6fff78158..079231b8cc 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -29,11 +29,40 @@ ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMPVAR|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; + zval *op1, *op2, *result; + + op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_add_function(EX_VAR(opline->result.var), - GET_OP1_ZVAL_PTR(BP_VAR_R), - GET_OP2_ZVAL_PTR(BP_VAR_R)); + 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); + } + add_function(EX_VAR(opline->result.var), op1, op2); FREE_OP1(); FREE_OP2(); CHECK_EXCEPTION(); @@ -44,11 +73,40 @@ ZEND_VM_HANDLER(2, ZEND_SUB, CONST|TMPVAR|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; + zval *op1, *op2, *result; + + op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_sub_function(EX_VAR(opline->result.var), - GET_OP1_ZVAL_PTR(BP_VAR_R), - GET_OP2_ZVAL_PTR(BP_VAR_R)); + 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); + } + sub_function(EX_VAR(opline->result.var), op1, op2); FREE_OP1(); FREE_OP2(); CHECK_EXCEPTION(); @@ -59,11 +117,43 @@ ZEND_VM_HANDLER(3, ZEND_MUL, CONST|TMPVAR|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; + zval *op1, *op2, *result; + + op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + zend_long overflow; + + result = EX_VAR(opline->result.var); + ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1), Z_LVAL_P(op2), Z_LVAL_P(result), Z_DVAL_P(result), overflow); + Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG; + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_mul_function(EX_VAR(opline->result.var), - GET_OP1_ZVAL_PTR(BP_VAR_R), - GET_OP2_ZVAL_PTR(BP_VAR_R)); + 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); + } + mul_function(EX_VAR(opline->result.var), op1, op2); FREE_OP1(); FREE_OP2(); CHECK_EXCEPTION(); @@ -89,11 +179,36 @@ ZEND_VM_HANDLER(5, ZEND_MOD, CONST|TMPVAR|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; + zval *op1, *op2, *result; + + op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + result = EX_VAR(opline->result.var); + if (UNEXPECTED(Z_LVAL_P(op2) == 0)) { + // TODO: change into exception ??? + SAVE_OPLINE(); + zend_error(E_WARNING, "Division by zero"); + ZVAL_FALSE(result); + } else if (UNEXPECTED(Z_LVAL_P(op2) == -1)) { + /* Prevent overflow error/crash if op1==ZEND_LONG_MIN */ + ZVAL_LONG(result, 0); + } else { + ZVAL_LONG(result, Z_LVAL_P(op1) % Z_LVAL_P(op2)); + } + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_mod_function(EX_VAR(opline->result.var), - GET_OP1_ZVAL_PTR(BP_VAR_R), - GET_OP2_ZVAL_PTR(BP_VAR_R)); + 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); + } + mod_function(EX_VAR(opline->result.var), op1, op2); FREE_OP1(); FREE_OP2(); CHECK_EXCEPTION(); @@ -180,12 +295,64 @@ ZEND_VM_HANDLER(17, ZEND_IS_EQUAL, CONST|TMPVAR|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + FREE_OP1(); + FREE_OP2(); + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + FREE_OP1(); + FREE_OP2(); + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + FREE_OP1(); + FREE_OP2(); + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + FREE_OP1(); + FREE_OP2(); + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_equal_function(result, - GET_OP1_ZVAL_PTR(BP_VAR_R), - GET_OP2_ZVAL_PTR(BP_VAR_R)); + 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_OP1(); FREE_OP2(); CHECK_EXCEPTION(); @@ -196,12 +363,64 @@ ZEND_VM_HANDLER(18, ZEND_IS_NOT_EQUAL, CONST|TMPVAR|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) != Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + FREE_OP1(); + FREE_OP2(); + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + FREE_OP1(); + FREE_OP2(); + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) != 0); + FREE_OP1(); + FREE_OP2(); + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) != 0); + FREE_OP1(); + FREE_OP2(); + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_not_equal_function(result, - GET_OP1_ZVAL_PTR(BP_VAR_R), - GET_OP2_ZVAL_PTR(BP_VAR_R)); + 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_OP1(); FREE_OP2(); CHECK_EXCEPTION(); @@ -212,12 +431,38 @@ ZEND_VM_HANDLER(19, ZEND_IS_SMALLER, CONST|TMPVAR|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) < Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_function(result, - GET_OP1_ZVAL_PTR(BP_VAR_R), - GET_OP2_ZVAL_PTR(BP_VAR_R)); + 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_OP1(); FREE_OP2(); CHECK_EXCEPTION(); @@ -228,12 +473,38 @@ ZEND_VM_HANDLER(20, ZEND_IS_SMALLER_OR_EQUAL, CONST|TMPVAR|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) <= Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_or_equal_function(result, - GET_OP1_ZVAL_PTR(BP_VAR_R), - GET_OP2_ZVAL_PTR(BP_VAR_R)); + 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_OP1(); FREE_OP2(); CHECK_EXCEPTION(); @@ -961,17 +1232,17 @@ ZEND_VM_HANDLER(34, ZEND_PRE_INC, VAR|CV, ANY) zend_free_op free_op1; zval *var_ptr; - SAVE_OPLINE(); - var_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW); + var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == NULL)) { + SAVE_OPLINE(); zend_error(E_EXCEPTION | E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); FREE_OP1_VAR_PTR(); HANDLE_EXCEPTION(); } if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { - fast_increment_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); } @@ -982,10 +1253,13 @@ ZEND_VM_HANDLER(34, ZEND_PRE_INC, VAR|CV, ANY) if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } + 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_DEREF(var_ptr); SEPARATE_ZVAL_NOREF(var_ptr); @@ -1006,17 +1280,17 @@ ZEND_VM_HANDLER(35, ZEND_PRE_DEC, VAR|CV, ANY) zend_free_op free_op1; zval *var_ptr; - SAVE_OPLINE(); - var_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW); + var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == NULL)) { + SAVE_OPLINE(); zend_error(E_EXCEPTION | E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); FREE_OP1_VAR_PTR(); HANDLE_EXCEPTION(); } if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { - fast_decrement_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); } @@ -1027,10 +1301,13 @@ ZEND_VM_HANDLER(35, ZEND_PRE_DEC, VAR|CV, ANY) if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } + 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_DEREF(var_ptr); SEPARATE_ZVAL_NOREF(var_ptr); @@ -1051,10 +1328,10 @@ ZEND_VM_HANDLER(36, ZEND_POST_INC, VAR|CV, ANY) zend_free_op free_op1; zval *var_ptr; - SAVE_OPLINE(); - var_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW); + var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == NULL)) { + SAVE_OPLINE(); zend_error(E_EXCEPTION | E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); FREE_OP1_VAR_PTR(); HANDLE_EXCEPTION(); @@ -1062,16 +1339,19 @@ ZEND_VM_HANDLER(36, ZEND_POST_INC, VAR|CV, ANY) if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); - fast_increment_function(var_ptr); + fast_long_increment_function(var_ptr); ZEND_VM_NEXT_OPCODE(); } if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { ZVAL_NULL(EX_VAR(opline->result.var)); - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } + 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_DEREF(var_ptr); ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); zval_opt_copy_ctor(var_ptr); @@ -1089,10 +1369,10 @@ ZEND_VM_HANDLER(37, ZEND_POST_DEC, VAR|CV, ANY) zend_free_op free_op1; zval *var_ptr; - SAVE_OPLINE(); - var_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW); + var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == NULL)) { + SAVE_OPLINE(); zend_error(E_EXCEPTION | E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); FREE_OP1_VAR_PTR(); HANDLE_EXCEPTION(); @@ -1100,16 +1380,19 @@ ZEND_VM_HANDLER(37, ZEND_POST_DEC, VAR|CV, ANY) if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); - fast_decrement_function(var_ptr); + fast_long_decrement_function(var_ptr); ZEND_VM_NEXT_OPCODE(); } if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { ZVAL_NULL(EX_VAR(opline->result.var)); - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } + 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_DEREF(var_ptr); ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); zval_opt_copy_ctor(var_ptr); @@ -4210,13 +4493,60 @@ ZEND_VM_HANDLER(48, ZEND_CASE, CONST|TMPVAR|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; - SAVE_OPLINE(); - fast_equal_function(result, - GET_OP1_ZVAL_PTR(BP_VAR_R), - GET_OP2_ZVAL_PTR(BP_VAR_R)); + op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + FREE_OP2(); + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + FREE_OP2(); + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + FREE_OP2(); + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + FREE_OP2(); + ZEND_VM_NEXT_OPCODE(); + } + } + } + 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(); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index a9ad8deec4..9dcf0ad462 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3865,11 +3865,40 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_CONST_CONST_HANDLER(Z { USE_OPLINE + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_add_function(EX_VAR(opline->result.var), - EX_CONSTANT(opline->op1), - EX_CONSTANT(opline->op2)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + add_function(EX_VAR(opline->result.var), op1, op2); CHECK_EXCEPTION(); @@ -3880,11 +3909,40 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_CONST_CONST_HANDLER(Z { USE_OPLINE + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_sub_function(EX_VAR(opline->result.var), - EX_CONSTANT(opline->op1), - EX_CONSTANT(opline->op2)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + sub_function(EX_VAR(opline->result.var), op1, op2); CHECK_EXCEPTION(); @@ -3895,11 +3953,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MUL_SPEC_CONST_CONST_HANDLER(Z { USE_OPLINE + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + zend_long overflow; + + result = EX_VAR(opline->result.var); + ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1), Z_LVAL_P(op2), Z_LVAL_P(result), Z_DVAL_P(result), overflow); + Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG; + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_mul_function(EX_VAR(opline->result.var), - EX_CONSTANT(opline->op1), - EX_CONSTANT(opline->op2)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + mul_function(EX_VAR(opline->result.var), op1, op2); CHECK_EXCEPTION(); @@ -3925,11 +4015,36 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MOD_SPEC_CONST_CONST_HANDLER(Z { USE_OPLINE + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + result = EX_VAR(opline->result.var); + if (UNEXPECTED(Z_LVAL_P(op2) == 0)) { + // TODO: change into exception ??? + SAVE_OPLINE(); + zend_error(E_WARNING, "Division by zero"); + ZVAL_FALSE(result); + } else if (UNEXPECTED(Z_LVAL_P(op2) == -1)) { + /* Prevent overflow error/crash if op1==ZEND_LONG_MIN */ + ZVAL_LONG(result, 0); + } else { + ZVAL_LONG(result, Z_LVAL_P(op1) % Z_LVAL_P(op2)); + } + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_mod_function(EX_VAR(opline->result.var), - EX_CONSTANT(opline->op1), - EX_CONSTANT(opline->op2)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + mod_function(EX_VAR(opline->result.var), op1, op2); CHECK_EXCEPTION(); @@ -4016,12 +4131,64 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CONST_CONST_HAND { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + + + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + + + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + + + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_equal_function(result, - EX_CONSTANT(opline->op1), - EX_CONSTANT(opline->op2)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == 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); CHECK_EXCEPTION(); @@ -4032,12 +4199,64 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CONST_CONST_ { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) != Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + + + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) != 0); + + + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) != 0); + + + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_not_equal_function(result, - EX_CONSTANT(opline->op1), - EX_CONSTANT(opline->op2)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == 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); CHECK_EXCEPTION(); @@ -4048,12 +4267,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_CONST_CONST_HA { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) < Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_function(result, - EX_CONSTANT(opline->op1), - EX_CONSTANT(opline->op2)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == 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); CHECK_EXCEPTION(); @@ -4064,12 +4309,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_CONST { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) <= Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_or_equal_function(result, - EX_CONSTANT(opline->op1), - EX_CONSTANT(opline->op2)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == 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); CHECK_EXCEPTION(); @@ -4800,12 +5071,60 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CASE_SPEC_CONST_CONST_HANDLER( { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_equal_function(result, - EX_CONSTANT(opline->op1), - EX_CONSTANT(opline->op2)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == 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); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -7073,11 +7392,40 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_CONST_CV_HANDLER(ZEND { USE_OPLINE + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_add_function(EX_VAR(opline->result.var), - EX_CONSTANT(opline->op1), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + add_function(EX_VAR(opline->result.var), op1, op2); CHECK_EXCEPTION(); @@ -7088,11 +7436,40 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_CONST_CV_HANDLER(ZEND { USE_OPLINE + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_sub_function(EX_VAR(opline->result.var), - EX_CONSTANT(opline->op1), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + sub_function(EX_VAR(opline->result.var), op1, op2); CHECK_EXCEPTION(); @@ -7103,11 +7480,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MUL_SPEC_CONST_CV_HANDLER(ZEND { USE_OPLINE + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + zend_long overflow; + + result = EX_VAR(opline->result.var); + ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1), Z_LVAL_P(op2), Z_LVAL_P(result), Z_DVAL_P(result), overflow); + Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG; + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_mul_function(EX_VAR(opline->result.var), - EX_CONSTANT(opline->op1), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + mul_function(EX_VAR(opline->result.var), op1, op2); CHECK_EXCEPTION(); @@ -7133,11 +7542,36 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MOD_SPEC_CONST_CV_HANDLER(ZEND { USE_OPLINE + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + result = EX_VAR(opline->result.var); + if (UNEXPECTED(Z_LVAL_P(op2) == 0)) { + // TODO: change into exception ??? + SAVE_OPLINE(); + zend_error(E_WARNING, "Division by zero"); + ZVAL_FALSE(result); + } else if (UNEXPECTED(Z_LVAL_P(op2) == -1)) { + /* Prevent overflow error/crash if op1==ZEND_LONG_MIN */ + ZVAL_LONG(result, 0); + } else { + ZVAL_LONG(result, Z_LVAL_P(op1) % Z_LVAL_P(op2)); + } + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_mod_function(EX_VAR(opline->result.var), - EX_CONSTANT(opline->op1), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + mod_function(EX_VAR(opline->result.var), op1, op2); CHECK_EXCEPTION(); @@ -7224,12 +7658,64 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CONST_CV_HANDLER { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + + + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + + + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + + + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_equal_function(result, - EX_CONSTANT(opline->op1), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == 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); CHECK_EXCEPTION(); @@ -7240,12 +7726,64 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CONST_CV_HAN { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) != Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + + + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) != 0); + + + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) != 0); + + + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_not_equal_function(result, - EX_CONSTANT(opline->op1), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == 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); CHECK_EXCEPTION(); @@ -7256,12 +7794,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_CONST_CV_HANDL { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) < Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_function(result, - EX_CONSTANT(opline->op1), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == 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); CHECK_EXCEPTION(); @@ -7272,12 +7836,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_CONST { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) <= Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_or_equal_function(result, - EX_CONSTANT(opline->op1), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == 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); CHECK_EXCEPTION(); @@ -7850,12 +8440,60 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CASE_SPEC_CONST_CV_HANDLER(ZEN { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_equal_function(result, - EX_CONSTANT(opline->op1), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == 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); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -8296,11 +8934,40 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_CONST_TMPVAR_HANDLER( { USE_OPLINE zend_free_op free_op2; + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_add_function(EX_VAR(opline->result.var), - EX_CONSTANT(opline->op1), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + add_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -8311,11 +8978,40 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_CONST_TMPVAR_HANDLER( { USE_OPLINE zend_free_op free_op2; + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_sub_function(EX_VAR(opline->result.var), - EX_CONSTANT(opline->op1), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + sub_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -8326,11 +9022,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MUL_SPEC_CONST_TMPVAR_HANDLER( { USE_OPLINE zend_free_op free_op2; + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + zend_long overflow; + + result = EX_VAR(opline->result.var); + ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1), Z_LVAL_P(op2), Z_LVAL_P(result), Z_DVAL_P(result), overflow); + Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG; + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_mul_function(EX_VAR(opline->result.var), - EX_CONSTANT(opline->op1), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + mul_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -8356,11 +9084,36 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MOD_SPEC_CONST_TMPVAR_HANDLER( { USE_OPLINE zend_free_op free_op2; + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + result = EX_VAR(opline->result.var); + if (UNEXPECTED(Z_LVAL_P(op2) == 0)) { + // TODO: change into exception ??? + SAVE_OPLINE(); + zend_error(E_WARNING, "Division by zero"); + ZVAL_FALSE(result); + } else if (UNEXPECTED(Z_LVAL_P(op2) == -1)) { + /* Prevent overflow error/crash if op1==ZEND_LONG_MIN */ + ZVAL_LONG(result, 0); + } else { + ZVAL_LONG(result, Z_LVAL_P(op1) % Z_LVAL_P(op2)); + } + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_mod_function(EX_VAR(opline->result.var), - EX_CONSTANT(opline->op1), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + mod_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -8416,12 +9169,64 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CONST_TMPVAR_HAN { USE_OPLINE zend_free_op free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_equal_function(result, - EX_CONSTANT(opline->op1), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == 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); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -8432,12 +9237,64 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CONST_TMPVAR { USE_OPLINE zend_free_op free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) != Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) != 0); + + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) != 0); + + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_not_equal_function(result, - EX_CONSTANT(opline->op1), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == 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); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -8448,12 +9305,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_CONST_TMPVAR_H { USE_OPLINE zend_free_op free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) < Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_function(result, - EX_CONSTANT(opline->op1), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == 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); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -8464,12 +9347,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_CONST { USE_OPLINE zend_free_op free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = EX_CONSTANT(opline->op1); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) <= Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_or_equal_function(result, - EX_CONSTANT(opline->op1), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == 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); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -8994,13 +9903,60 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CASE_SPEC_CONST_TMPVAR_HANDLER { USE_OPLINE zend_free_op free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; - SAVE_OPLINE(); - fast_equal_function(result, - EX_CONSTANT(opline->op1), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + op1 = EX_CONSTANT(opline->op1); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } + } + } + SAVE_OPLINE(); + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == 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); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -11934,17 +12890,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_INC_SPEC_VAR_HANDLER(ZEND_ zend_free_op free_op1; zval *var_ptr; - SAVE_OPLINE(); var_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1); if (IS_VAR == IS_VAR && UNEXPECTED(var_ptr == NULL)) { + SAVE_OPLINE(); zend_error(E_EXCEPTION | E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); if (free_op1) {zval_ptr_dtor_nogc(free_op1);}; HANDLE_EXCEPTION(); } if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { - fast_increment_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); } @@ -11955,10 +12911,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_INC_SPEC_VAR_HANDLER(ZEND_ if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } + SAVE_OPLINE(); + if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_UNDEF)) { + var_ptr = GET_OP1_UNDEF_CV(var_ptr, BP_VAR_RW); + } ZVAL_DEREF(var_ptr); SEPARATE_ZVAL_NOREF(var_ptr); @@ -11979,17 +12938,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_DEC_SPEC_VAR_HANDLER(ZEND_ zend_free_op free_op1; zval *var_ptr; - SAVE_OPLINE(); var_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1); if (IS_VAR == IS_VAR && UNEXPECTED(var_ptr == NULL)) { + SAVE_OPLINE(); zend_error(E_EXCEPTION | E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); if (free_op1) {zval_ptr_dtor_nogc(free_op1);}; HANDLE_EXCEPTION(); } if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { - fast_decrement_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); } @@ -12000,10 +12959,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_DEC_SPEC_VAR_HANDLER(ZEND_ if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } + SAVE_OPLINE(); + if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_UNDEF)) { + var_ptr = GET_OP1_UNDEF_CV(var_ptr, BP_VAR_RW); + } ZVAL_DEREF(var_ptr); SEPARATE_ZVAL_NOREF(var_ptr); @@ -12024,10 +12986,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POST_INC_SPEC_VAR_HANDLER(ZEND zend_free_op free_op1; zval *var_ptr; - SAVE_OPLINE(); var_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1); if (IS_VAR == IS_VAR && UNEXPECTED(var_ptr == NULL)) { + SAVE_OPLINE(); zend_error(E_EXCEPTION | E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); if (free_op1) {zval_ptr_dtor_nogc(free_op1);}; HANDLE_EXCEPTION(); @@ -12035,16 +12997,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POST_INC_SPEC_VAR_HANDLER(ZEND if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); - fast_increment_function(var_ptr); + fast_long_increment_function(var_ptr); ZEND_VM_NEXT_OPCODE(); } if (IS_VAR == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { ZVAL_NULL(EX_VAR(opline->result.var)); - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } + SAVE_OPLINE(); + if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_UNDEF)) { + var_ptr = GET_OP1_UNDEF_CV(var_ptr, BP_VAR_RW); + } ZVAL_DEREF(var_ptr); ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); zval_opt_copy_ctor(var_ptr); @@ -12062,10 +13027,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POST_DEC_SPEC_VAR_HANDLER(ZEND zend_free_op free_op1; zval *var_ptr; - SAVE_OPLINE(); var_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1); if (IS_VAR == IS_VAR && UNEXPECTED(var_ptr == NULL)) { + SAVE_OPLINE(); zend_error(E_EXCEPTION | E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); if (free_op1) {zval_ptr_dtor_nogc(free_op1);}; HANDLE_EXCEPTION(); @@ -12073,16 +13038,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POST_DEC_SPEC_VAR_HANDLER(ZEND if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); - fast_decrement_function(var_ptr); + fast_long_decrement_function(var_ptr); ZEND_VM_NEXT_OPCODE(); } if (IS_VAR == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { ZVAL_NULL(EX_VAR(opline->result.var)); - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } + SAVE_OPLINE(); + if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_UNDEF)) { + var_ptr = GET_OP1_UNDEF_CV(var_ptr, BP_VAR_RW); + } ZVAL_DEREF(var_ptr); ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); zval_opt_copy_ctor(var_ptr); @@ -24699,17 +25667,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_INC_SPEC_CV_HANDLER(ZEND_O zval *var_ptr; - SAVE_OPLINE(); - var_ptr = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var); + var_ptr = _get_zval_ptr_cv_undef_BP_VAR_RW(execute_data, opline->op1.var); if (IS_CV == IS_VAR && UNEXPECTED(var_ptr == NULL)) { + SAVE_OPLINE(); zend_error(E_EXCEPTION | E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); HANDLE_EXCEPTION(); } if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { - fast_increment_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); } @@ -24720,10 +25688,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_INC_SPEC_CV_HANDLER(ZEND_O if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } + SAVE_OPLINE(); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_UNDEF)) { + var_ptr = GET_OP1_UNDEF_CV(var_ptr, BP_VAR_RW); + } ZVAL_DEREF(var_ptr); SEPARATE_ZVAL_NOREF(var_ptr); @@ -24743,17 +25714,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_DEC_SPEC_CV_HANDLER(ZEND_O zval *var_ptr; - SAVE_OPLINE(); - var_ptr = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var); + var_ptr = _get_zval_ptr_cv_undef_BP_VAR_RW(execute_data, opline->op1.var); if (IS_CV == IS_VAR && UNEXPECTED(var_ptr == NULL)) { + SAVE_OPLINE(); zend_error(E_EXCEPTION | E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); HANDLE_EXCEPTION(); } if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { - fast_decrement_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); } @@ -24764,10 +25735,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_DEC_SPEC_CV_HANDLER(ZEND_O if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } + SAVE_OPLINE(); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_UNDEF)) { + var_ptr = GET_OP1_UNDEF_CV(var_ptr, BP_VAR_RW); + } ZVAL_DEREF(var_ptr); SEPARATE_ZVAL_NOREF(var_ptr); @@ -24787,10 +25761,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POST_INC_SPEC_CV_HANDLER(ZEND_ zval *var_ptr; - SAVE_OPLINE(); - var_ptr = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var); + var_ptr = _get_zval_ptr_cv_undef_BP_VAR_RW(execute_data, opline->op1.var); if (IS_CV == IS_VAR && UNEXPECTED(var_ptr == NULL)) { + SAVE_OPLINE(); zend_error(E_EXCEPTION | E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); HANDLE_EXCEPTION(); @@ -24798,16 +25772,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POST_INC_SPEC_CV_HANDLER(ZEND_ if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); - fast_increment_function(var_ptr); + fast_long_increment_function(var_ptr); ZEND_VM_NEXT_OPCODE(); } if (IS_CV == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { ZVAL_NULL(EX_VAR(opline->result.var)); - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } + SAVE_OPLINE(); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_UNDEF)) { + var_ptr = GET_OP1_UNDEF_CV(var_ptr, BP_VAR_RW); + } ZVAL_DEREF(var_ptr); ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); zval_opt_copy_ctor(var_ptr); @@ -24824,10 +25801,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POST_DEC_SPEC_CV_HANDLER(ZEND_ zval *var_ptr; - SAVE_OPLINE(); - var_ptr = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var); + var_ptr = _get_zval_ptr_cv_undef_BP_VAR_RW(execute_data, opline->op1.var); if (IS_CV == IS_VAR && UNEXPECTED(var_ptr == NULL)) { + SAVE_OPLINE(); zend_error(E_EXCEPTION | E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); HANDLE_EXCEPTION(); @@ -24835,16 +25812,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POST_DEC_SPEC_CV_HANDLER(ZEND_ if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); - fast_decrement_function(var_ptr); + fast_long_decrement_function(var_ptr); ZEND_VM_NEXT_OPCODE(); } if (IS_CV == IS_VAR && UNEXPECTED(var_ptr == &EG(error_zval))) { ZVAL_NULL(EX_VAR(opline->result.var)); - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } + SAVE_OPLINE(); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_UNDEF)) { + var_ptr = GET_OP1_UNDEF_CV(var_ptr, BP_VAR_RW); + } ZVAL_DEREF(var_ptr); ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); zval_opt_copy_ctor(var_ptr); @@ -26193,11 +27173,40 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_CV_CONST_HANDLER(ZEND { USE_OPLINE + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_add_function(EX_VAR(opline->result.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - EX_CONSTANT(opline->op2)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + add_function(EX_VAR(opline->result.var), op1, op2); CHECK_EXCEPTION(); @@ -26208,11 +27217,40 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_CV_CONST_HANDLER(ZEND { USE_OPLINE + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_sub_function(EX_VAR(opline->result.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - EX_CONSTANT(opline->op2)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + sub_function(EX_VAR(opline->result.var), op1, op2); CHECK_EXCEPTION(); @@ -26223,11 +27261,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MUL_SPEC_CV_CONST_HANDLER(ZEND { USE_OPLINE + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + zend_long overflow; + + result = EX_VAR(opline->result.var); + ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1), Z_LVAL_P(op2), Z_LVAL_P(result), Z_DVAL_P(result), overflow); + Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG; + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_mul_function(EX_VAR(opline->result.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - EX_CONSTANT(opline->op2)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + mul_function(EX_VAR(opline->result.var), op1, op2); CHECK_EXCEPTION(); @@ -26253,11 +27323,36 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MOD_SPEC_CV_CONST_HANDLER(ZEND { USE_OPLINE + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + result = EX_VAR(opline->result.var); + if (UNEXPECTED(Z_LVAL_P(op2) == 0)) { + // TODO: change into exception ??? + SAVE_OPLINE(); + zend_error(E_WARNING, "Division by zero"); + ZVAL_FALSE(result); + } else if (UNEXPECTED(Z_LVAL_P(op2) == -1)) { + /* Prevent overflow error/crash if op1==ZEND_LONG_MIN */ + ZVAL_LONG(result, 0); + } else { + ZVAL_LONG(result, Z_LVAL_P(op1) % Z_LVAL_P(op2)); + } + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_mod_function(EX_VAR(opline->result.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - EX_CONSTANT(opline->op2)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + mod_function(EX_VAR(opline->result.var), op1, op2); CHECK_EXCEPTION(); @@ -26344,12 +27439,64 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CV_CONST_HANDLER { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + + + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + + + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + + + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_equal_function(result, - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - EX_CONSTANT(opline->op2)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == 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); CHECK_EXCEPTION(); @@ -26360,12 +27507,64 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_CONST_HAN { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) != Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + + + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) != 0); + + + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) != 0); + + + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_not_equal_function(result, - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - EX_CONSTANT(opline->op2)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == 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); CHECK_EXCEPTION(); @@ -26376,12 +27575,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_CV_CONST_HANDL { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) < Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_function(result, - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - EX_CONSTANT(opline->op2)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == 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); CHECK_EXCEPTION(); @@ -26392,12 +27617,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_CV_CO { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) <= Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_or_equal_function(result, - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - EX_CONSTANT(opline->op2)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == 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); CHECK_EXCEPTION(); @@ -27943,12 +29194,60 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CASE_SPEC_CV_CONST_HANDLER(ZEN { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_equal_function(result, - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - EX_CONSTANT(opline->op2)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == 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); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -30768,11 +32067,40 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_CV_CV_HANDLER(ZEND_OP { USE_OPLINE + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_add_function(EX_VAR(opline->result.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + add_function(EX_VAR(opline->result.var), op1, op2); CHECK_EXCEPTION(); @@ -30783,11 +32111,40 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_CV_CV_HANDLER(ZEND_OP { USE_OPLINE + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_sub_function(EX_VAR(opline->result.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + sub_function(EX_VAR(opline->result.var), op1, op2); CHECK_EXCEPTION(); @@ -30798,11 +32155,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MUL_SPEC_CV_CV_HANDLER(ZEND_OP { USE_OPLINE + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + zend_long overflow; + + result = EX_VAR(opline->result.var); + ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1), Z_LVAL_P(op2), Z_LVAL_P(result), Z_DVAL_P(result), overflow); + Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG; + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_mul_function(EX_VAR(opline->result.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + mul_function(EX_VAR(opline->result.var), op1, op2); CHECK_EXCEPTION(); @@ -30828,11 +32217,36 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MOD_SPEC_CV_CV_HANDLER(ZEND_OP { USE_OPLINE + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + result = EX_VAR(opline->result.var); + if (UNEXPECTED(Z_LVAL_P(op2) == 0)) { + // TODO: change into exception ??? + SAVE_OPLINE(); + zend_error(E_WARNING, "Division by zero"); + ZVAL_FALSE(result); + } else if (UNEXPECTED(Z_LVAL_P(op2) == -1)) { + /* Prevent overflow error/crash if op1==ZEND_LONG_MIN */ + ZVAL_LONG(result, 0); + } else { + ZVAL_LONG(result, Z_LVAL_P(op1) % Z_LVAL_P(op2)); + } + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_mod_function(EX_VAR(opline->result.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + mod_function(EX_VAR(opline->result.var), op1, op2); CHECK_EXCEPTION(); @@ -30919,12 +32333,64 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CV_CV_HANDLER(ZE { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + + + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + + + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + + + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_equal_function(result, - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == 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); CHECK_EXCEPTION(); @@ -30935,12 +32401,64 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_CV_HANDLE { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) != Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + + + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) != 0); + + + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) != 0); + + + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_not_equal_function(result, - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == 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); CHECK_EXCEPTION(); @@ -30951,12 +32469,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_CV_CV_HANDLER( { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) < Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_function(result, - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == 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); CHECK_EXCEPTION(); @@ -30967,12 +32511,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_CV_CV { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) <= Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_or_equal_function(result, - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == 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); CHECK_EXCEPTION(); @@ -32371,12 +33941,60 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CASE_SPEC_CV_CV_HANDLER(ZEND_O { USE_OPLINE - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_equal_function(result, - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == 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); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -32950,11 +34568,40 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_CV_TMPVAR_HANDLER(ZEN { USE_OPLINE zend_free_op free_op2; + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_add_function(EX_VAR(opline->result.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + add_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -32965,11 +34612,40 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_CV_TMPVAR_HANDLER(ZEN { USE_OPLINE zend_free_op free_op2; + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_sub_function(EX_VAR(opline->result.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + sub_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -32980,11 +34656,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MUL_SPEC_CV_TMPVAR_HANDLER(ZEN { USE_OPLINE zend_free_op free_op2; + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + zend_long overflow; + + result = EX_VAR(opline->result.var); + ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1), Z_LVAL_P(op2), Z_LVAL_P(result), Z_DVAL_P(result), overflow); + Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG; + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_mul_function(EX_VAR(opline->result.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + mul_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -33010,11 +34718,36 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MOD_SPEC_CV_TMPVAR_HANDLER(ZEN { USE_OPLINE zend_free_op free_op2; + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + result = EX_VAR(opline->result.var); + if (UNEXPECTED(Z_LVAL_P(op2) == 0)) { + // TODO: change into exception ??? + SAVE_OPLINE(); + zend_error(E_WARNING, "Division by zero"); + ZVAL_FALSE(result); + } else if (UNEXPECTED(Z_LVAL_P(op2) == -1)) { + /* Prevent overflow error/crash if op1==ZEND_LONG_MIN */ + ZVAL_LONG(result, 0); + } else { + ZVAL_LONG(result, Z_LVAL_P(op1) % Z_LVAL_P(op2)); + } + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_mod_function(EX_VAR(opline->result.var), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + mod_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -33070,12 +34803,64 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CV_TMPVAR_HANDLE { USE_OPLINE zend_free_op free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_equal_function(result, - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == 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); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -33086,12 +34871,64 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_TMPVAR_HA { USE_OPLINE zend_free_op free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) != Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) != 0); + + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) != 0); + + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_not_equal_function(result, - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == 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); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -33102,12 +34939,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_CV_TMPVAR_HAND { USE_OPLINE zend_free_op free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) < Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_function(result, - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == 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); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -33118,12 +34981,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_CV_TM { USE_OPLINE zend_free_op free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) <= Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_or_equal_function(result, - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == 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); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -34435,13 +36324,60 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CASE_SPEC_CV_TMPVAR_HANDLER(ZE { USE_OPLINE zend_free_op free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; - SAVE_OPLINE(); - fast_equal_function(result, - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + op1 = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } + } + } + SAVE_OPLINE(); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == 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); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -35437,11 +37373,40 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_TMPVAR_CONST_HANDLER( { USE_OPLINE zend_free_op free_op1; + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_add_function(EX_VAR(opline->result.var), - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - EX_CONSTANT(opline->op2)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + add_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op1); CHECK_EXCEPTION(); @@ -35452,11 +37417,40 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_TMPVAR_CONST_HANDLER( { USE_OPLINE zend_free_op free_op1; + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_sub_function(EX_VAR(opline->result.var), - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - EX_CONSTANT(opline->op2)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + sub_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op1); CHECK_EXCEPTION(); @@ -35467,11 +37461,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MUL_SPEC_TMPVAR_CONST_HANDLER( { USE_OPLINE zend_free_op free_op1; + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + zend_long overflow; + + result = EX_VAR(opline->result.var); + ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1), Z_LVAL_P(op2), Z_LVAL_P(result), Z_DVAL_P(result), overflow); + Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG; + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_mul_function(EX_VAR(opline->result.var), - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - EX_CONSTANT(opline->op2)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + mul_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op1); CHECK_EXCEPTION(); @@ -35497,11 +37523,36 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MOD_SPEC_TMPVAR_CONST_HANDLER( { USE_OPLINE zend_free_op free_op1; + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + result = EX_VAR(opline->result.var); + if (UNEXPECTED(Z_LVAL_P(op2) == 0)) { + // TODO: change into exception ??? + SAVE_OPLINE(); + zend_error(E_WARNING, "Division by zero"); + ZVAL_FALSE(result); + } else if (UNEXPECTED(Z_LVAL_P(op2) == -1)) { + /* Prevent overflow error/crash if op1==ZEND_LONG_MIN */ + ZVAL_LONG(result, 0); + } else { + ZVAL_LONG(result, Z_LVAL_P(op1) % Z_LVAL_P(op2)); + } + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_mod_function(EX_VAR(opline->result.var), - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - EX_CONSTANT(opline->op2)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + mod_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op1); CHECK_EXCEPTION(); @@ -35557,12 +37608,64 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_TMPVAR_CONST_HAN { USE_OPLINE zend_free_op free_op1; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op1); + + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op1); + + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + zval_ptr_dtor_nogc(free_op1); + + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + zval_ptr_dtor_nogc(free_op1); + + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_equal_function(result, - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - EX_CONSTANT(opline->op2)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == 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); zval_ptr_dtor_nogc(free_op1); CHECK_EXCEPTION(); @@ -35573,12 +37676,64 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_TMPVAR_CONST { USE_OPLINE zend_free_op free_op1; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) != Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op1); + + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op1); + + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) != 0); + zval_ptr_dtor_nogc(free_op1); + + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) != 0); + zval_ptr_dtor_nogc(free_op1); + + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_not_equal_function(result, - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - EX_CONSTANT(opline->op2)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == 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); zval_ptr_dtor_nogc(free_op1); CHECK_EXCEPTION(); @@ -35589,12 +37744,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_TMPVAR_CONST_H { USE_OPLINE zend_free_op free_op1; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) < Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_function(result, - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - EX_CONSTANT(opline->op2)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == 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); zval_ptr_dtor_nogc(free_op1); CHECK_EXCEPTION(); @@ -35605,12 +37786,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_TMPVA { USE_OPLINE zend_free_op free_op1; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) <= Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_or_equal_function(result, - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - EX_CONSTANT(opline->op2)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == 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); zval_ptr_dtor_nogc(free_op1); CHECK_EXCEPTION(); @@ -36095,12 +38302,60 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CASE_SPEC_TMPVAR_CONST_HANDLER { USE_OPLINE zend_free_op free_op1; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = EX_CONSTANT(opline->op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_equal_function(result, - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - EX_CONSTANT(opline->op2)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CONST == 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); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -37249,11 +39504,40 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_TMPVAR_CV_HANDLER(ZEN { USE_OPLINE zend_free_op free_op1; + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_add_function(EX_VAR(opline->result.var), - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + add_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op1); CHECK_EXCEPTION(); @@ -37264,11 +39548,40 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_TMPVAR_CV_HANDLER(ZEN { USE_OPLINE zend_free_op free_op1; + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_sub_function(EX_VAR(opline->result.var), - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + sub_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op1); CHECK_EXCEPTION(); @@ -37279,11 +39592,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MUL_SPEC_TMPVAR_CV_HANDLER(ZEN { USE_OPLINE zend_free_op free_op1; + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + zend_long overflow; + + result = EX_VAR(opline->result.var); + ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1), Z_LVAL_P(op2), Z_LVAL_P(result), Z_DVAL_P(result), overflow); + Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG; + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_mul_function(EX_VAR(opline->result.var), - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + mul_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op1); CHECK_EXCEPTION(); @@ -37309,11 +39654,36 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MOD_SPEC_TMPVAR_CV_HANDLER(ZEN { USE_OPLINE zend_free_op free_op1; + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + result = EX_VAR(opline->result.var); + if (UNEXPECTED(Z_LVAL_P(op2) == 0)) { + // TODO: change into exception ??? + SAVE_OPLINE(); + zend_error(E_WARNING, "Division by zero"); + ZVAL_FALSE(result); + } else if (UNEXPECTED(Z_LVAL_P(op2) == -1)) { + /* Prevent overflow error/crash if op1==ZEND_LONG_MIN */ + ZVAL_LONG(result, 0); + } else { + ZVAL_LONG(result, Z_LVAL_P(op1) % Z_LVAL_P(op2)); + } + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_mod_function(EX_VAR(opline->result.var), - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + mod_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op1); CHECK_EXCEPTION(); @@ -37369,12 +39739,64 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_TMPVAR_CV_HANDLE { USE_OPLINE zend_free_op free_op1; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op1); + + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op1); + + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + zval_ptr_dtor_nogc(free_op1); + + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + zval_ptr_dtor_nogc(free_op1); + + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_equal_function(result, - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == 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); zval_ptr_dtor_nogc(free_op1); CHECK_EXCEPTION(); @@ -37385,12 +39807,64 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_TMPVAR_CV_HA { USE_OPLINE zend_free_op free_op1; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) != Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op1); + + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op1); + + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) != 0); + zval_ptr_dtor_nogc(free_op1); + + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) != 0); + zval_ptr_dtor_nogc(free_op1); + + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_not_equal_function(result, - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == 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); zval_ptr_dtor_nogc(free_op1); CHECK_EXCEPTION(); @@ -37401,12 +39875,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_TMPVAR_CV_HAND { USE_OPLINE zend_free_op free_op1; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) < Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_function(result, - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == 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); zval_ptr_dtor_nogc(free_op1); CHECK_EXCEPTION(); @@ -37417,12 +39917,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_TMPVA { USE_OPLINE zend_free_op free_op1; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) <= Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_or_equal_function(result, - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == 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); zval_ptr_dtor_nogc(free_op1); CHECK_EXCEPTION(); @@ -37697,12 +40223,60 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CASE_SPEC_TMPVAR_CV_HANDLER(ZE { USE_OPLINE zend_free_op free_op1; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_equal_function(result, - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if (IS_CV == 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); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -37883,11 +40457,40 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_TMPVAR_TMPVAR_HANDLER { USE_OPLINE zend_free_op free_op1, free_op2; + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_add_function(EX_VAR(opline->result.var), - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + add_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op1); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -37898,11 +40501,40 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_TMPVAR_TMPVAR_HANDLER { USE_OPLINE zend_free_op free_op1, free_op2; + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_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_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_sub_function(EX_VAR(opline->result.var), - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + sub_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op1); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -37913,11 +40545,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MUL_SPEC_TMPVAR_TMPVAR_HANDLER { USE_OPLINE zend_free_op free_op1, free_op2; + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + zend_long overflow; + + result = EX_VAR(opline->result.var); + ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1), Z_LVAL_P(op2), Z_LVAL_P(result), Z_DVAL_P(result), overflow); + Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG; + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_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(); + } + } SAVE_OPLINE(); - fast_mul_function(EX_VAR(opline->result.var), - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + mul_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op1); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -37943,11 +40607,36 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MOD_SPEC_TMPVAR_TMPVAR_HANDLER { USE_OPLINE zend_free_op free_op1, free_op2; + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + result = EX_VAR(opline->result.var); + if (UNEXPECTED(Z_LVAL_P(op2) == 0)) { + // TODO: change into exception ??? + SAVE_OPLINE(); + zend_error(E_WARNING, "Division by zero"); + ZVAL_FALSE(result); + } else if (UNEXPECTED(Z_LVAL_P(op2) == -1)) { + /* Prevent overflow error/crash if op1==ZEND_LONG_MIN */ + ZVAL_LONG(result, 0); + } else { + ZVAL_LONG(result, Z_LVAL_P(op1) % Z_LVAL_P(op2)); + } + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_mod_function(EX_VAR(opline->result.var), - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) { + op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); + } + mod_function(EX_VAR(opline->result.var), op1, op2); zval_ptr_dtor_nogc(free_op1); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -38003,12 +40692,64 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_TMPVAR_TMPVAR_HA { USE_OPLINE zend_free_op free_op1, free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op1); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op1); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + zval_ptr_dtor_nogc(free_op1); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + zval_ptr_dtor_nogc(free_op1); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_equal_function(result, - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == 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); zval_ptr_dtor_nogc(free_op1); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -38019,12 +40760,64 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_TMPVAR_TMPVA { USE_OPLINE zend_free_op free_op1, free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) != Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) != ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op1); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op1); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) != 0); + zval_ptr_dtor_nogc(free_op1); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) != 0); + zval_ptr_dtor_nogc(free_op1); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } + } + } SAVE_OPLINE(); - fast_not_equal_function(result, - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == 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); zval_ptr_dtor_nogc(free_op1); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -38035,12 +40828,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_TMPVAR_TMPVAR_ { USE_OPLINE zend_free_op free_op1, free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) < Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) < ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_function(result, - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == 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); zval_ptr_dtor_nogc(free_op1); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -38051,12 +40870,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_TMPVA { USE_OPLINE zend_free_op free_op1, free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; + + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) <= Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) <= ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } SAVE_OPLINE(); - fast_is_smaller_or_equal_function(result, - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == 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); zval_ptr_dtor_nogc(free_op1); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); @@ -38333,13 +41178,60 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CASE_SPEC_TMPVAR_TMPVAR_HANDLE { USE_OPLINE zend_free_op free_op1, free_op2; - zval *result = EX_VAR(opline->result.var); + zval *op1, *op2, *result; - SAVE_OPLINE(); - fast_equal_function(result, - _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1), - _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)); + op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_LVAL_P(op1) == Z_LVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == Z_DVAL_P(op2)); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(EX_VAR(opline->result.var), Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + ZEND_VM_NEXT_OPCODE(); + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } + } else { + ZVAL_BOOL(EX_VAR(opline->result.var), zendi_smart_strcmp(op1, op2) == 0); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE(); + } + } + } + SAVE_OPLINE(); + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); + } + if ((IS_TMP_VAR|IS_VAR) == 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); zval_ptr_dtor_nogc(free_op2); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index cd0fb378b0..a4eac1dcd7 100644 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -199,6 +199,26 @@ $op2_get_zval_ptr_deref = array( "TMPVAR" => "???", ); +$op1_get_zval_ptr_undef = array( + "ANY" => "get_zval_ptr_undef(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)", + "TMP" => "_get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1)", + "VAR" => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1)", + "CONST" => "EX_CONSTANT(opline->op1)", + "UNUSED" => "NULL", + "CV" => "_get_zval_ptr_cv_undef(execute_data, opline->op1.var)", + "TMPVAR" => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1)", +); + +$op2_get_zval_ptr_undef = array( + "ANY" => "get_zval_ptr_undef(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)", + "TMP" => "_get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2)", + "VAR" => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)", + "CONST" => "EX_CONSTANT(opline->op2)", + "UNUSED" => "NULL", + "CV" => "_get_zval_ptr_cv_undef(execute_data, opline->op2.var)", + "TMPVAR" => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)", +); + $op1_get_zval_ptr_ptr_undef = array( "ANY" => "get_zval_ptr_ptr_undef(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)", "TMP" => "NULL", @@ -425,6 +445,7 @@ function helper_name($name, $spec, $op1, $op2) { function gen_code($f, $spec, $kind, $export, $code, $op1, $op2, $name) { global $op1_type, $op2_type, $op1_get_zval_ptr, $op2_get_zval_ptr, $op1_get_zval_ptr_deref, $op2_get_zval_ptr_deref, + $op1_get_zval_ptr_undef, $op2_get_zval_ptr_undef, $op1_get_zval_ptr_ptr, $op2_get_zval_ptr_ptr, $op1_get_zval_ptr_ptr_undef, $op2_get_zval_ptr_ptr_undef, $op1_get_obj_zval_ptr, $op2_get_obj_zval_ptr, @@ -446,6 +467,8 @@ function gen_code($f, $spec, $kind, $export, $code, $op1, $op2, $name) { "/GET_OP2_ZVAL_PTR\(([^)]*)\)/", "/GET_OP1_ZVAL_PTR_DEREF\(([^)]*)\)/", "/GET_OP2_ZVAL_PTR_DEREF\(([^)]*)\)/", + "/GET_OP1_ZVAL_PTR_UNDEF\(([^)]*)\)/", + "/GET_OP2_ZVAL_PTR_UNDEF\(([^)]*)\)/", "/GET_OP1_ZVAL_PTR_PTR\(([^)]*)\)/", "/GET_OP2_ZVAL_PTR_PTR\(([^)]*)\)/", "/GET_OP1_ZVAL_PTR_PTR_UNDEF\(([^)]*)\)/", @@ -486,6 +509,8 @@ function gen_code($f, $spec, $kind, $export, $code, $op1, $op2, $name) { $op2_get_zval_ptr[$op2], $op1_get_zval_ptr_deref[$op1], $op2_get_zval_ptr_deref[$op2], + $op1_get_zval_ptr_undef[$op1], + $op2_get_zval_ptr_undef[$op2], $op1_get_zval_ptr_ptr[$op1], $op2_get_zval_ptr_ptr[$op2], $op1_get_zval_ptr_ptr_undef[$op1], |