@@ -11401,9 +11401,16 @@ static int zend_jit_fetch_this(dasm_State **Dst, const zend_op *opline, const ze
11401
11401
return 1;
11402
11402
}
11403
11403
11404
- static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa)
11404
+ static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, zend_jit_trace_rec *trace )
11405
11405
{
11406
11406
HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
11407
+ const zend_op *next_opline = NULL;
11408
+
11409
+ if (trace) {
11410
+ ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
11411
+ ZEND_ASSERT(trace->opline != NULL);
11412
+ next_opline = trace->opline;
11413
+ }
11407
11414
11408
11415
// TODO: Implement for match instructions
11409
11416
if (opline->opcode == ZEND_MATCH) {
@@ -11420,22 +11427,34 @@ static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_o
11420
11427
if (opline->opcode == ZEND_SWITCH_LONG) {
11421
11428
if (Z_TYPE_P(zv) == IS_LONG) {
11422
11429
jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
11423
- if (jump_zv != NULL) {
11424
- b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)) - op_array->opcodes];
11430
+ if (next_opline) {
11431
+ const zend_op *target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv));
11432
+
11433
+ ZEND_ASSERT(target == next_opline);
11425
11434
} else {
11426
- b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes];
11435
+ if (jump_zv != NULL) {
11436
+ b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)) - op_array->opcodes];
11437
+ } else {
11438
+ b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes];
11439
+ }
11440
+ | jmp =>b
11427
11441
}
11428
- | jmp =>b
11429
11442
}
11430
11443
} else if (opline->opcode == ZEND_SWITCH_STRING) {
11431
11444
if (Z_TYPE_P(zv) == IS_STRING) {
11432
11445
jump_zv = zend_hash_find_ex(jumptable, Z_STR_P(zv), 1);
11433
- if (jump_zv != NULL) {
11434
- b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)) - op_array->opcodes];
11446
+ if (next_opline) {
11447
+ const zend_op *target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv));
11448
+
11449
+ ZEND_ASSERT(target == next_opline);
11435
11450
} else {
11436
- b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes];
11451
+ if (jump_zv != NULL) {
11452
+ b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)) - op_array->opcodes];
11453
+ } else {
11454
+ b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes];
11455
+ }
11456
+ | jmp =>b
11437
11457
}
11438
- | jmp =>b
11439
11458
}
11440
11459
} else {
11441
11460
ZEND_UNREACHABLE();
@@ -11444,8 +11463,26 @@ static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_o
11444
11463
zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
11445
11464
uint32_t op1_info = OP1_INFO();
11446
11465
zend_jit_addr op1_addr = OP1_ADDR();
11447
- int b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes];
11466
+ const zend_op *default_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
11467
+ const zend_op *target;
11468
+ int default_b = ssa->cfg.map[default_opline - op_array->opcodes];
11469
+ int b;
11448
11470
zval *val;
11471
+ int32_t exit_point;
11472
+ const void *fallback_label = NULL;
11473
+ const void *default_label = NULL;
11474
+ const void *exit_addr;
11475
+
11476
+ if (next_opline) {
11477
+ if (next_opline != opline + 1) {
11478
+ exit_point = zend_jit_trace_get_exit_point(opline, opline + 1, NULL, 0);
11479
+ fallback_label = zend_jit_trace_get_exit_addr(exit_point);
11480
+ }
11481
+ if (next_opline != default_opline) {
11482
+ exit_point = zend_jit_trace_get_exit_point(opline, default_opline, NULL, 0);
11483
+ default_label = zend_jit_trace_get_exit_addr(exit_point);
11484
+ }
11485
+ }
11449
11486
11450
11487
if (opline->opcode == ZEND_SWITCH_LONG) {
11451
11488
if (op1_info & MAY_BE_LONG) {
@@ -11455,16 +11492,28 @@ static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_o
11455
11492
|.cold_code
11456
11493
|1:
11457
11494
| // ZVAL_DEREF(op)
11458
- | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, >3
11495
+ if (fallback_label) {
11496
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, &fallback_label
11497
+ } else {
11498
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, >3
11499
+ }
11459
11500
| GET_ZVAL_PTR FCARG2a, op1_addr
11460
- | IF_NOT_Z_TYPE FCARG2a + offsetof(zend_reference, val), IS_LONG, >3
11501
+ if (fallback_label) {
11502
+ | IF_NOT_Z_TYPE FCARG2a + offsetof(zend_reference, val), IS_LONG, &fallback_label
11503
+ } else {
11504
+ | IF_NOT_Z_TYPE FCARG2a + offsetof(zend_reference, val), IS_LONG, >3
11505
+ }
11461
11506
| mov FCARG2a, aword [FCARG2a + offsetof(zend_reference, val.value.lval)]
11462
11507
| jmp >2
11463
11508
|.code
11464
11509
|2:
11465
11510
} else {
11466
11511
if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
11467
- | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >3
11512
+ if (fallback_label) {
11513
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, &fallback_label
11514
+ } else {
11515
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >3
11516
+ }
11468
11517
}
11469
11518
| GET_ZVAL_LVAL ZREG_FCARG2a, op1_addr
11470
11519
}
@@ -11473,7 +11522,13 @@ static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_o
11473
11522
Bucket *p = jumptable->arData;
11474
11523
11475
11524
| cmp FCARG2a, jumptable->nNumUsed
11476
- | jae >3
11525
+ if (default_label) {
11526
+ | jae &default_label
11527
+ } else if (next_opline) {
11528
+ | jae >3
11529
+ } else {
11530
+ | jae =>default_b
11531
+ }
11477
11532
|.if X64
11478
11533
if (!IS_32BIT(dasm_end)) {
11479
11534
| lea r0, aword [>4]
@@ -11484,27 +11539,48 @@ static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_o
11484
11539
|.else
11485
11540
| jmp aword [FCARG2a * 4 + >4]
11486
11541
|.endif
11487
- |3:
11488
11542
|.cold_code
11489
11543
|.align aword
11490
11544
|4:
11491
11545
p = jumptable->arData;
11492
11546
do {
11493
11547
if (Z_TYPE(p->val) == IS_UNDEF) {
11494
- | .aword =>b
11548
+ if (default_label) {
11549
+ | .aword &default_label
11550
+ } else if (next_opline) {
11551
+ | .aword >3
11552
+ } else {
11553
+ | .aword =>default_b
11554
+ }
11495
11555
} else {
11496
- int b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL(p->val)) - op_array->opcodes];
11497
- | .aword =>b
11556
+ target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL(p->val));
11557
+ if (!next_opline) {
11558
+ b = ssa->cfg.map[target - op_array->opcodes];
11559
+ | .aword =>b
11560
+ } else if (next_opline == target) {
11561
+ | .aword >3
11562
+ } else {
11563
+ exit_point = zend_jit_trace_get_exit_point(opline, target, NULL, 0);
11564
+ exit_addr = zend_jit_trace_get_exit_addr(exit_point);
11565
+ | .aword &exit_addr
11566
+ }
11498
11567
}
11499
11568
p++;
11500
11569
count--;
11501
11570
} while (count);
11502
11571
|.code
11572
+ |3:
11503
11573
} else {
11504
11574
| LOAD_ADDR FCARG1a, jumptable
11505
11575
| EXT_CALL zend_hash_index_find, r0
11506
11576
| test r0, r0
11507
- | jz =>b
11577
+ if (default_label) {
11578
+ | jz &default_label
11579
+ } else if (next_opline) {
11580
+ | jz >3
11581
+ } else {
11582
+ | jz =>default_b
11583
+ }
11508
11584
| LOAD_ADDR FCARG1a, jumptable
11509
11585
| sub r0, aword [FCARG1a + offsetof(HashTable, arData)]
11510
11586
| mov FCARG1a, (sizeof(Bucket) / sizeof(void*))
@@ -11524,15 +11600,24 @@ static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_o
11524
11600
|.else
11525
11601
| jmp aword [r0 + >4]
11526
11602
|.endif
11527
- |3:
11528
11603
|.cold_code
11529
11604
|.align aword
11530
11605
|4:
11531
11606
ZEND_HASH_FOREACH_VAL(jumptable, val) {
11532
- b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(val)) - op_array->opcodes];
11533
- | .aword =>b
11607
+ target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(val));
11608
+ if (!next_opline) {
11609
+ b = ssa->cfg.map[target - op_array->opcodes];
11610
+ | .aword =>b
11611
+ } else if (next_opline == target) {
11612
+ | .aword >3
11613
+ } else {
11614
+ exit_point = zend_jit_trace_get_exit_point(opline, target, NULL, 0);
11615
+ exit_addr = zend_jit_trace_get_exit_addr(exit_point);
11616
+ | .aword &exit_addr
11617
+ }
11534
11618
} ZEND_HASH_FOREACH_END();
11535
11619
|.code
11620
+ |3:
11536
11621
}
11537
11622
}
11538
11623
} else if (opline->opcode == ZEND_SWITCH_STRING) {
@@ -11543,23 +11628,41 @@ static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_o
11543
11628
|.cold_code
11544
11629
|1:
11545
11630
| // ZVAL_DEREF(op)
11546
- | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, >3
11631
+ if (fallback_label) {
11632
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, &fallback_label
11633
+ } else {
11634
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, >3
11635
+ }
11547
11636
| GET_ZVAL_PTR FCARG2a, op1_addr
11548
- | IF_NOT_Z_TYPE FCARG2a + offsetof(zend_reference, val), IS_STRING, >3
11637
+ if (fallback_label) {
11638
+ | IF_NOT_Z_TYPE FCARG2a + offsetof(zend_reference, val), IS_STRING, &fallback_label
11639
+ } else {
11640
+ | IF_NOT_Z_TYPE FCARG2a + offsetof(zend_reference, val), IS_STRING, >3
11641
+ }
11549
11642
| mov FCARG2a, aword [FCARG2a + offsetof(zend_reference, val.value.ptr)]
11550
11643
| jmp >2
11551
11644
|.code
11552
11645
|2:
11553
11646
} else {
11554
11647
if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_STRING)) {
11555
- | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >3
11648
+ if (fallback_label) {
11649
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, &fallback_label
11650
+ } else {
11651
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >3
11652
+ }
11556
11653
}
11557
11654
| GET_ZVAL_PTR FCARG2a, op1_addr
11558
11655
}
11559
11656
| LOAD_ADDR FCARG1a, jumptable
11560
11657
| EXT_CALL zend_hash_find, r0
11561
11658
| test r0, r0
11562
- | jz =>b
11659
+ if (default_label) {
11660
+ | jz &default_label
11661
+ } else if (next_opline) {
11662
+ | jz >3
11663
+ } else {
11664
+ | jz =>default_b
11665
+ }
11563
11666
| LOAD_ADDR FCARG1a, jumptable
11564
11667
| sub r0, aword [FCARG1a + offsetof(HashTable, arData)]
11565
11668
| mov FCARG1a, (sizeof(Bucket) / sizeof(void*))
@@ -11579,15 +11682,24 @@ static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_o
11579
11682
|.else
11580
11683
| jmp aword [r0 + >4]
11581
11684
|.endif
11582
- |3:
11583
11685
|.cold_code
11584
11686
|.align aword
11585
11687
|4:
11586
11688
ZEND_HASH_FOREACH_VAL(jumptable, val) {
11587
- b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(val)) - op_array->opcodes];
11588
- | .aword =>b
11689
+ target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(val));
11690
+ if (!next_opline) {
11691
+ b = ssa->cfg.map[target - op_array->opcodes];
11692
+ | .aword =>b
11693
+ } else if (next_opline == target) {
11694
+ | .aword >3
11695
+ } else {
11696
+ exit_point = zend_jit_trace_get_exit_point(opline, target, NULL, 0);
11697
+ exit_addr = zend_jit_trace_get_exit_addr(exit_point);
11698
+ | .aword &exit_addr
11699
+ }
11589
11700
} ZEND_HASH_FOREACH_END();
11590
11701
|.code
11702
+ |3:
11591
11703
}
11592
11704
} else {
11593
11705
ZEND_UNREACHABLE();
0 commit comments