Skip to content

Commit

Permalink
Tracing JIT for INIT_DYNAMIC_CALL (closure only)
Browse files Browse the repository at this point in the history
  • Loading branch information
dstogov committed Sep 15, 2020
1 parent 2408991 commit f5bbb04
Show file tree
Hide file tree
Showing 5 changed files with 227 additions and 37 deletions.
1 change: 1 addition & 0 deletions ext/opcache/jit/zend_jit.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "Zend/zend_vm.h"
#include "Zend/zend_exceptions.h"
#include "Zend/zend_constants.h"
#include "Zend/zend_closures.h"
#include "Zend/zend_ini.h"
#include "zend_smart_str.h"
#include "jit/zend_jit.h"
Expand Down
3 changes: 2 additions & 1 deletion ext/opcache/jit/zend_jit_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ typedef enum _zend_jit_trace_stop {
#define ZEND_JIT_EXIT_FREE_OP1 (1<<5)
#define ZEND_JIT_EXIT_FREE_OP2 (1<<6)
#define ZEND_JIT_EXIT_PACKED_GUARD (1<<7)
#define ZEND_JIT_EXIT_DYNAMIC_CALL (1<<8) /* exit because of polymorphic INTI_DYNAMIC_CALL call */

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

int ZEND_FASTCALL zend_jit_trace_hot_root(zend_execute_data *execute_data, const zend_op *opline);
int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf *regs);
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);
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);

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)
{
Expand Down
55 changes: 38 additions & 17 deletions ext/opcache/jit/zend_jit_trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -1361,13 +1361,15 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
level = 0;
for (;;p++) {
if (p->op == ZEND_JIT_TRACE_VM) {
uint8_t orig_op1_type, op1_type, op2_type, op3_type;
uint8_t orig_op1_type, orig_op2_type, op1_type, op2_type, op3_type;
// zend_class_entry *op1_ce = NULL;
zend_class_entry *op2_ce = NULL;

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

op1_type = orig_op1_type = p->op1_type;
op2_type = p->op2_type;
op2_type = orig_op2_type = p->op2_type;
op3_type = p->op3_type;
if (op1_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
op1_type = IS_UNKNOWN;
Expand All @@ -1383,11 +1385,11 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
}

if ((p+1)->op == ZEND_JIT_TRACE_OP1_TYPE) {
// TODO: support for recorded classes ???
// op1_ce = (zend_class_entry*)(p+1)->ce;
p++;
}
if ((p+1)->op == ZEND_JIT_TRACE_OP2_TYPE) {
// TODO: support for recorded classes ???
op2_ce = (zend_class_entry*)(p+1)->ce;
p++;
}

Expand Down Expand Up @@ -1701,6 +1703,11 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
}
ADD_OP1_TRACE_GUARD();
break;
case ZEND_INIT_DYNAMIC_CALL:
if (orig_op2_type == IS_OBJECT && op2_ce == zend_ce_closure) {
ADD_OP2_TRACE_GUARD();
}
break;
default:
break;
}
Expand Down Expand Up @@ -3361,8 +3368,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
uint8_t op2_type = p->op2_type;
uint8_t op3_type = p->op3_type;
uint8_t orig_op1_type = op1_type;
uint8_t orig_op2_type = op2_type;
zend_bool op1_indirect;
zend_class_entry *op1_ce = NULL;
zend_class_entry *op2_ce = NULL;

opline = p->opline;
if (op1_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
Expand All @@ -3383,7 +3392,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
p++;
}
if ((p+1)->op == ZEND_JIT_TRACE_OP2_TYPE) {
// TODO: support for recorded classes ???
op2_ce = (zend_class_entry*)(p+1)->ce;
p++;
}

Expand Down Expand Up @@ -4970,8 +4979,17 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
goto jit_failure;
}
goto done;
case ZEND_INIT_METHOD_CALL:
case ZEND_INIT_DYNAMIC_CALL:
if (orig_op2_type == IS_OBJECT && op2_ce == zend_ce_closure) {
op2_info = OP2_INFO();
CHECK_OP2_TRACE_TYPE();
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)) {
goto jit_failure;
}
goto done;
}
/* break missing intentionally */
case ZEND_INIT_METHOD_CALL:
if (!zend_jit_trace_handler(&dasm_state, op_array, opline, zend_may_throw(opline, ssa_op, op_array, ssa), p + 1)) {
goto jit_failure;
}
Expand Down Expand Up @@ -6058,7 +6076,7 @@ static void zend_jit_dump_exit_info(zend_jit_trace_info *t)
if (t->exit_info[i].flags & ZEND_JIT_EXIT_RESTORE_CALL) {
fprintf(stderr, "/CALL");
}
if (t->exit_info[i].flags & ZEND_JIT_EXIT_POLYMORPHISM) {
if (t->exit_info[i].flags & (ZEND_JIT_EXIT_POLYMORPHISM|ZEND_JIT_EXIT_DYNAMIC_CALL)) {
fprintf(stderr, "/POLY");
}
if (t->exit_info[i].flags & ZEND_JIT_EXIT_FREE_OP1) {
Expand Down Expand Up @@ -6398,7 +6416,7 @@ int ZEND_FASTCALL zend_jit_trace_hot_side(zend_execute_data *execute_data, uint3
int ret = 0;
uint32_t trace_num;
zend_jit_trace_rec trace_buffer[ZEND_JIT_TRACE_MAX_LENGTH];
zend_bool is_megamorphic = 0;
uint32_t is_megamorphic = 0;
uint32_t polymorphism = 0;

trace_num = ZEND_JIT_TRACE_NUM;
Expand Down Expand Up @@ -6427,15 +6445,18 @@ int ZEND_FASTCALL zend_jit_trace_hot_side(zend_execute_data *execute_data, uint3
goto abort;
}

if (EX(call)
&& JIT_G(max_polymorphic_calls) > 0
&& (zend_jit_traces[parent_num].exit_info[exit_num].flags & ZEND_JIT_EXIT_POLYMORPHISM)) {
if (zend_jit_traces[parent_num].polymorphism >= JIT_G(max_polymorphic_calls) - 1) {
is_megamorphic = 1;
} else if (!zend_jit_traces[parent_num].polymorphism) {
polymorphism = 1;
} else if (exit_num == 0) {
polymorphism = zend_jit_traces[parent_num].polymorphism + 1;
if (JIT_G(max_polymorphic_calls) > 0) {
if ((zend_jit_traces[parent_num].exit_info[exit_num].flags & ZEND_JIT_EXIT_DYNAMIC_CALL)
|| ((zend_jit_traces[parent_num].exit_info[exit_num].flags & ZEND_JIT_EXIT_POLYMORPHISM)
&& EX(call))) {
if (zend_jit_traces[parent_num].polymorphism >= JIT_G(max_polymorphic_calls) - 1) {
is_megamorphic = zend_jit_traces[parent_num].exit_info[exit_num].flags &
(ZEND_JIT_EXIT_DYNAMIC_CALL | ZEND_JIT_EXIT_POLYMORPHISM);
} else if (!zend_jit_traces[parent_num].polymorphism) {
polymorphism = 1;
} else if (exit_num == 0) {
polymorphism = zend_jit_traces[parent_num].polymorphism + 1;
}
}
}

Expand Down
11 changes: 7 additions & 4 deletions ext/opcache/jit/zend_jit_vm_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ static int zend_jit_trace_bad_loop_exit(const zend_op *opline)
return 0;
}

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)
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)
{
zend_jit_trace_stop stop ZEND_ATTRIBUTE_UNUSED = ZEND_JIT_TRACE_STOP_ERROR;

Expand Down Expand Up @@ -507,7 +507,7 @@ static int zend_jit_trace_record_fake_init_call_ex(zend_execute_data *call, zend
}
func = (zend_function*)jit_extension->op_array;
}
if (is_megamorphic
if (is_megamorphic == ZEND_JIT_EXIT_POLYMORPHISM
/* TODO: use more accurate check ??? */
&& ((ZEND_CALL_INFO(call) & ZEND_CALL_DYNAMIC)
|| func->common.scope)) {
Expand All @@ -522,7 +522,7 @@ static int zend_jit_trace_record_fake_init_call_ex(zend_execute_data *call, zend
return idx;
}

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)
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)
{
uint32_t call_level = 0;

Expand Down Expand Up @@ -570,7 +570,7 @@ static int zend_jit_trace_call_level(const zend_execute_data *call)
*
*/

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)
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)

{
#ifdef HAVE_GCC_GLOBAL_REGS
Expand Down Expand Up @@ -929,6 +929,9 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
if (JIT_G(max_polymorphic_calls) == 0
&& zend_jit_may_be_polymorphic_call(opline - 1)) {
func = NULL;
} else if (is_megamorphic == ZEND_JIT_EXIT_DYNAMIC_CALL
&& trace_buffer[1].opline == opline - 1) {
func = NULL;
}
call_level = zend_jit_trace_call_level(EX(call));
ZEND_ASSERT(ret_level + level + call_level < 32);
Expand Down

0 comments on commit f5bbb04

Please sign in to comment.