Skip to content

Commit 7c16d11

Browse files
committed
Tracing JIT for SWITCH instructions
1 parent ddba2a7 commit 7c16d11

File tree

3 files changed

+143
-33
lines changed

3 files changed

+143
-33
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2861,7 +2861,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
28612861
case ZEND_SWITCH_LONG:
28622862
case ZEND_SWITCH_STRING:
28632863
case ZEND_MATCH:
2864-
if (!zend_jit_switch(&dasm_state, opline, op_array, ssa)) {
2864+
if (!zend_jit_switch(&dasm_state, opline, op_array, ssa, NULL)) {
28652865
goto jit_failure;
28662866
}
28672867
goto done;

ext/opcache/jit/zend_jit_trace.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3950,15 +3950,13 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
39503950
goto jit_failure;
39513951
}
39523952
goto done;
3953-
#if 0
39543953
case ZEND_SWITCH_LONG:
39553954
case ZEND_SWITCH_STRING:
39563955
case ZEND_MATCH:
3957-
if (!zend_jit_switch(&dasm_state, opline, op_array, op_array_ssa)) {
3956+
if (!zend_jit_switch(&dasm_state, opline, op_array, op_array_ssa, p+1)) {
39583957
goto jit_failure;
39593958
}
39603959
goto done;
3961-
#endif
39623960
case ZEND_INIT_METHOD_CALL:
39633961
case ZEND_INIT_DYNAMIC_CALL:
39643962
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: 141 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11401,9 +11401,16 @@ static int zend_jit_fetch_this(dasm_State **Dst, const zend_op *opline, const ze
1140111401
return 1;
1140211402
}
1140311403

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)
1140511405
{
1140611406
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+
}
1140711414

1140811415
// TODO: Implement for match instructions
1140911416
if (opline->opcode == ZEND_MATCH) {
@@ -11420,22 +11427,34 @@ static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_o
1142011427
if (opline->opcode == ZEND_SWITCH_LONG) {
1142111428
if (Z_TYPE_P(zv) == IS_LONG) {
1142211429
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);
1142511434
} 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
1142711441
}
11428-
| jmp =>b
1142911442
}
1143011443
} else if (opline->opcode == ZEND_SWITCH_STRING) {
1143111444
if (Z_TYPE_P(zv) == IS_STRING) {
1143211445
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);
1143511450
} 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
1143711457
}
11438-
| jmp =>b
1143911458
}
1144011459
} else {
1144111460
ZEND_UNREACHABLE();
@@ -11444,8 +11463,26 @@ static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_o
1144411463
zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
1144511464
uint32_t op1_info = OP1_INFO();
1144611465
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;
1144811470
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+
}
1144911486

1145011487
if (opline->opcode == ZEND_SWITCH_LONG) {
1145111488
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
1145511492
|.cold_code
1145611493
|1:
1145711494
| // 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+
}
1145911500
| 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+
}
1146111506
| mov FCARG2a, aword [FCARG2a + offsetof(zend_reference, val.value.lval)]
1146211507
| jmp >2
1146311508
|.code
1146411509
|2:
1146511510
} else {
1146611511
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+
}
1146811517
}
1146911518
| GET_ZVAL_LVAL ZREG_FCARG2a, op1_addr
1147011519
}
@@ -11473,7 +11522,13 @@ static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_o
1147311522
Bucket *p = jumptable->arData;
1147411523

1147511524
| 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+
}
1147711532
|.if X64
1147811533
if (!IS_32BIT(dasm_end)) {
1147911534
| lea r0, aword [>4]
@@ -11484,27 +11539,48 @@ static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_o
1148411539
|.else
1148511540
| jmp aword [FCARG2a * 4 + >4]
1148611541
|.endif
11487-
|3:
1148811542
|.cold_code
1148911543
|.align aword
1149011544
|4:
1149111545
p = jumptable->arData;
1149211546
do {
1149311547
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+
}
1149511555
} 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+
}
1149811567
}
1149911568
p++;
1150011569
count--;
1150111570
} while (count);
1150211571
|.code
11572+
|3:
1150311573
} else {
1150411574
| LOAD_ADDR FCARG1a, jumptable
1150511575
| EXT_CALL zend_hash_index_find, r0
1150611576
| 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+
}
1150811584
| LOAD_ADDR FCARG1a, jumptable
1150911585
| sub r0, aword [FCARG1a + offsetof(HashTable, arData)]
1151011586
| 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
1152411600
|.else
1152511601
| jmp aword [r0 + >4]
1152611602
|.endif
11527-
|3:
1152811603
|.cold_code
1152911604
|.align aword
1153011605
|4:
1153111606
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+
}
1153411618
} ZEND_HASH_FOREACH_END();
1153511619
|.code
11620+
|3:
1153611621
}
1153711622
}
1153811623
} 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
1154311628
|.cold_code
1154411629
|1:
1154511630
| // 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+
}
1154711636
| 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+
}
1154911642
| mov FCARG2a, aword [FCARG2a + offsetof(zend_reference, val.value.ptr)]
1155011643
| jmp >2
1155111644
|.code
1155211645
|2:
1155311646
} else {
1155411647
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+
}
1155611653
}
1155711654
| GET_ZVAL_PTR FCARG2a, op1_addr
1155811655
}
1155911656
| LOAD_ADDR FCARG1a, jumptable
1156011657
| EXT_CALL zend_hash_find, r0
1156111658
| 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+
}
1156311666
| LOAD_ADDR FCARG1a, jumptable
1156411667
| sub r0, aword [FCARG1a + offsetof(HashTable, arData)]
1156511668
| 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
1157911682
|.else
1158011683
| jmp aword [r0 + >4]
1158111684
|.endif
11582-
|3:
1158311685
|.cold_code
1158411686
|.align aword
1158511687
|4:
1158611688
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+
}
1158911700
} ZEND_HASH_FOREACH_END();
1159011701
|.code
11702+
|3:
1159111703
}
1159211704
} else {
1159311705
ZEND_UNREACHABLE();

0 commit comments

Comments
 (0)