diff options
-rw-r--r-- | ext/opcache/jit/zend_jit.c | 1 | ||||
-rw-r--r-- | ext/opcache/jit/zend_jit_trace.c | 3 | ||||
-rw-r--r-- | ext/opcache/jit/zend_jit_x86.dasc | 349 |
3 files changed, 214 insertions, 139 deletions
diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 5073894dbe..5d1b2414a8 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -2633,6 +2633,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op } case ZEND_IS_IDENTICAL: case ZEND_IS_NOT_IDENTICAL: + case ZEND_CASE_STRICT: if ((opline->result_type & IS_TMP_VAR) && (i + 1) <= end && ((opline+1)->opcode == ZEND_JMPZ diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 46d84bfa4e..3d6a7dd07c 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -257,6 +257,7 @@ static int zend_jit_trace_may_exit(const zend_op_array *op_array, const zend_op case ZEND_IS_SMALLER: case ZEND_IS_SMALLER_OR_EQUAL: case ZEND_CASE: + case ZEND_CASE_STRICT: case ZEND_ISSET_ISEMPTY_CV: case ZEND_ISSET_ISEMPTY_VAR: case ZEND_ISSET_ISEMPTY_DIM_OBJ: @@ -1423,6 +1424,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin case ZEND_CASE: case ZEND_IS_IDENTICAL: case ZEND_IS_NOT_IDENTICAL: + case ZEND_CASE_STRICT: case ZEND_FETCH_DIM_R: case ZEND_FETCH_DIM_IS: case ZEND_BW_OR: @@ -3733,6 +3735,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par goto done; case ZEND_IS_IDENTICAL: case ZEND_IS_NOT_IDENTICAL: + case ZEND_CASE_STRICT: op1_info = OP1_INFO(); CHECK_OP1_TRACE_TYPE(); op2_info = OP2_INFO(); diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 6fc18bdd3d..812d1f5f56 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -6246,6 +6246,7 @@ static int zend_jit_cmp_long_long(dasm_State **Dst, const zend_op *opline, zend_ case ZEND_IS_EQUAL: case ZEND_IS_IDENTICAL: case ZEND_CASE: + case ZEND_CASE_STRICT: | sete al break; case ZEND_IS_NOT_EQUAL: @@ -6279,6 +6280,7 @@ static int zend_jit_cmp_long_long(dasm_State **Dst, const zend_op *opline, zend_ case ZEND_IS_EQUAL: case ZEND_IS_IDENTICAL: case ZEND_CASE: + case ZEND_CASE_STRICT: if (exit_addr) { | jne &exit_addr } else { @@ -6338,6 +6340,7 @@ static int zend_jit_cmp_long_long(dasm_State **Dst, const zend_op *opline, zend_ case ZEND_IS_EQUAL: case ZEND_IS_IDENTICAL: case ZEND_CASE: + case ZEND_CASE_STRICT: if (exit_addr) { | je &exit_addr } else { @@ -6396,6 +6399,7 @@ static int zend_jit_cmp_long_long(dasm_State **Dst, const zend_op *opline, zend_ case ZEND_IS_EQUAL: case ZEND_IS_IDENTICAL: case ZEND_CASE: + case ZEND_CASE_STRICT: | jne => target_label break; case ZEND_IS_NOT_EQUAL: @@ -6428,6 +6432,7 @@ static int zend_jit_cmp_long_long(dasm_State **Dst, const zend_op *opline, zend_ case ZEND_IS_EQUAL: case ZEND_IS_IDENTICAL: case ZEND_CASE: + case ZEND_CASE_STRICT: | sete al break; case ZEND_IS_NOT_EQUAL: @@ -6467,6 +6472,7 @@ static int zend_jit_cmp_double_common(dasm_State **Dst, const zend_op *opline, z case ZEND_IS_EQUAL: case ZEND_IS_IDENTICAL: case ZEND_CASE: + case ZEND_CASE_STRICT: if (exit_addr) { | jne &exit_addr | jp &exit_addr @@ -6536,6 +6542,7 @@ static int zend_jit_cmp_double_common(dasm_State **Dst, const zend_op *opline, z case ZEND_IS_EQUAL: case ZEND_IS_IDENTICAL: case ZEND_CASE: + case ZEND_CASE_STRICT: | jp >1 if (exit_addr) { | je &exit_addr @@ -6605,6 +6612,7 @@ static int zend_jit_cmp_double_common(dasm_State **Dst, const zend_op *opline, z case ZEND_IS_EQUAL: case ZEND_IS_IDENTICAL: case ZEND_CASE: + case ZEND_CASE_STRICT: | jne => target_label | jp => target_label break; @@ -6638,6 +6646,7 @@ static int zend_jit_cmp_double_common(dasm_State **Dst, const zend_op *opline, z case ZEND_IS_EQUAL: case ZEND_IS_IDENTICAL: case ZEND_CASE: + case ZEND_CASE_STRICT: | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE | jne => target_label | jp => target_label @@ -6683,6 +6692,7 @@ static int zend_jit_cmp_double_common(dasm_State **Dst, const zend_op *opline, z case ZEND_IS_EQUAL: case ZEND_IS_IDENTICAL: case ZEND_CASE: + case ZEND_CASE_STRICT: | jp >1 | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE | je => target_label @@ -6737,6 +6747,7 @@ static int zend_jit_cmp_double_common(dasm_State **Dst, const zend_op *opline, z case ZEND_IS_EQUAL: case ZEND_IS_IDENTICAL: case ZEND_CASE: + case ZEND_CASE_STRICT: | jp >1 | mov eax, IS_TRUE | je >2 @@ -7205,7 +7216,7 @@ static int zend_jit_identical(dasm_State **Dst, const zend_op *opline, uint32_t uint32_t not_identical_label = (uint32_t)-1; if (smart_branch_opcode && !exit_addr) { - if (opline->opcode == ZEND_IS_IDENTICAL) { + if (opline->opcode != ZEND_IS_NOT_IDENTICAL) { if (smart_branch_opcode == ZEND_JMPZ) { not_identical_label = target_label; } else if (smart_branch_opcode == ZEND_JMPNZ) { @@ -7216,7 +7227,7 @@ static int zend_jit_identical(dasm_State **Dst, const zend_op *opline, uint32_t } else { ZEND_UNREACHABLE(); } - } else if (opline->opcode == ZEND_IS_NOT_IDENTICAL) { + } else { if (smart_branch_opcode == ZEND_JMPZ) { identical_label = target_label; } else if (smart_branch_opcode == ZEND_JMPNZ) { @@ -7227,8 +7238,6 @@ static int zend_jit_identical(dasm_State **Dst, const zend_op *opline, uint32_t } else { ZEND_UNREACHABLE(); } - } else { - ZEND_UNREACHABLE(); } } @@ -7351,12 +7360,15 @@ static int zend_jit_identical(dasm_State **Dst, const zend_op *opline, uint32_t } if ((op1_info & op2_info & MAY_BE_ANY) == 0) { - if (((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && + if ((opline->opcode != ZEND_CASE_STRICT && + (opline->op1_type & (IS_VAR|IS_TMP_VAR)) && (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) || ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)))) { | SAVE_VALID_OPLINE opline, r0 - | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline + if (opline->opcode != ZEND_CASE_STRICT) { + | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline + } | FREE_OP opline->op2_type, opline->op2, op2_info, 1, opline } if (smart_branch_opcode) { @@ -7369,7 +7381,7 @@ static int zend_jit_identical(dasm_State **Dst, const zend_op *opline, uint32_t | jmp =>not_identical_label } } else { - | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode == ZEND_IS_IDENTICAL ? IS_FALSE : IS_TRUE) + | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_FALSE : IS_TRUE) zend_jit_check_exception(Dst); } } else if (has_concrete_type(op1_info) && @@ -7385,7 +7397,7 @@ static int zend_jit_identical(dasm_State **Dst, const zend_op *opline, uint32_t | jmp =>identical_label } } else { - | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode == ZEND_IS_IDENTICAL ? IS_TRUE : IS_FALSE) + | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_TRUE : IS_FALSE) } } else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) == IS_CONST_ZVAL) { if (zend_is_identical(Z_ZV(op1_addr), Z_ZV(op2_addr))) { @@ -7398,7 +7410,7 @@ static int zend_jit_identical(dasm_State **Dst, const zend_op *opline, uint32_t | jmp =>identical_label } } else { - | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode == ZEND_IS_IDENTICAL ? IS_TRUE : IS_FALSE) + | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_TRUE : IS_FALSE) } } else { if (smart_branch_opcode) { @@ -7410,7 +7422,7 @@ static int zend_jit_identical(dasm_State **Dst, const zend_op *opline, uint32_t | jmp =>not_identical_label } } else { - | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode == ZEND_IS_IDENTICAL ? IS_FALSE : IS_TRUE) + | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_FALSE : IS_TRUE) } } } else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op1_addr)) <= IS_TRUE) { @@ -7439,7 +7451,7 @@ static int zend_jit_identical(dasm_State **Dst, const zend_op *opline, uint32_t | je >9 } } else { - if (opline->opcode == ZEND_IS_IDENTICAL) { + if (opline->opcode != ZEND_IS_NOT_IDENTICAL) { | sete al } else { | setne al @@ -7466,7 +7478,8 @@ static int zend_jit_identical(dasm_State **Dst, const zend_op *opline, uint32_t | cmp byte [FCARG1a + offsetof(zval, u1.v.type)], Z_TYPE_P(val) if (smart_branch_opcode) { - if (opline->op1_type == IS_VAR && (op1_info & MAY_BE_REF)) { + if (opline->opcode != ZEND_CASE_STRICT + && opline->op1_type == IS_VAR && (op1_info & MAY_BE_REF)) { | jne >8 | SAVE_VALID_OPLINE opline, r0 | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline @@ -7487,7 +7500,7 @@ static int zend_jit_identical(dasm_State **Dst, const zend_op *opline, uint32_t | je >9 } } else { - if (opline->opcode == ZEND_IS_IDENTICAL) { + if (opline->opcode != ZEND_IS_NOT_IDENTICAL) { | sete al } else { | setne al @@ -7496,7 +7509,8 @@ static int zend_jit_identical(dasm_State **Dst, const zend_op *opline, uint32_t | lea eax, [eax + 2] | SET_ZVAL_TYPE_INFO res_addr, eax } - if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && + if (opline->opcode != ZEND_CASE_STRICT + && (opline->op1_type & (IS_VAR|IS_TMP_VAR)) && (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) { | SAVE_VALID_OPLINE opline, r0 | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline @@ -7519,13 +7533,16 @@ static int zend_jit_identical(dasm_State **Dst, const zend_op *opline, uint32_t | LOAD_ZVAL_ADDR FCARG2a, op2_addr } | EXT_CALL zend_is_identical, r0 - if (((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && + if ((opline->opcode != ZEND_CASE_STRICT && + (opline->op1_type & (IS_VAR|IS_TMP_VAR)) && (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) || ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)))) { | mov aword T1, r0 // save | SAVE_VALID_OPLINE opline, r0 - | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline + if (opline->opcode != ZEND_CASE_STRICT) { + | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline + } | FREE_OP opline->op2_type, opline->op2, op2_info, 1, opline zend_jit_check_exception_undef_result(Dst, opline); | mov r0, aword T1 // restore @@ -7548,7 +7565,7 @@ static int zend_jit_identical(dasm_State **Dst, const zend_op *opline, uint32_t } } else { | movzx eax, al - if (opline->opcode == ZEND_IS_IDENTICAL) { + if (opline->opcode != ZEND_IS_NOT_IDENTICAL) { | lea eax, [eax + 2] } else { | neg eax @@ -11883,6 +11900,81 @@ static int zend_jit_fetch_this(dasm_State **Dst, const zend_op *opline, const ze return 1; } +static int zend_jit_hash_jmp(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, HashTable *jumptable, int default_b, const void *default_label, const zend_op *next_opline, zend_jit_trace_info *trace_info) +{ + uint32_t count; + Bucket *p; + const zend_op *target; + int b; + int32_t exit_point; + const void *exit_addr; + + | test r0, r0 + if (default_label) { + | jz &default_label + } else if (next_opline) { + | jz >3 + } else { + | jz =>default_b + } + | LOAD_ADDR FCARG1a, jumptable + | sub r0, aword [FCARG1a + offsetof(HashTable, arData)] + | mov FCARG1a, (sizeof(Bucket) / sizeof(void*)) + |.if X64 + | cqo + |.else + | cdq + |.endif + | idiv FCARG1a + |.if X64 + if (!IS_32BIT(dasm_end)) { + | lea FCARG1a, aword [>4] + | jmp aword [FCARG1a + r0] + } else { + | jmp aword [r0 + >4] + } + |.else + | jmp aword [r0 + >4] + |.endif + |.jmp_table + |.align aword + |4: + if (trace_info) { + trace_info->jmp_table_size += zend_hash_num_elements(jumptable); + } + + count = jumptable->nNumUsed; + p = jumptable->arData; + do { + if (Z_TYPE(p->val) == IS_UNDEF) { + if (default_label) { + | .aword &default_label + } else if (next_opline) { + | .aword >3 + } else { + | .aword =>default_b + } + } else { + target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL(p->val)); + if (!next_opline) { + b = ssa->cfg.map[target - op_array->opcodes]; + | .aword =>b + } else if (next_opline == target) { + | .aword >3 + } else { + exit_point = zend_jit_trace_get_exit_point(target, 0); + exit_addr = zend_jit_trace_get_exit_addr(exit_point); + | .aword &exit_addr + } + } + p++; + count--; + } while (count); + |.code + + return 1; +} + static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, zend_jit_trace_rec *trace, zend_jit_trace_info *trace_info) { HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2)); @@ -11894,53 +11986,45 @@ static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_o next_opline = trace->opline; } - // TODO: Implement for match instructions - if (opline->opcode == ZEND_MATCH) { - // Since the match expression doesn't have a IS_IDENTICAL/JMPNZ chain - // we can't skip the jumptable and thus can't JIT the function - return 0; - } - if (opline->op1_type == IS_CONST) { zval *zv = RT_CONSTANT(opline, opline->op1); - zval *jump_zv; + zval *jump_zv = NULL; int b; if (opline->opcode == ZEND_SWITCH_LONG) { if (Z_TYPE_P(zv) == IS_LONG) { jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv)); - if (next_opline) { - const zend_op *target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)); - - ZEND_ASSERT(target == next_opline); - } else { - if (jump_zv != NULL) { - b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)) - op_array->opcodes]; - } else { - b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes]; - } - | jmp =>b - } } } else if (opline->opcode == ZEND_SWITCH_STRING) { if (Z_TYPE_P(zv) == IS_STRING) { jump_zv = zend_hash_find_ex(jumptable, Z_STR_P(zv), 1); - if (next_opline) { - const zend_op *target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)); - - ZEND_ASSERT(target == next_opline); - } else { - if (jump_zv != NULL) { - b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)) - op_array->opcodes]; - } else { - b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes]; - } - | jmp =>b - } + } + } else if (opline->opcode == ZEND_MATCH) { + if (Z_TYPE_P(zv) == IS_LONG) { + jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv)); + } else if (Z_TYPE_P(zv) == IS_STRING) { + jump_zv = zend_hash_find_ex(jumptable, Z_STR_P(zv), 1); } } else { ZEND_UNREACHABLE(); } + if (next_opline) { + const zend_op *target; + + if (jump_zv != NULL) { + target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)); + } else { + target = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value); + } + ZEND_ASSERT(target == next_opline); + } else { + if (jump_zv != NULL) { + b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)) - op_array->opcodes]; + } else { + b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes]; + } + | jmp =>b + } } else { zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes]; uint32_t op1_info = OP1_INFO(); @@ -11949,7 +12033,6 @@ static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_o const zend_op *target; int default_b = next_opline ? -1 : ssa->cfg.map[default_opline - op_array->opcodes]; int b; - zval *val; int32_t exit_point; const void *fallback_label = NULL; const void *default_label = NULL; @@ -12058,53 +12141,9 @@ static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_o } else { | LOAD_ADDR FCARG1a, jumptable | EXT_CALL zend_hash_index_find, r0 - | test r0, r0 - if (default_label) { - | jz &default_label - } else if (next_opline) { - | jz >3 - } else { - | jz =>default_b - } - | LOAD_ADDR FCARG1a, jumptable - | sub r0, aword [FCARG1a + offsetof(HashTable, arData)] - | mov FCARG1a, (sizeof(Bucket) / sizeof(void*)) - |.if X64 - | cqo - |.else - | cdq - |.endif - | idiv FCARG1a - |.if X64 - if (!IS_32BIT(dasm_end)) { - | lea FCARG1a, aword [>4] - | jmp aword [FCARG1a + r0] - } else { - | jmp aword [r0 + >4] + if (!zend_jit_hash_jmp(Dst, opline, op_array, ssa, jumptable, default_b, default_label, next_opline, trace_info)) { + return 0; } - |.else - | jmp aword [r0 + >4] - |.endif - |.jmp_table - |.align aword - |4: - if (trace_info) { - trace_info->jmp_table_size += zend_hash_num_elements(jumptable); - } - ZEND_HASH_FOREACH_VAL(jumptable, val) { - target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(val)); - if (!next_opline) { - b = ssa->cfg.map[target - op_array->opcodes]; - | .aword =>b - } else if (next_opline == target) { - | .aword >3 - } else { - exit_point = zend_jit_trace_get_exit_point(target, 0); - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - | .aword &exit_addr - } - } ZEND_HASH_FOREACH_END(); - |.code |3: } } @@ -12143,55 +12182,87 @@ static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_o } | LOAD_ADDR FCARG1a, jumptable | EXT_CALL zend_hash_find, r0 - | test r0, r0 - if (default_label) { - | jz &default_label - } else if (next_opline) { - | jz >3 - } else { - | jz =>default_b + if (!zend_jit_hash_jmp(Dst, opline, op_array, ssa, jumptable, default_b, default_label, next_opline, trace_info)) { + return 0; + } + |3: + } + } else if (opline->opcode == ZEND_MATCH) { + if (op1_info & (MAY_BE_LONG|MAY_BE_STRING)) { + if (op1_info & MAY_BE_REF) { + | LOAD_ZVAL_ADDR FCARG2a, op1_addr + | ZVAL_DEREF FCARG2a, op1_info + op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2a, 0); } | LOAD_ADDR FCARG1a, jumptable - | sub r0, aword [FCARG1a + offsetof(HashTable, arData)] - | mov FCARG1a, (sizeof(Bucket) / sizeof(void*)) - |.if X64 - | cqo - |.else - | cdq - |.endif - | idiv FCARG1a - |.if X64 - if (!IS_32BIT(dasm_end)) { - | lea FCARG1a, aword [>4] - | jmp aword [FCARG1a + r0] - } else { - | jmp aword [r0 + >4] + if (op1_info & MAY_BE_LONG) { + if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) { + if (op1_info & MAY_BE_STRING) { + | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >5 + } else if (op1_info & MAY_BE_UNDEF) { + | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >6 + } else if (default_label) { + | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, &default_label + } else if (next_opline) { + | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >3 + } else { + | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, =>default_b + } + } + | GET_ZVAL_LVAL ZREG_FCARG2a, op1_addr + | EXT_CALL zend_hash_index_find, r0 + if (op1_info & MAY_BE_STRING) { + | jmp >2 + } + } + if (op1_info & MAY_BE_STRING) { + |5: + if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_STRING))) { + if (op1_info & MAY_BE_UNDEF) { + | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >6 + } else if (default_label) { + | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, &default_label + } else if (next_opline) { + | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >3 + } else { + | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, =>default_b + } + } + | GET_ZVAL_PTR FCARG2a, op1_addr + | EXT_CALL zend_hash_find, r0 } - |.else - | jmp aword [r0 + >4] - |.endif - |.jmp_table - |.align aword - |4: - if (trace_info) { - trace_info->jmp_table_size += zend_hash_num_elements(jumptable); - } - ZEND_HASH_FOREACH_VAL(jumptable, val) { - target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(val)); - if (!next_opline) { - b = ssa->cfg.map[target - op_array->opcodes]; - | .aword =>b - } else if (next_opline == target) { - | .aword >3 + |2: + if (!zend_jit_hash_jmp(Dst, opline, op_array, ssa, jumptable, default_b, default_label, next_opline, trace_info)) { + return 0; + } + } + if (op1_info & MAY_BE_UNDEF) { + |6: + if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_STRING))) { + if (default_label) { + | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, &default_label + } else if (next_opline) { + | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >3 } else { - exit_point = zend_jit_trace_get_exit_point(target, 0); - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - | .aword &exit_addr + | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, =>default_b } - } ZEND_HASH_FOREACH_END(); - |.code - |3: + } + | // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)))); + | SAVE_VALID_OPLINE opline, r0 + | mov FCARG1d, opline->op1.var + | EXT_CALL zend_jit_undefined_op_helper, r0 + if (!zend_jit_check_exception_undef_result(Dst, opline)) { + return 0; + } } + if (default_label) { + | jmp &default_label + } else if (next_opline) { + | jmp >3 + } else { + | jmp =>default_b + } + |3: } else { ZEND_UNREACHABLE(); } |