Skip to content

Commit 99118a6

Browse files
shqkingdstogov
authored andcommitted
Support failed JIT test case: fetch_dim_func_args_001.phpt
1. For statement "$a->change($a = array("a" => range(1, 5)));", the following opcodes will be generated: 0002 ASSIGN CV0($a) V1 0003 INIT_METHOD_CALL 1 CV0($a) string("change") 0004 INIT_NS_FCALL_BY_NAME 2 string("A\range") 0005 SEND_VAL_EX int(1) 1 0006 SEND_VAL_EX int(5) 2 0007 V1 = DO_FCALL_BY_NAME The updates in function zend_jit_init_fcall(), zend_jit_send_val() and zend_jit_do_fcall() are made to support INIT_NS_FCALL_BY_NAME, SEND_VAL_EX and DO_FCALL_BY_NAME respectively. 2. For method $change(), opcode RECV is used to obtain the argument: 0000 #1.CV0($config) [rc1, rcn, array of [any, ref]] = RECV 1 Accordingly the updates in functions zend_jit_recv() and zend_jit_verify_arg_type() are made. 3. For statement "array_keys($config["a"])", the following opcodes will be generated: 0001 INIT_NS_FCALL_BY_NAME 1 string("A\array_keys") 0002 CHECK_FUNC_ARG 1 0003 php#3.V1 [ref, rc1, rcn, any] = FETCH_DIM_FUNC_ARG #1.CV0($config) ... -> #2.CV0($config) [rc1, rcn, ... 0004 SEND_FUNC_ARG php#3.V1 [ref, rc1, rcn, any] 1 0005 php#4.V1 [ref, rc1, rcn, any] = DO_FCALL_BY_NAME CHECK_FUNC_ARG and SEND_FUNC_ARG are not supported before. See the updates in functions zend_jit_check_func_arg() and zend_jit_send_var(). Besides, a new path is covered in macro OBJ_RELEASE when leaving.
1 parent 3748319 commit 99118a6

File tree

1 file changed

+204
-9
lines changed

1 file changed

+204
-9
lines changed

ext/opcache/jit/zend_jit_arm64.dasc

Lines changed: 204 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,7 +1136,6 @@ static void* dasm_labels[zend_lb_MAX];
11361136
|.macro OBJ_RELEASE, reg, exit_label, tmp_reg1, tmp_reg2
11371137
| GC_DELREF Rx(reg), Rw(tmp_reg1)
11381138
| bne >1
1139-
| brk #0 // TODO
11401139
| // zend_objects_store_del(obj);
11411140
|| if (reg != ZREG_FCARG1x) {
11421141
| mov FCARG1x, Rx(reg)
@@ -4706,13 +4705,14 @@ static int zend_jit_init_fcall(dasm_State **Dst, const zend_op *opline, uint32_t
47064705
} else if (opline->opcode == ZEND_INIT_FCALL_BY_NAME) {
47074706
| brk #0 // TODO
47084707
} else if (opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
4709-
| brk #0 // TODO
4708+
| LOAD_ADDR FCARG1x, zv;
4709+
| EXT_CALL zend_jit_find_ns_func_helper, REG0
47104710
} else {
47114711
ZEND_UNREACHABLE();
47124712
}
47134713
| // CACHE_PTR(opline->result.num, fbc);
47144714
| ldr REG1, EX->run_time_cache
4715-
| // Get the return value of function zend_jit_find_func_helper
4715+
| // Get the return value of function zend_jit_find_func_helper/zend_jit_find_ns_func_helper
47164716
| mov REG0, RETVALx
47174717
| str REG0, [REG1, #opline->result.num]
47184718
if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
@@ -5282,7 +5282,38 @@ static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, const zend
52825282
|8:
52835283
}
52845284
if (opline->opcode == ZEND_DO_FCALL_BY_NAME) {
5285-
| brk #0 // TODO
5285+
if (!func) {
5286+
if (trace) {
5287+
uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
5288+
5289+
exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5290+
if (!exit_addr) {
5291+
return 0;
5292+
}
5293+
| brk #0 // TODO
5294+
} else {
5295+
|| ZEND_ASSERT(ZEND_ACC_DEPRECATED <= MAX_IMM12);
5296+
| ldr TMP1w, [REG0, #offsetof(zend_op_array, fn_flags)]
5297+
| tst TMP1w, #ZEND_ACC_DEPRECATED
5298+
| bne >1
5299+
|.cold_code
5300+
|1:
5301+
| brk #0 // TODO
5302+
if (!GCC_GLOBAL_REGS) {
5303+
| mov FCARG1x, RX
5304+
}
5305+
| EXT_CALL zend_jit_deprecated_helper, REG0
5306+
| and RETVALw, RETVALw, #0xff
5307+
| cmp RETVALw, #0 // Result is 0 on exception
5308+
| ldr REG0, EX:RX->func // reload
5309+
| bne >1
5310+
| b ->exception_handler
5311+
|.code
5312+
|1:
5313+
}
5314+
} else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
5315+
| brk #0 // TODO
5316+
}
52865317
}
52875318

52885319
| // ZVAL_NULL(EX_VAR(opline->result.var));
@@ -5445,7 +5476,17 @@ static int zend_jit_send_val(dasm_State **Dst, const zend_op *opline, uint32_t o
54455476
}
54465477
| brk #0 // TODO
54475478
} else {
5448-
| brk #0 // TODO
5479+
| ldr REG0, EX:RX->func
5480+
| ldr TMP1w, [REG0, #offsetof(zend_function, quick_arg_flags)]
5481+
| LOAD_32BIT_VAL TMP2w, mask
5482+
| tst TMP1w, TMP2w
5483+
| bne >1
5484+
|.cold_code
5485+
|1:
5486+
| brk #0 // TODO
5487+
| SET_EX_OPLINE opline, REG0
5488+
| b ->throw_cannot_pass_by_ref
5489+
|.code
54495490
}
54505491
}
54515492

@@ -5504,7 +5545,30 @@ static int zend_jit_send_var(dasm_State **Dst, const zend_op *opline, const zend
55045545
} else if (opline->opcode == ZEND_SEND_VAR_NO_REF_EX) {
55055546
| brk #0 // TODO
55065547
} else if (opline->opcode == ZEND_SEND_FUNC_ARG) {
5507-
| brk #0 // TODO
5548+
if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
5549+
&& JIT_G(current_frame)
5550+
&& JIT_G(current_frame)->call
5551+
&& JIT_G(current_frame)->call->func) {
5552+
if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
5553+
if (!zend_jit_send_ref(Dst, opline, op_array, op1_info, 0)) {
5554+
return 0;
5555+
}
5556+
return 1;
5557+
}
5558+
} else {
5559+
| ldr TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)]
5560+
| LOAD_32BIT_VAL TMP2w, ZEND_CALL_SEND_ARG_BY_REF
5561+
| tst TMP1w, TMP2w
5562+
| bne >1
5563+
|.cold_code
5564+
|1:
5565+
| brk #0 // TODO
5566+
if (!zend_jit_send_ref(Dst, opline, op_array, op1_info, 1)) {
5567+
return 0;
5568+
}
5569+
| b >7
5570+
|.code
5571+
}
55085572
}
55095573

55105574
if (op1_info & MAY_BE_UNDEF) {
@@ -5579,7 +5643,42 @@ static int zend_jit_check_func_arg(dasm_State **Dst, const zend_op *opline)
55795643
{
55805644
uint32_t arg_num = opline->op2.num;
55815645

5582-
| brk #0 // TODO
5646+
if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
5647+
&& JIT_G(current_frame)
5648+
&& JIT_G(current_frame)->call
5649+
&& JIT_G(current_frame)->call->func) {
5650+
| brk #0 // TODO
5651+
} else {
5652+
// if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
5653+
uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
5654+
5655+
if (!zend_jit_reuse_ip(Dst)) {
5656+
return 0;
5657+
}
5658+
5659+
| ldr REG0, EX:RX->func
5660+
| ldr TMP1w, [REG0, #offsetof(zend_function, quick_arg_flags)]
5661+
| LOAD_32BIT_VAL TMP2w, mask
5662+
| tst TMP1w, TMP2w
5663+
| bne >1
5664+
|.cold_code
5665+
|1:
5666+
| brk #0 // TODO
5667+
| // ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
5668+
| ldr TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)]
5669+
| LOAD_32BIT_VAL TMP2w, ZEND_CALL_SEND_ARG_BY_REF
5670+
| orr TMP1w, TMP1w, TMP2w
5671+
| str TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)]
5672+
| b >1
5673+
|.code
5674+
| // ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
5675+
| ldr TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)]
5676+
| LOAD_32BIT_VAL TMP2w, ZEND_CALL_SEND_ARG_BY_REF
5677+
| mvn TMP2w, TMP2w
5678+
| and TMP1w, TMP1w, TMP2w
5679+
| str TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)]
5680+
|1:
5681+
}
55835682

55845683
return 1;
55855684
}
@@ -6160,7 +6259,59 @@ static int zend_jit_verify_arg_type(dasm_State **Dst, const zend_op *opline, zen
61606259
uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
61616260
zend_reg tmp_reg = (type_mask == 0 || is_power_of_two(type_mask)) ? ZREG_FCARG1x : ZREG_REG0;
61626261

6163-
| brk #0 // TODO
6262+
if (ZEND_ARG_SEND_MODE(arg_info)) {
6263+
| brk #0 // TODO
6264+
}
6265+
6266+
if (type_mask != 0) {
6267+
if (is_power_of_two(type_mask)) {
6268+
uint32_t type_code = concrete_type(type_mask);
6269+
|| ZEND_ASSERT(type_code <= MAX_IMM12);
6270+
| IF_NOT_ZVAL_TYPE res_addr, type_code, >1, TMP1w, TMP2
6271+
} else {
6272+
| brk #0 // TODO
6273+
}
6274+
6275+
|.cold_code
6276+
|1:
6277+
6278+
in_cold = 1;
6279+
}
6280+
6281+
| brk #0 // TODO: currently in cold code
6282+
if (Z_REG(res_addr) != ZREG_FCARG1x || Z_OFFSET(res_addr) != 0) {
6283+
| brk #0 // TODO
6284+
| LOAD_ZVAL_ADDR FCARG1x, res_addr
6285+
}
6286+
if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
6287+
| brk #0 // TODO
6288+
| SET_EX_OPLINE opline, REG0
6289+
} else {
6290+
| ADDR_STORE EX->opline, opline, REG0
6291+
}
6292+
| LOAD_ADDR FCARG2x, (ptrdiff_t)arg_info
6293+
| EXT_CALL zend_jit_verify_arg_slow, REG0
6294+
| mov REG0w, RETVALw
6295+
6296+
if (check_exception) {
6297+
| brk #0 // TODO
6298+
| and REG0w, REG0w, #0xff
6299+
| tst REG0w, REG0w
6300+
if (in_cold) {
6301+
| bne >1
6302+
| b ->exception_handler
6303+
|.code
6304+
|1:
6305+
} else {
6306+
| beq ->exception_handler
6307+
}
6308+
} else if (in_cold) {
6309+
| brk #0 // TODO
6310+
| b >1
6311+
|.code
6312+
|1:
6313+
}
6314+
61646315
return 1;
61656316
}
61666317

@@ -6169,7 +6320,51 @@ static int zend_jit_recv(dasm_State **Dst, const zend_op *opline, const zend_op_
61696320
uint32_t arg_num = opline->op1.num;
61706321
zend_arg_info *arg_info = NULL;
61716322

6172-
| brk #0 // TODO
6323+
if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
6324+
if (EXPECTED(arg_num <= op_array->num_args)) {
6325+
arg_info = &op_array->arg_info[arg_num-1];
6326+
} else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
6327+
arg_info = &op_array->arg_info[op_array->num_args];
6328+
}
6329+
if (arg_info && !ZEND_TYPE_IS_SET(arg_info->type)) {
6330+
arg_info = NULL;
6331+
}
6332+
}
6333+
6334+
if (arg_info || (opline+1)->opcode != ZEND_RECV) {
6335+
| ldr TMP1w, EX->This.u2.num_args
6336+
| LOAD_32BIT_VAL TMP2w, arg_num
6337+
| cmp TMP1w, TMP2w
6338+
if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
6339+
int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
6340+
const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
6341+
6342+
if (!exit_addr) {
6343+
return 0;
6344+
}
6345+
| brk #0 // TODO
6346+
} else {
6347+
| blt >1
6348+
|.cold_code
6349+
|1:
6350+
| brk #0 // TODO
6351+
|.code
6352+
}
6353+
}
6354+
6355+
if (arg_info) {
6356+
if (!zend_jit_verify_arg_type(Dst, opline, arg_info, 1)) {
6357+
return 0;
6358+
}
6359+
}
6360+
6361+
if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
6362+
if ((opline+1)->opcode != ZEND_RECV && (opline+1)->opcode != ZEND_RECV_INIT) {
6363+
| LOAD_IP_ADDR (opline + 1)
6364+
zend_jit_set_last_valid_opline(opline + 1);
6365+
}
6366+
}
6367+
61736368
return 1;
61746369
}
61756370

0 commit comments

Comments
 (0)