Skip to content

Commit 225cd9d

Browse files
committed
Improved JIT for VERIFY_RETURN_TYPE
1 parent 3e800e9 commit 225cd9d

File tree

2 files changed

+97
-42
lines changed

2 files changed

+97
-42
lines changed

ext/opcache/jit/zend_jit_trace.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,6 +1447,21 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
14471447
case ZEND_QM_ASSIGN:
14481448
ADD_OP1_TRACE_GUARD();
14491449
break;
1450+
case ZEND_VERIFY_RETURN_TYPE:
1451+
if (opline->op1_type == IS_UNUSED) {
1452+
/* Always throws */
1453+
break;
1454+
}
1455+
if (opline->op1_type == IS_CONST) {
1456+
/* TODO Different instruction format, has return value */
1457+
break;
1458+
}
1459+
if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
1460+
/* Not worth bothering with */
1461+
break;
1462+
}
1463+
ADD_OP1_TRACE_GUARD();
1464+
break;
14501465
case ZEND_FETCH_DIM_FUNC_ARG:
14511466
if (!frame
14521467
|| !frame->call
@@ -4502,6 +4517,29 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
45024517
goto jit_failure;
45034518
}
45044519
goto done;
4520+
case ZEND_VERIFY_RETURN_TYPE:
4521+
if (opline->op1_type == IS_UNUSED) {
4522+
/* Always throws */
4523+
break;
4524+
}
4525+
if (opline->op1_type == IS_CONST) {
4526+
/* TODO Different instruction format, has return value */
4527+
break;
4528+
}
4529+
if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
4530+
/* Not worth bothering with */
4531+
break;
4532+
}
4533+
op1_info = OP1_INFO();
4534+
CHECK_OP1_TRACE_TYPE();
4535+
if (op1_info & MAY_BE_REF) {
4536+
/* TODO May need reference unwrapping. */
4537+
break;
4538+
}
4539+
if (!zend_jit_verify_return_type(&dasm_state, opline, op_array, op1_info)) {
4540+
goto jit_failure;
4541+
}
4542+
goto done;
45054543
case ZEND_INIT_METHOD_CALL:
45064544
case ZEND_INIT_DYNAMIC_CALL:
45074545
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: 59 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,11 @@ static void* dasm_labels[zend_lb_MAX];
483483
| mov dword [zv+offsetof(zval,u1.type_info)], type
484484
|.endmacro
485485

486+
|.macro GET_ZVAL_TYPE, reg, addr
487+
|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
488+
| mov reg, byte [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval,u1.v.type)]
489+
|.endmacro
490+
486491
|.macro GET_ZVAL_TYPE_INFO, reg, addr
487492
|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
488493
| mov reg, dword [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval,u1.type_info)]
@@ -12393,53 +12398,65 @@ static zend_bool zend_jit_verify_return_type(dasm_State **Dst, const zend_op *op
1239312398
zend_arg_info *arg_info = &op_array->arg_info[-1];
1239412399
ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type));
1239512400
zend_jit_addr op1_addr = OP1_ADDR();
12396-
12397-
| LOAD_ZVAL_ADDR r0, op1_addr
12398-
12401+
zend_bool needs_slow_check = 1;
12402+
zend_bool slow_check_in_cold = 1;
1239912403
uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
12404+
1240012405
if (type_mask == 0) {
12401-
| jmp >7
12402-
} else if (is_power_of_two(type_mask)) {
12403-
uint32_t type_code = concrete_type(type_mask);
12404-
| cmp byte [r0 + 8], type_code
12405-
| jne >7
12406+
slow_check_in_cold = 0;
1240612407
} else {
12407-
| mov edx, 1
12408-
| mov cl, byte [r0 + 8]
12409-
| shl edx, cl
12410-
| test edx, type_mask
12411-
| je >7
12412-
}
12413-
|.cold_code
12414-
|7:
12415-
| SAVE_VALID_OPLINE opline, r1
12416-
if (op1_info & MAY_BE_UNDEF) {
12417-
| IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >8
12418-
| mov FCARG1a, opline->op1.var
12419-
| EXT_CALL zend_jit_undefined_op_helper, FCARG2a
12420-
| LOAD_ADDR_ZTS r0, executor_globals, uninitialized_zval
12408+
if (((op1_info & MAY_BE_ANY) & type_mask) == 0) {
12409+
slow_check_in_cold = 0;
12410+
} else if (((op1_info & MAY_BE_ANY) | type_mask) == type_mask) {
12411+
needs_slow_check = 0;
12412+
} else if (is_power_of_two(type_mask)) {
12413+
uint32_t type_code = concrete_type(type_mask);
12414+
| IF_NOT_ZVAL_TYPE op1_addr, type_code, >7
12415+
} else {
12416+
| mov edx, 1
12417+
| GET_ZVAL_TYPE cl, op1_addr
12418+
| shl edx, cl
12419+
| test edx, type_mask
12420+
| je >7
12421+
}
1242112422
}
12422-
|8:
12423-
| mov FCARG1a, r0
12424-
| mov r0, EX->run_time_cache
12425-
| add r0, opline->op2.num
12426-
| mov FCARG2a, EX->func
12427-
|.if X64
12428-
| LOAD_ADDR CARG3, (ptrdiff_t)arg_info
12429-
| mov CARG4, r0
12430-
| EXT_CALL zend_jit_verify_return_slow, r0
12431-
|.else
12432-
| sub r4, 8
12433-
| push r0
12434-
| push (ptrdiff_t)arg_info
12435-
| EXT_CALL zend_jit_verify_return_slow, r0
12436-
| add r4, 8
12437-
|.endif
12438-
if (!zend_jit_check_exception(Dst)) {
12439-
return 0;
12423+
if (needs_slow_check) {
12424+
if (slow_check_in_cold) {
12425+
|.cold_code
12426+
|7:
12427+
}
12428+
| SAVE_VALID_OPLINE opline, r1
12429+
if (op1_info & MAY_BE_UNDEF) {
12430+
| IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >8
12431+
| mov FCARG1a, opline->op1.var
12432+
| EXT_CALL zend_jit_undefined_op_helper, FCARG2a
12433+
| LOAD_ADDR_ZTS r0, executor_globals, uninitialized_zval
12434+
}
12435+
|8:
12436+
| LOAD_ZVAL_ADDR FCARG1a, op1_addr
12437+
| mov FCARG2a, EX->func
12438+
|.if X64
12439+
| LOAD_ADDR CARG3, (ptrdiff_t)arg_info
12440+
| mov r0, EX->run_time_cache
12441+
| lea CARG4, aword [r0+opline->op2.num]
12442+
| EXT_CALL zend_jit_verify_return_slow, r0
12443+
|.else
12444+
| sub r4, 8
12445+
| mov r0, EX->run_time_cache
12446+
| add r0, opline->op2.num
12447+
| push r0
12448+
| push (ptrdiff_t)arg_info
12449+
| EXT_CALL zend_jit_verify_return_slow, r0
12450+
| add r4, 8
12451+
|.endif
12452+
if (!zend_jit_check_exception(Dst)) {
12453+
return 0;
12454+
}
12455+
if (slow_check_in_cold) {
12456+
| jmp >9
12457+
|.code
12458+
}
1244012459
}
12441-
| jmp >9
12442-
|.code
1244312460
|9:
1244412461
return 1;
1244512462
}

0 commit comments

Comments
 (0)