Skip to content

Commit f5bbb04

Browse files
committed
Tracing JIT for INIT_DYNAMIC_CALL (closure only)
1 parent 2408991 commit f5bbb04

File tree

5 files changed

+227
-37
lines changed

5 files changed

+227
-37
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "Zend/zend_vm.h"
2323
#include "Zend/zend_exceptions.h"
2424
#include "Zend/zend_constants.h"
25+
#include "Zend/zend_closures.h"
2526
#include "Zend/zend_ini.h"
2627
#include "zend_smart_str.h"
2728
#include "jit/zend_jit.h"

ext/opcache/jit/zend_jit_internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ typedef enum _zend_jit_trace_stop {
211211
#define ZEND_JIT_EXIT_FREE_OP1 (1<<5)
212212
#define ZEND_JIT_EXIT_FREE_OP2 (1<<6)
213213
#define ZEND_JIT_EXIT_PACKED_GUARD (1<<7)
214+
#define ZEND_JIT_EXIT_DYNAMIC_CALL (1<<8) /* exit because of polymorphic INTI_DYNAMIC_CALL call */
214215

215216
typedef union _zend_op_trace_info {
216217
zend_op dummy; /* the size of this structure must be the same as zend_op */
@@ -458,7 +459,7 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_trace_helper(ZEND_OPCODE_HAN
458459

459460
int ZEND_FASTCALL zend_jit_trace_hot_root(zend_execute_data *execute_data, const zend_op *opline);
460461
int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf *regs);
461-
zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *execute_data, const zend_op *opline, zend_jit_trace_rec *trace_buffer, uint8_t start, zend_bool is_megamorphc);
462+
zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *execute_data, const zend_op *opline, zend_jit_trace_rec *trace_buffer, uint8_t start, uint32_t is_megamorphc);
462463

463464
static zend_always_inline const zend_op* zend_jit_trace_get_exit_opline(zend_jit_trace_rec *trace, const zend_op *opline, zend_bool *exit_if_true)
464465
{

ext/opcache/jit/zend_jit_trace.c

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,13 +1361,15 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
13611361
level = 0;
13621362
for (;;p++) {
13631363
if (p->op == ZEND_JIT_TRACE_VM) {
1364-
uint8_t orig_op1_type, op1_type, op2_type, op3_type;
1364+
uint8_t orig_op1_type, orig_op2_type, op1_type, op2_type, op3_type;
1365+
// zend_class_entry *op1_ce = NULL;
1366+
zend_class_entry *op2_ce = NULL;
13651367

13661368
// TODO: range inference ???
13671369
opline = p->opline;
13681370

13691371
op1_type = orig_op1_type = p->op1_type;
1370-
op2_type = p->op2_type;
1372+
op2_type = orig_op2_type = p->op2_type;
13711373
op3_type = p->op3_type;
13721374
if (op1_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
13731375
op1_type = IS_UNKNOWN;
@@ -1383,11 +1385,11 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
13831385
}
13841386

13851387
if ((p+1)->op == ZEND_JIT_TRACE_OP1_TYPE) {
1386-
// TODO: support for recorded classes ???
1388+
// op1_ce = (zend_class_entry*)(p+1)->ce;
13871389
p++;
13881390
}
13891391
if ((p+1)->op == ZEND_JIT_TRACE_OP2_TYPE) {
1390-
// TODO: support for recorded classes ???
1392+
op2_ce = (zend_class_entry*)(p+1)->ce;
13911393
p++;
13921394
}
13931395

@@ -1701,6 +1703,11 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
17011703
}
17021704
ADD_OP1_TRACE_GUARD();
17031705
break;
1706+
case ZEND_INIT_DYNAMIC_CALL:
1707+
if (orig_op2_type == IS_OBJECT && op2_ce == zend_ce_closure) {
1708+
ADD_OP2_TRACE_GUARD();
1709+
}
1710+
break;
17041711
default:
17051712
break;
17061713
}
@@ -3361,8 +3368,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
33613368
uint8_t op2_type = p->op2_type;
33623369
uint8_t op3_type = p->op3_type;
33633370
uint8_t orig_op1_type = op1_type;
3371+
uint8_t orig_op2_type = op2_type;
33643372
zend_bool op1_indirect;
33653373
zend_class_entry *op1_ce = NULL;
3374+
zend_class_entry *op2_ce = NULL;
33663375

33673376
opline = p->opline;
33683377
if (op1_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
@@ -3383,7 +3392,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
33833392
p++;
33843393
}
33853394
if ((p+1)->op == ZEND_JIT_TRACE_OP2_TYPE) {
3386-
// TODO: support for recorded classes ???
3395+
op2_ce = (zend_class_entry*)(p+1)->ce;
33873396
p++;
33883397
}
33893398

@@ -4970,8 +4979,17 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
49704979
goto jit_failure;
49714980
}
49724981
goto done;
4973-
case ZEND_INIT_METHOD_CALL:
49744982
case ZEND_INIT_DYNAMIC_CALL:
4983+
if (orig_op2_type == IS_OBJECT && op2_ce == zend_ce_closure) {
4984+
op2_info = OP2_INFO();
4985+
CHECK_OP2_TRACE_TYPE();
4986+
if (!zend_jit_init_closure_call(&dasm_state, opline, op_array_ssa->cfg.map ? op_array_ssa->cfg.map[opline - op_array->opcodes] : -1, op_array, ssa, ssa_op, frame->call_level, p + 1)) {
4987+
goto jit_failure;
4988+
}
4989+
goto done;
4990+
}
4991+
/* break missing intentionally */
4992+
case ZEND_INIT_METHOD_CALL:
49754993
if (!zend_jit_trace_handler(&dasm_state, op_array, opline, zend_may_throw(opline, ssa_op, op_array, ssa), p + 1)) {
49764994
goto jit_failure;
49774995
}
@@ -6058,7 +6076,7 @@ static void zend_jit_dump_exit_info(zend_jit_trace_info *t)
60586076
if (t->exit_info[i].flags & ZEND_JIT_EXIT_RESTORE_CALL) {
60596077
fprintf(stderr, "/CALL");
60606078
}
6061-
if (t->exit_info[i].flags & ZEND_JIT_EXIT_POLYMORPHISM) {
6079+
if (t->exit_info[i].flags & (ZEND_JIT_EXIT_POLYMORPHISM|ZEND_JIT_EXIT_DYNAMIC_CALL)) {
60626080
fprintf(stderr, "/POLY");
60636081
}
60646082
if (t->exit_info[i].flags & ZEND_JIT_EXIT_FREE_OP1) {
@@ -6398,7 +6416,7 @@ int ZEND_FASTCALL zend_jit_trace_hot_side(zend_execute_data *execute_data, uint3
63986416
int ret = 0;
63996417
uint32_t trace_num;
64006418
zend_jit_trace_rec trace_buffer[ZEND_JIT_TRACE_MAX_LENGTH];
6401-
zend_bool is_megamorphic = 0;
6419+
uint32_t is_megamorphic = 0;
64026420
uint32_t polymorphism = 0;
64036421

64046422
trace_num = ZEND_JIT_TRACE_NUM;
@@ -6427,15 +6445,18 @@ int ZEND_FASTCALL zend_jit_trace_hot_side(zend_execute_data *execute_data, uint3
64276445
goto abort;
64286446
}
64296447

6430-
if (EX(call)
6431-
&& JIT_G(max_polymorphic_calls) > 0
6432-
&& (zend_jit_traces[parent_num].exit_info[exit_num].flags & ZEND_JIT_EXIT_POLYMORPHISM)) {
6433-
if (zend_jit_traces[parent_num].polymorphism >= JIT_G(max_polymorphic_calls) - 1) {
6434-
is_megamorphic = 1;
6435-
} else if (!zend_jit_traces[parent_num].polymorphism) {
6436-
polymorphism = 1;
6437-
} else if (exit_num == 0) {
6438-
polymorphism = zend_jit_traces[parent_num].polymorphism + 1;
6448+
if (JIT_G(max_polymorphic_calls) > 0) {
6449+
if ((zend_jit_traces[parent_num].exit_info[exit_num].flags & ZEND_JIT_EXIT_DYNAMIC_CALL)
6450+
|| ((zend_jit_traces[parent_num].exit_info[exit_num].flags & ZEND_JIT_EXIT_POLYMORPHISM)
6451+
&& EX(call))) {
6452+
if (zend_jit_traces[parent_num].polymorphism >= JIT_G(max_polymorphic_calls) - 1) {
6453+
is_megamorphic = zend_jit_traces[parent_num].exit_info[exit_num].flags &
6454+
(ZEND_JIT_EXIT_DYNAMIC_CALL | ZEND_JIT_EXIT_POLYMORPHISM);
6455+
} else if (!zend_jit_traces[parent_num].polymorphism) {
6456+
polymorphism = 1;
6457+
} else if (exit_num == 0) {
6458+
polymorphism = zend_jit_traces[parent_num].polymorphism + 1;
6459+
}
64396460
}
64406461
}
64416462

ext/opcache/jit/zend_jit_vm_helpers.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ static int zend_jit_trace_bad_loop_exit(const zend_op *opline)
474474
return 0;
475475
}
476476

477-
static int zend_jit_trace_record_fake_init_call_ex(zend_execute_data *call, zend_jit_trace_rec *trace_buffer, int idx, zend_bool is_megamorphic, uint32_t *megamorphic, uint32_t level, uint32_t init_level, uint32_t *call_level)
477+
static int zend_jit_trace_record_fake_init_call_ex(zend_execute_data *call, zend_jit_trace_rec *trace_buffer, int idx, uint32_t is_megamorphic, uint32_t *megamorphic, uint32_t level, uint32_t init_level, uint32_t *call_level)
478478
{
479479
zend_jit_trace_stop stop ZEND_ATTRIBUTE_UNUSED = ZEND_JIT_TRACE_STOP_ERROR;
480480

@@ -507,7 +507,7 @@ static int zend_jit_trace_record_fake_init_call_ex(zend_execute_data *call, zend
507507
}
508508
func = (zend_function*)jit_extension->op_array;
509509
}
510-
if (is_megamorphic
510+
if (is_megamorphic == ZEND_JIT_EXIT_POLYMORPHISM
511511
/* TODO: use more accurate check ??? */
512512
&& ((ZEND_CALL_INFO(call) & ZEND_CALL_DYNAMIC)
513513
|| func->common.scope)) {
@@ -522,7 +522,7 @@ static int zend_jit_trace_record_fake_init_call_ex(zend_execute_data *call, zend
522522
return idx;
523523
}
524524

525-
static int zend_jit_trace_record_fake_init_call(zend_execute_data *call, zend_jit_trace_rec *trace_buffer, int idx, zend_bool is_megamorphic, uint32_t *megamorphic, uint32_t level)
525+
static int zend_jit_trace_record_fake_init_call(zend_execute_data *call, zend_jit_trace_rec *trace_buffer, int idx, uint32_t is_megamorphic, uint32_t *megamorphic, uint32_t level)
526526
{
527527
uint32_t call_level = 0;
528528

@@ -570,7 +570,7 @@ static int zend_jit_trace_call_level(const zend_execute_data *call)
570570
*
571571
*/
572572

573-
zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex, const zend_op *op, zend_jit_trace_rec *trace_buffer, uint8_t start, zend_bool is_megamorphic)
573+
zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex, const zend_op *op, zend_jit_trace_rec *trace_buffer, uint8_t start, uint32_t is_megamorphic)
574574

575575
{
576576
#ifdef HAVE_GCC_GLOBAL_REGS
@@ -929,6 +929,9 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
929929
if (JIT_G(max_polymorphic_calls) == 0
930930
&& zend_jit_may_be_polymorphic_call(opline - 1)) {
931931
func = NULL;
932+
} else if (is_megamorphic == ZEND_JIT_EXIT_DYNAMIC_CALL
933+
&& trace_buffer[1].opline == opline - 1) {
934+
func = NULL;
932935
}
933936
call_level = zend_jit_trace_call_level(EX(call));
934937
ZEND_ASSERT(ret_level + level + call_level < 32);

0 commit comments

Comments
 (0)