@@ -3565,6 +3565,11 @@ static int zend_jit_store_const(dasm_State **Dst, int var, zend_reg reg)
3565
3565
| SET_ZVAL_TYPE_INFO dst, IS_DOUBLE
3566
3566
} else if (reg == ZREG_NULL) {
3567
3567
| SET_ZVAL_TYPE_INFO dst, IS_NULL
3568
+ } else if (reg == ZREG_ZVAL_TRY_ADDREF) {
3569
+ | IF_NOT_ZVAL_REFCOUNTED dst, >1
3570
+ | GET_ZVAL_PTR r1, dst
3571
+ | GC_ADDREF r1
3572
+ |1:
3568
3573
} else if (reg == ZREG_ZVAL_COPY_R0) {
3569
3574
zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
3570
3575
@@ -4811,14 +4816,15 @@ static int zend_jit_concat(dasm_State **Dst, const zend_op *opline, const zend_o
4811
4816
return zend_jit_concat_helper(Dst, opline, op_array, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, res_addr, res_info, may_throw);
4812
4817
}
4813
4818
4814
- static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_op *opline, uint32_t type, uint32_t op1_info, uint32_t op2_info, uint32_t found, uint32_t not_found, const void *found_exit_addr, const void *not_found_exit_addr)
4819
+ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_op *opline, uint32_t type, uint32_t op1_info, uint32_t op2_info, uint32_t found, uint32_t not_found, const void *found_exit_addr, const void *not_found_exit_addr, const void *exit_addr )
4815
4820
/* Labels: 1,2,3,4,5 */
4816
4821
{
4817
4822
zend_jit_addr op2_addr = OP2_ADDR();
4818
4823
zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
4819
- const void *exit_addr = NULL;
4820
4824
4821
- if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && (type == BP_VAR_R || type == BP_VAR_RW)) {
4825
+ if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
4826
+ && (type == BP_VAR_R || type == BP_VAR_RW)
4827
+ && !exit_addr) {
4822
4828
int32_t exit_point = zend_jit_trace_get_exit_point(opline, opline, NULL, ZEND_JIT_EXIT_TO_VM);
4823
4829
exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4824
4830
if (!exit_addr) {
@@ -5642,7 +5648,7 @@ static int zend_jit_assign_dim(dasm_State **Dst, const zend_op *opline, const ze
5642
5648
uint32_t var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0);
5643
5649
zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
5644
5650
5645
- if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_VAR_W, op1_info, op2_info, 8, 8, NULL, NULL)) {
5651
+ if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_VAR_W, op1_info, op2_info, 8, 8, NULL, NULL, NULL )) {
5646
5652
return 0;
5647
5653
}
5648
5654
@@ -5869,7 +5875,7 @@ static int zend_jit_assign_dim_op(dasm_State **Dst, const zend_op *opline, const
5869
5875
var_info |= MAY_BE_RC1;
5870
5876
}
5871
5877
5872
- if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_VAR_RW, op1_info, op2_info, 8, 8, NULL, NULL)) {
5878
+ if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_VAR_RW, op1_info, op2_info, 8, 8, NULL, NULL, NULL )) {
5873
5879
return 0;
5874
5880
}
5875
5881
@@ -10256,6 +10262,45 @@ static int zend_jit_zval_copy_deref(dasm_State **Dst, zend_jit_addr res_addr, ze
10256
10262
return 1;
10257
10263
}
10258
10264
10265
+ static zend_bool zend_jit_may_avoid_refcounting(const zend_op *opline)
10266
+ {
10267
+ switch (opline->opcode) {
10268
+ case ZEND_FETCH_OBJ_FUNC_ARG:
10269
+ if (!JIT_G(current_frame) ||
10270
+ !JIT_G(current_frame) ||
10271
+ !JIT_G(current_frame)->call->func ||
10272
+ !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
10273
+ return 0;
10274
+ }
10275
+ /* break missing intentionally */
10276
+ case ZEND_FETCH_OBJ_R:
10277
+ case ZEND_FETCH_OBJ_IS:
10278
+ if (opline->op2_type == IS_CONST
10279
+ && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_STRING
10280
+ && Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] != '\0') {
10281
+ return 1;
10282
+ }
10283
+ break;
10284
+ case ZEND_FETCH_DIM_FUNC_ARG:
10285
+ if (!JIT_G(current_frame) ||
10286
+ !JIT_G(current_frame) ||
10287
+ !JIT_G(current_frame)->call->func ||
10288
+ !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
10289
+ return 0;
10290
+ }
10291
+ /* break missing intentionally */
10292
+ case ZEND_FETCH_DIM_R:
10293
+ case ZEND_FETCH_DIM_IS:
10294
+ return 1;
10295
+ case ZEND_ISSET_ISEMPTY_DIM_OBJ:
10296
+ if (!(opline->extended_value & ZEND_ISEMPTY)) {
10297
+ return 1;
10298
+ }
10299
+ break;
10300
+ }
10301
+ return 0;
10302
+ }
10303
+
10259
10304
static int zend_jit_fetch_dim_read(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, const zend_ssa_op *ssa_op, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, uint32_t res_info, int may_throw)
10260
10305
{
10261
10306
zend_jit_addr orig_op1_addr, op2_addr, res_addr;
@@ -10277,6 +10322,11 @@ static int zend_jit_fetch_dim_read(dasm_State **Dst, const zend_op *opline, cons
10277
10322
}
10278
10323
}
10279
10324
10325
+ if (op1_info & AVOID_REFCOUNTING) {
10326
+ SET_STACK_REG(JIT_G(current_frame)->stack,
10327
+ EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
10328
+ }
10329
+
10280
10330
if ((res_info & MAY_BE_GUARD)
10281
10331
&& JIT_G(current_frame)
10282
10332
&& (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
@@ -10285,13 +10335,20 @@ static int zend_jit_fetch_dim_read(dasm_State **Dst, const zend_op *opline, cons
10285
10335
zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
10286
10336
int32_t exit_point;
10287
10337
10288
- if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
10338
+ if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
10339
+ && !(op1_info & AVOID_REFCOUNTING)) {
10289
10340
flags = ZEND_JIT_EXIT_FREE_OP1;
10290
10341
}
10291
10342
if ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
10292
10343
&& (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
10293
10344
flags = ZEND_JIT_EXIT_FREE_OP2;
10294
10345
}
10346
+ if ((res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
10347
+ && (ssa_op+1)->op1_use == ssa_op->result_def
10348
+ && zend_jit_may_avoid_refcounting(opline+1)) {
10349
+ res_info |= AVOID_REFCOUNTING;
10350
+ ssa->var_info[ssa_op->result_def].type |= AVOID_REFCOUNTING;
10351
+ }
10295
10352
old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
10296
10353
SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN);
10297
10354
SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_ZVAL_COPY_R0);
@@ -10332,7 +10389,7 @@ static int zend_jit_fetch_dim_read(dasm_State **Dst, const zend_op *opline, cons
10332
10389
}
10333
10390
}
10334
10391
| GET_ZVAL_LVAL ZREG_FCARG1a, op1_addr
10335
- if (!zend_jit_fetch_dimension_address_inner(Dst, opline, (opline->opcode != ZEND_FETCH_DIM_IS) ? BP_VAR_R : BP_VAR_IS, op1_info, op2_info, 8, 9, NULL, not_found_exit_addr)) {
10392
+ if (!zend_jit_fetch_dimension_address_inner(Dst, opline, (opline->opcode != ZEND_FETCH_DIM_IS) ? BP_VAR_R : BP_VAR_IS, op1_info, op2_info, 8, 9, NULL, not_found_exit_addr, exit_addr )) {
10336
10393
return 0;
10337
10394
}
10338
10395
}
@@ -10473,7 +10530,9 @@ static int zend_jit_fetch_dim_read(dasm_State **Dst, const zend_op *opline, cons
10473
10530
| IF_NOT_ZVAL_TYPE val_addr, type, &res_exit_addr
10474
10531
| // ZVAL_COPY
10475
10532
| ZVAL_COPY_VALUE res_addr, -1, val_addr, res_info, ZREG_R1, ZREG_R2
10476
- | TRY_ADDREF res_info, ch, r2
10533
+ if (!(res_info & AVOID_REFCOUNTING)) {
10534
+ | TRY_ADDREF res_info, ch, r2
10535
+ }
10477
10536
} else if (op1_info & MAY_BE_ARRAY_OF_REF) {
10478
10537
| // ZVAL_COPY_DEREF
10479
10538
| GET_ZVAL_TYPE_INFO Rd(ZREG_R2), val_addr
@@ -10496,7 +10555,9 @@ static int zend_jit_fetch_dim_read(dasm_State **Dst, const zend_op *opline, cons
10496
10555
#endif
10497
10556
10498
10557
| FREE_OP opline->op2_type, opline->op2, op2_info, 0, op_array, opline
10499
- | FREE_OP opline->op1_type, opline->op1, op1_info, 0, op_array, opline
10558
+ if (!(op1_info & AVOID_REFCOUNTING)) {
10559
+ | FREE_OP opline->op1_type, opline->op1, op1_info, 0, op_array, opline
10560
+ }
10500
10561
10501
10562
if (may_throw) {
10502
10563
if (!zend_jit_check_exception(Dst)) {
@@ -10542,7 +10603,7 @@ static int zend_jit_isset_isempty_dim(dasm_State **Dst, const zend_op *opline, c
10542
10603
not_found_exit_addr = exit_addr;
10543
10604
}
10544
10605
}
10545
- if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_JIT_IS, op1_info, op2_info, 8, 9, found_exit_addr, not_found_exit_addr)) {
10606
+ if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_JIT_IS, op1_info, op2_info, 8, 9, found_exit_addr, not_found_exit_addr, NULL )) {
10546
10607
return 0;
10547
10608
}
10548
10609
@@ -10602,7 +10663,9 @@ static int zend_jit_isset_isempty_dim(dasm_State **Dst, const zend_op *opline, c
10602
10663
10603
10664
|8:
10604
10665
| FREE_OP opline->op2_type, opline->op2, op2_info, 0, op_array, opline
10605
- | FREE_OP opline->op1_type, opline->op1, op1_info, 0, op_array, opline
10666
+ if (!(op1_info & AVOID_REFCOUNTING)) {
10667
+ | FREE_OP opline->op1_type, opline->op1, op1_info, 0, op_array, opline
10668
+ }
10606
10669
if (may_throw) {
10607
10670
if (!zend_jit_check_exception_undef_result(Dst, opline)) {
10608
10671
return 0;
@@ -10636,7 +10699,9 @@ static int zend_jit_isset_isempty_dim(dasm_State **Dst, const zend_op *opline, c
10636
10699
10637
10700
|9: // not found
10638
10701
| FREE_OP opline->op2_type, opline->op2, op2_info, 0, op_array, opline
10639
- | FREE_OP opline->op1_type, opline->op1, op1_info, 0, op_array, opline
10702
+ if (!(op1_info & AVOID_REFCOUNTING)) {
10703
+ | FREE_OP opline->op1_type, opline->op1, op1_info, 0, op_array, opline
10704
+ }
10640
10705
if (may_throw) {
10641
10706
if (!zend_jit_check_exception_undef_result(Dst, opline)) {
10642
10707
return 0;
@@ -11233,6 +11298,10 @@ static int zend_jit_fetch_obj(dasm_State **Dst, const zend_op *opline, const zen
11233
11298
}
11234
11299
}
11235
11300
}
11301
+ if (op1_info & AVOID_REFCOUNTING) {
11302
+ SET_STACK_REG(JIT_G(current_frame)->stack,
11303
+ EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
11304
+ }
11236
11305
if (opline->opcode == ZEND_FETCH_OBJ_W) {
11237
11306
if (Z_REG(prop_addr) != ZREG_FCARG1a || Z_OFFSET(prop_addr) != 0) {
11238
11307
| LOAD_ZVAL_ADDR FCARG1a, prop_addr
@@ -11251,12 +11320,21 @@ static int zend_jit_fetch_obj(dasm_State **Dst, const zend_op *opline, const zen
11251
11320
zend_uchar type;
11252
11321
zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
11253
11322
11254
- if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !use_this) {
11323
+ if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
11324
+ && !use_this
11325
+ && !(op1_info & AVOID_REFCOUNTING)) {
11255
11326
flags = ZEND_JIT_EXIT_FREE_OP1;
11256
11327
}
11257
11328
11258
11329
| LOAD_ZVAL_ADDR r0, prop_addr
11259
11330
11331
+ if ((res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
11332
+ && (ssa_op+1)->op1_use == ssa_op->result_def
11333
+ && zend_jit_may_avoid_refcounting(opline+1)) {
11334
+ res_info |= AVOID_REFCOUNTING;
11335
+ ssa->var_info[ssa_op->result_def].type |= AVOID_REFCOUNTING;
11336
+ }
11337
+
11260
11338
old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
11261
11339
SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN);
11262
11340
SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_ZVAL_COPY_R0);
@@ -11289,7 +11367,9 @@ static int zend_jit_fetch_obj(dasm_State **Dst, const zend_op *opline, const zen
11289
11367
| SET_ZVAL_TYPE_INFO res_addr, type
11290
11368
} else {
11291
11369
| SET_ZVAL_TYPE_INFO res_addr, edx
11292
- | TRY_ADDREF res_info, dh, r1
11370
+ if (!(res_info & AVOID_REFCOUNTING)) {
11371
+ | TRY_ADDREF res_info, dh, r1
11372
+ }
11293
11373
}
11294
11374
} else {
11295
11375
if (!zend_jit_zval_copy_deref(Dst, res_addr, prop_addr, ZREG_R2)) {
@@ -11375,7 +11455,7 @@ static int zend_jit_fetch_obj(dasm_State **Dst, const zend_op *opline, const zen
11375
11455
| SAVE_VALID_OPLINE opline, r0
11376
11456
| EXT_CALL zend_jit_extract_helper, r0
11377
11457
|1:
11378
- } else {
11458
+ } else if (!(op1_info & AVOID_REFCOUNTING)) {
11379
11459
| FREE_OP opline->op1_type, opline->op1, op1_info, 1, op_array, opline
11380
11460
}
11381
11461
}
0 commit comments