Skip to content

Commit 3748319

Browse files
shqkingdstogov
authored andcommitted
Support failed JIT test case: assign_035.phpt
1. For statement "echo $a->test()", opcode INIT_METHOD_CALL is involved. The updates in function zend_jit_init_method_call() and zend_jit_push_call_frame() are made to support it. 2. The updates in function zend_jit_leave_func() are made to support the RETURN opcode used in functions $closure and $test. 3. The updates in function zend_jit_assign_to_variable() are used to support statement "$x = $arr". 4. The updates in function zend_jit_fetch_dimension_address_inner() and zend_jit_simple_assign() are made to support statement "$x['a'] = $closure()", where opcode ASSIGN_DIM is involved.
1 parent 77b3d71 commit 3748319

File tree

1 file changed

+268
-12
lines changed

1 file changed

+268
-12
lines changed

ext/opcache/jit/zend_jit_arm64.dasc

Lines changed: 268 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,6 @@ static void* dasm_labels[zend_lb_MAX];
635635
|| if (Z_LVAL_P(Z_ZV(addr)) == 0) {
636636
| mov Rx(reg), xzr
637637
|| } else {
638-
| brk #0 // TODO: test
639638
| LOAD_64BIT_VAL Rx(reg), Z_LVAL_P(Z_ZV(addr))
640639
|| }
641640
|| } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
@@ -1001,7 +1000,7 @@ static void* dasm_labels[zend_lb_MAX];
10011000
|| } else if (type == IS_ARRAY) {
10021001
|| if ((var_info) & (MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF)) {
10031002
|| if (opline && ((var_info) & (MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF))) {
1004-
| brk #0 // TODO
1003+
| SET_EX_OPLINE opline, tmp_reg
10051004
|| }
10061005
| EXT_CALL zend_array_destroy, tmp_reg
10071006
|| } else {
@@ -3344,7 +3343,39 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
33443343
}
33453344

33463345
if (op2_info & MAY_BE_STRING) {
3347-
| brk #0 // TODO
3346+
|3:
3347+
if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
3348+
| // if (EXPECTED(Z_TYPE_P(dim) == IS_STRING))
3349+
| brk #0 // TODO
3350+
| IF_NOT_ZVAL_TYPE op2_addr, IS_STRING, >3, TMP1w, TMP2
3351+
}
3352+
| // offset_key = Z_STR_P(dim);
3353+
| GET_ZVAL_LVAL ZREG_FCARG2x, op2_addr, TMP1
3354+
| // retval = zend_hash_find(ht, offset_key);
3355+
switch (type) {
3356+
case BP_JIT_IS:
3357+
| brk #0 // TODO
3358+
break;
3359+
case BP_VAR_R:
3360+
case BP_VAR_IS:
3361+
case BP_VAR_UNSET:
3362+
| brk #0 // TODO
3363+
break;
3364+
case BP_VAR_RW:
3365+
| brk #0 // TODO
3366+
break;
3367+
case BP_VAR_W:
3368+
if (opline->op2_type != IS_CONST) {
3369+
| brk #0 // TODO
3370+
| EXT_CALL zend_jit_symtable_lookup_w, REG0
3371+
} else {
3372+
| EXT_CALL zend_hash_lookup, REG0
3373+
}
3374+
| mov REG0, RETVALx
3375+
break;
3376+
default:
3377+
ZEND_UNREACHABLE();
3378+
}
33483379
}
33493380

33503381
if (type == BP_JIT_IS && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))) {
@@ -3443,7 +3474,20 @@ static int zend_jit_simple_assign(dasm_State **Dst,
34433474
} else {
34443475
zend_jit_addr ref_addr;
34453476

3446-
| brk #0
3477+
if (in_cold) {
3478+
| brk #0 // TODO
3479+
| IF_NOT_ZVAL_TYPE val_addr, IS_REFERENCE, >1, TMP1w, TMP2
3480+
} else {
3481+
| IF_ZVAL_TYPE val_addr, IS_REFERENCE, >1, TMP1w, TMP2
3482+
|.cold_code
3483+
|1:
3484+
}
3485+
| brk #0 // TODO
3486+
if (in_cold) {
3487+
|1:
3488+
} else {
3489+
|.code
3490+
}
34473491
}
34483492
}
34493493

@@ -3595,13 +3639,14 @@ static int zend_jit_assign_to_variable(dasm_State **Dst,
35953639
if (RC_MAY_BE_N(var_info) && (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0) {
35963640
| bne >4
35973641
} else {
3598-
| brk #0 // TODO
3642+
| bne >8
35993643
}
3600-
| brk #0
36013644
| ZVAL_DTOR_FUNC var_info, opline, TMP1
36023645
if (in_cold || (RC_MAY_BE_N(var_info) && (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0)) {
36033646
if (check_exception) {
3604-
| brk #0 // TODO
3647+
| MEM_LOAD_CMP_ZTS ldr, xzr, executor_globals, exception, REG0, TMP1
3648+
| beq >8
3649+
| b ->exception_handler
36053650
} else {
36063651
| brk #0 // TODO
36073652
}
@@ -4380,7 +4425,30 @@ static int zend_jit_push_call_frame(dasm_State **Dst, const zend_op *opline, con
43804425
}
43814426
if (opline->opcode == ZEND_INIT_METHOD_CALL) {
43824427
| // Z_PTR(call->This) = obj;
4383-
| brk #0 // TODO
4428+
| ldr REG1, T1
4429+
| str REG1, EX:RX->This.value.ptr
4430+
if (opline->op1_type == IS_UNUSED || use_this) {
4431+
| // call->call_info |= ZEND_CALL_HAS_THIS;
4432+
if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
4433+
| brk #0 // TODO
4434+
} else {
4435+
| brk #0 // TODO
4436+
}
4437+
} else {
4438+
if (opline->op1_type == IS_CV) {
4439+
| // GC_ADDREF(obj);
4440+
| GC_ADDREF REG1, TMP1w
4441+
}
4442+
| // call->call_info |= ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS;
4443+
if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
4444+
| brk #0 // TODO
4445+
} else {
4446+
| ldr TMP1w, EX:RX->This.u1.type_info
4447+
| LOAD_32BIT_VAL TMP2w, (ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS)
4448+
| orr TMP1w, TMP1w, TMP2w
4449+
| str TMP1w, EX:RX->This.u1.type_info
4450+
}
4451+
}
43844452
} else if (!is_closure) {
43854453
| // Z_CE(call->This) = called_scope;
43864454
| str xzr, EX:RX->This.value.ptr
@@ -4700,7 +4768,183 @@ static int zend_jit_init_method_call(dasm_State **Dst,
47004768
ZEND_ASSERT(opline->op2_type == IS_CONST);
47014769
ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
47024770

4703-
| brk #0 // TODO
4771+
function_name = RT_CONSTANT(opline, opline->op2);
4772+
4773+
if (info) {
4774+
call_info = info->callee_info;
4775+
while (call_info && call_info->caller_init_opline != opline) {
4776+
call_info = call_info->next_callee;
4777+
}
4778+
if (call_info && call_info->callee_func && !call_info->is_prototype) {
4779+
func = call_info->callee_func;
4780+
}
4781+
}
4782+
4783+
if (polymorphic_side_trace) {
4784+
/* function is passed in r0 from parent_trace */
4785+
} else {
4786+
if (opline->op1_type == IS_UNUSED || use_this) {
4787+
zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
4788+
4789+
| brk #0 // TODO
4790+
| GET_ZVAL_PTR FCARG1x, this_addr, TMP1
4791+
} else {
4792+
if (op1_info & MAY_BE_REF) {
4793+
if (opline->op1_type == IS_CV) {
4794+
if (Z_REG(op1_addr) != ZREG_FCARG1x || Z_OFFSET(op1_addr) != 0) {
4795+
| LOAD_ZVAL_ADDR FCARG1x, op1_addr
4796+
}
4797+
| ZVAL_DEREF FCARG1x, op1_info, TMP1w
4798+
op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1x, 0);
4799+
} else {
4800+
/* Hack: Convert reference to regular value to simplify JIT code */
4801+
ZEND_ASSERT(Z_REG(op1_addr) == ZREG_FP);
4802+
| brk #0 // TODO
4803+
}
4804+
}
4805+
if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
4806+
if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
4807+
int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
4808+
const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4809+
4810+
if (!exit_addr) {
4811+
return 0;
4812+
}
4813+
| brk #0 // TODO
4814+
} else {
4815+
| IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >1, TMP1w, TMP2
4816+
|.cold_code
4817+
|1:
4818+
| brk #0 // TODO: currently not jump to cold code.
4819+
if (Z_REG(op1_addr) != ZREG_FCARG1x || Z_OFFSET(op1_addr) != 0) {
4820+
| LOAD_ZVAL_ADDR FCARG1x, op1_addr
4821+
}
4822+
| SET_EX_OPLINE opline, REG0
4823+
if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !use_this) {
4824+
| EXT_CALL zend_jit_invalid_method_call_tmp, REG0
4825+
} else {
4826+
| EXT_CALL zend_jit_invalid_method_call, REG0
4827+
}
4828+
| b ->exception_handler
4829+
|.code
4830+
}
4831+
}
4832+
| GET_ZVAL_PTR FCARG1x, op1_addr, TMP1
4833+
}
4834+
4835+
if (delayed_call_chain) {
4836+
if (!zend_jit_save_call_chain(Dst, delayed_call_level)) {
4837+
return 0;
4838+
}
4839+
}
4840+
4841+
| str FCARG1x, T1 // save
4842+
4843+
if (func) {
4844+
| // fbc = CACHED_PTR(opline->result.num + sizeof(void*));
4845+
| brk #0 // TODO
4846+
} else {
4847+
| // if (CACHED_PTR(opline->result.num) == obj->ce)) {
4848+
| ldr REG0, EX->run_time_cache
4849+
| LOAD_32BIT_VAL TMP1w, opline->result.num
4850+
| add TMP1, REG0, TMP1
4851+
| ldr REG2, [TMP1]
4852+
| ldr TMP1, [FCARG1x, #offsetof(zend_object, ce)]
4853+
| cmp REG2, TMP1
4854+
| bne >1
4855+
| brk #0 // TODO: currently jump to label 1.
4856+
| // fbc = CACHED_PTR(opline->result.num + sizeof(void*));
4857+
| LOAD_32BIT_VAL TMP1w, (opline->result.num + sizeof(void*))
4858+
| add TMP1, TMP1, REG0
4859+
| ldr REG0, [TMP1]
4860+
}
4861+
4862+
|.cold_code
4863+
|1:
4864+
| LOAD_ADDR FCARG2x, function_name
4865+
| mov CARG3, sp
4866+
| SET_EX_OPLINE opline, REG0
4867+
if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !use_this) {
4868+
| brk #0 // TODO
4869+
| EXT_CALL zend_jit_find_method_tmp_helper, REG0
4870+
} else {
4871+
| EXT_CALL zend_jit_find_method_helper, REG0
4872+
}
4873+
| mov REG0, RETVALx
4874+
| cbnz REG0, >2
4875+
| b ->exception_handler
4876+
|.code
4877+
|2:
4878+
}
4879+
4880+
if (!func
4881+
&& trace
4882+
&& trace->op == ZEND_JIT_TRACE_INIT_CALL
4883+
&& trace->func
4884+
) {
4885+
int32_t exit_point;
4886+
const void *exit_addr;
4887+
4888+
exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_METHOD_CALL);
4889+
exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4890+
if (!exit_addr) {
4891+
return 0;
4892+
}
4893+
4894+
func = (zend_function*)trace->func;
4895+
4896+
if (func->type == ZEND_USER_FUNCTION &&
4897+
(!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
4898+
(func->common.fn_flags & ZEND_ACC_CLOSURE) ||
4899+
!func->common.function_name)) {
4900+
const zend_op *opcodes = func->op_array.opcodes;
4901+
4902+
| brk #0 // TODO
4903+
} else {
4904+
| brk #0 // TODO
4905+
}
4906+
}
4907+
4908+
if (!func) {
4909+
| // if (fbc->common.fn_flags & ZEND_ACC_STATIC) {
4910+
| ldr TMP1w, [REG0, #offsetof(zend_function, common.fn_flags)]
4911+
|| ZEND_ASSERT(ZEND_ACC_STATIC <= MAX_IMM12);
4912+
| tst TMP1w, #ZEND_ACC_STATIC
4913+
| bne >1
4914+
|.cold_code
4915+
|1:
4916+
}
4917+
4918+
if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) != 0) {
4919+
| brk #0 // TODO
4920+
}
4921+
4922+
if (!func) {
4923+
| brk #0 // TODO
4924+
| b >9
4925+
|.code
4926+
}
4927+
4928+
if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) == 0) {
4929+
if (!zend_jit_push_call_frame(Dst, opline, NULL, func, 0, use_this, stack_check)) {
4930+
return 0;
4931+
}
4932+
}
4933+
4934+
if (!func) {
4935+
|9:
4936+
}
4937+
zend_jit_start_reuse_ip();
4938+
4939+
if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, trace)) {
4940+
if (!zend_jit_save_call_chain(Dst, call_level)) {
4941+
return 0;
4942+
}
4943+
} else {
4944+
delayed_call_chain = 1;
4945+
delayed_call_level = call_level;
4946+
}
4947+
47044948
return 1;
47054949
}
47064950

@@ -5502,15 +5746,27 @@ static int zend_jit_leave_func(dasm_State **Dst,
55025746
return 0;
55035747
}
55045748
}
5505-
| brk #0 // TODO: test
5749+
| // OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
5750+
| ldr FCARG1x, EX->func
5751+
| sub FCARG1x, FCARG1x, #sizeof(zend_object)
5752+
| OBJ_RELEASE ZREG_FCARG1x, >4, ZREG_TMP1, ZREG_TMP2
5753+
|4:
55065754
} else if (may_need_release_this) {
55075755
if (!left_frame) {
55085756
left_frame = 1;
55095757
if (!zend_jit_leave_frame(Dst)) {
55105758
return 0;
55115759
}
55125760
}
5513-
| brk #0 // TODO: test
5761+
| // if (call_info & ZEND_CALL_RELEASE_THIS)
5762+
| LOAD_32BIT_VAL TMP1w, ZEND_CALL_RELEASE_THIS
5763+
| tst FCARG1w, TMP1w
5764+
| beq >4
5765+
| // zend_object *object = Z_OBJ(execute_data->This);
5766+
| ldr FCARG1x, EX->This.value.obj
5767+
| // OBJ_RELEASE(object);
5768+
| OBJ_RELEASE ZREG_FCARG1x, >4, ZREG_TMP1, ZREG_TMP2
5769+
|4:
55145770
// TODO: avoid EG(excption) check for $this->foo() calls
55155771
may_throw = 1;
55165772
}
@@ -5846,7 +6102,7 @@ static int zend_jit_fetch_dim(dasm_State **Dst,
58466102
}
58476103

58486104
if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY))) {
5849-
| brk #7
6105+
| brk #0 // TODO
58506106
}
58516107

58526108
#ifdef ZEND_JIT_USE_RC_INFERENCE

0 commit comments

Comments
 (0)