Skip to content

Commit f3f5719

Browse files
committed
JIT for FE_FETCH_R
1 parent 8c31001 commit f3f5719

File tree

3 files changed

+174
-0
lines changed

3 files changed

+174
-0
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2951,6 +2951,16 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
29512951
goto jit_failure;
29522952
}
29532953
goto done;
2954+
case ZEND_FE_FETCH_R:
2955+
op1_info = OP1_INFO();
2956+
if ((op1_info & MAY_BE_ANY) != MAY_BE_ARRAY) {
2957+
break;
2958+
}
2959+
if (!zend_jit_fe_fetch(&dasm_state, opline, op_array, ssa, ssa_op,
2960+
op1_info, ssa->cfg.blocks[b].successors[0], opline->opcode, NULL)) {
2961+
goto jit_failure;
2962+
}
2963+
goto done;
29542964
case ZEND_VERIFY_RETURN_TYPE:
29552965
if (opline->op1_type == IS_UNUSED) {
29562966
/* Always throws */

ext/opcache/jit/zend_jit_trace.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1445,6 +1445,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
14451445
case ZEND_ECHO:
14461446
case ZEND_STRLEN:
14471447
case ZEND_QM_ASSIGN:
1448+
case ZEND_FE_FETCH_R:
14481449
ADD_OP1_TRACE_GUARD();
14491450
break;
14501451
case ZEND_VERIFY_RETURN_TYPE:
@@ -4540,6 +4541,39 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
45404541
goto jit_failure;
45414542
}
45424543
goto done;
4544+
case ZEND_FE_FETCH_R:
4545+
op1_info = OP1_INFO();
4546+
CHECK_OP1_TRACE_TYPE();
4547+
if ((op1_info & MAY_BE_ANY) != MAY_BE_ARRAY) {
4548+
break;
4549+
}
4550+
if ((p+1)->op == ZEND_JIT_TRACE_VM || (p+1)->op == ZEND_JIT_TRACE_END) {
4551+
const zend_op *exit_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
4552+
uint32_t exit_point;
4553+
4554+
if ((p+1)->opline == exit_opline) {
4555+
/* taken branch (exit from loop) */
4556+
exit_opline = opline;
4557+
smart_branch_opcode = ZEND_NOP;
4558+
} else if ((p+1)->opline == opline + 1) {
4559+
/* not taken branch (loop) */
4560+
smart_branch_opcode = ZEND_JMP;
4561+
} else {
4562+
ZEND_UNREACHABLE();
4563+
}
4564+
exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
4565+
exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4566+
if (!exit_addr) {
4567+
goto jit_failure;
4568+
}
4569+
} else {
4570+
ZEND_UNREACHABLE();
4571+
}
4572+
if (!zend_jit_fe_fetch(&dasm_state, opline, op_array, ssa, ssa_op,
4573+
op1_info, -1, smart_branch_opcode, exit_addr)) {
4574+
goto jit_failure;
4575+
}
4576+
goto done;
45434577
case ZEND_INIT_METHOD_CALL:
45444578
case ZEND_INIT_DYNAMIC_CALL:
45454579
if (!zend_jit_trace_handler(&dasm_state, op_array, opline, zend_may_throw(opline, ssa_op, op_array, ssa), p + 1)) {

ext/opcache/jit/zend_jit_x86.dasc

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12530,6 +12530,136 @@ static int zend_jit_isset_isempty_cv(dasm_State **Dst, const zend_op *opline, ui
1253012530
return 1;
1253112531
}
1253212532

12533+
static int zend_jit_fe_fetch(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, const zend_ssa *ssa, const zend_ssa_op *ssa_op, uint32_t op1_info, unsigned int target_label, zend_uchar exit_opcode, const void *exit_addr)
12534+
{
12535+
zend_jit_addr op1_addr = OP1_ADDR();
12536+
12537+
| // array = EX_VAR(opline->op1.var);
12538+
| // fe_ht = Z_ARRVAL_P(array);
12539+
| GET_ZVAL_PTR FCARG2a, op1_addr
12540+
| // pos = Z_FE_POS_P(array);
12541+
| mov FCARG1d, dword [FP + opline->op1.var + offsetof(zval, u2.fe_pos)]
12542+
| // p = fe_ht->arData + pos;
12543+
|.if X64
12544+
| movsxd r0, FCARG1d
12545+
| shl r0, 5
12546+
|.else
12547+
| imul r0, FCARG1a, sizeof(Bucket)
12548+
|.endif
12549+
| add r0, aword [FCARG2a + offsetof(zend_array, arData)]
12550+
|1:
12551+
| // if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
12552+
| cmp dword [FCARG2a + offsetof(zend_array, nNumUsed)], FCARG1d
12553+
| // ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
12554+
| // ZEND_VM_CONTINUE();
12555+
if (exit_addr) {
12556+
if (exit_opcode == ZEND_JMP) {
12557+
| jbe &exit_addr
12558+
} else {
12559+
| jbe >3
12560+
}
12561+
} else {
12562+
| jbe =>target_label
12563+
}
12564+
| // pos++;
12565+
| add FCARG1d, 1
12566+
| // value_type = Z_TYPE_INFO_P(value);
12567+
| // if (EXPECTED(value_type != IS_UNDEF)) {
12568+
| IF_Z_TYPE r0, IS_UNDEF, >2
12569+
if (!exit_addr || exit_opcode == ZEND_JMP) {
12570+
| IF_NOT_Z_TYPE r0, IS_INDIRECT, >3
12571+
} else {
12572+
| IF_NOT_Z_TYPE r0, IS_INDIRECT, &exit_addr
12573+
}
12574+
| // value = Z_INDIRECT_P(value);
12575+
| GET_Z_PTR FCARG2a, r0
12576+
| // value_type = Z_TYPE_INFO_P(value);
12577+
| // if (EXPECTED(value_type != IS_UNDEF)) {
12578+
if (!exit_addr || exit_opcode == ZEND_JMP) {
12579+
| IF_NOT_Z_TYPE FCARG2a, IS_UNDEF, >4
12580+
} else {
12581+
| IF_NOT_Z_TYPE r0, IS_UNDEF, &exit_addr
12582+
}
12583+
| GET_ZVAL_PTR FCARG2a, op1_addr // reload
12584+
|2:
12585+
| // p++;
12586+
| add r0, sizeof(Bucket)
12587+
| jmp <1
12588+
|3:
12589+
12590+
if (!exit_addr || exit_opcode == ZEND_JMP) {
12591+
zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2a, 0);
12592+
zend_jit_addr var_addr = OP2_ADDR();
12593+
uint32_t val_info;
12594+
12595+
| mov FCARG2a, r0
12596+
|4:
12597+
| // Z_FE_POS_P(array) = pos + 1;
12598+
| mov dword [FP + opline->op1.var + offsetof(zval, u2.fe_pos)], FCARG1d
12599+
12600+
if (RETURN_VALUE_USED(opline)) {
12601+
zend_jit_addr res_addr = RES_ADDR();
12602+
12603+
if ((op1_info & MAY_BE_ARRAY_KEY_LONG)
12604+
&& (op1_info & MAY_BE_ARRAY_KEY_STRING)) {
12605+
| // if (!p->key) {
12606+
| cmp aword [r0 + offsetof(Bucket, key)], 0
12607+
| jz >2
12608+
}
12609+
if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
12610+
| // ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
12611+
| mov FCARG1a, aword [r0 + offsetof(Bucket, key)]
12612+
| SET_ZVAL_PTR res_addr, FCARG1a
12613+
| test dword [FCARG1a + offsetof(zend_refcounted, gc.u.type_info)], IS_STR_INTERNED
12614+
| jz >1
12615+
| SET_ZVAL_TYPE_INFO res_addr, IS_STRING
12616+
| jmp >3
12617+
|1:
12618+
| GC_ADDREF FCARG1a
12619+
| SET_ZVAL_TYPE_INFO res_addr, IS_STRING_EX
12620+
12621+
if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
12622+
| jmp >3
12623+
|2:
12624+
}
12625+
}
12626+
if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
12627+
| // ZVAL_LONG(EX_VAR(opline->result.var), p->h);
12628+
| mov FCARG1a, aword [r0 + offsetof(Bucket, h)]
12629+
| SET_ZVAL_LVAL res_addr, FCARG1a
12630+
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG
12631+
}
12632+
|3:
12633+
}
12634+
12635+
val_info = ((op1_info & MAY_BE_ARRAY_OF_ANY) >> MAY_BE_ARRAY_SHIFT);
12636+
if (val_info & MAY_BE_ARRAY) {
12637+
val_info |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
12638+
}
12639+
if (op1_info & MAY_BE_ARRAY_OF_REF) {
12640+
val_info |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY |
12641+
MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
12642+
} else if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
12643+
val_info |= MAY_BE_RC1 | MAY_BE_RCN;
12644+
}
12645+
12646+
if (opline->op2_type == IS_CV) {
12647+
| // zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES());
12648+
if (!zend_jit_assign_to_variable(Dst, opline, var_addr, var_addr, OP2_INFO(), -1, IS_CV, opline->op2, val_addr, val_info, 0, 1)) {
12649+
return 0;
12650+
}
12651+
} else {
12652+
| // ZVAL_COPY(res, value);
12653+
| ZVAL_COPY_VALUE var_addr, -1, val_addr, val_info, ZREG_R0, ZREG_FCARG1a
12654+
if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
12655+
| TRY_ADDREF op1_info, ah, FCARG1a
12656+
}
12657+
}
12658+
}
12659+
12660+
return 1;
12661+
}
12662+
1253312663
static zend_bool zend_jit_noref_guard(dasm_State **Dst, const zend_op *opline, zend_jit_addr var_addr)
1253412664
{
1253512665
int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);

0 commit comments

Comments
 (0)