HYBRID VM cleanup

This commit is contained in:
Dmitry Stogov 2017-05-16 09:24:23 +03:00
parent 0722a0188f
commit 7640e0a5f9
4 changed files with 98 additions and 61 deletions

View File

@ -28,8 +28,8 @@ ZEND_API void zend_vm_set_opcode_handler(zend_op* opcode);
ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* opcode, uint32_t op1_info, uint32_t op2_info, uint32_t res_info);
ZEND_API void zend_serialize_opcode_handler(zend_op *op);
ZEND_API void zend_deserialize_opcode_handler(zend_op *op);
ZEND_API const void *zend_get_real_opcode_handler(const zend_op *op);
ZEND_API const zend_op *zend_get_real_exit_op(void);
ZEND_API const void *zend_get_opcode_handler_func(const zend_op *op);
ZEND_API const zend_op *zend_get_halt_op(void);
ZEND_API int zend_vm_call_opcode_handler(zend_execute_data *ex);
ZEND_API int zend_vm_kind(void);

View File

@ -319,7 +319,6 @@ static const uint32_t *zend_spec_handlers;
static const void **zend_opcode_handlers;
static int zend_handlers_count;
static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op* op);
static const void *zend_vm_get_real_opcode_handler(zend_uchar opcode, const zend_op* op);
#ifdef ZEND_VM_FP_GLOBAL_REG
@ -400,7 +399,7 @@ typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_H
#endif
#define ZEND_VM_INTERRUPT() ZEND_VM_TAIL_CALL(zend_interrupt_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));
#define ZEND_VM_LOOP_INTERRUPT() zend_interrupt_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
#define ZEND_VM_DISPATCH(opcode, opline) ZEND_VM_TAIL_CALL(((opcode_handler_t)zend_vm_get_real_opcode_handler(opcode, opline))(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));
#define ZEND_VM_DISPATCH(opcode, opline) ZEND_VM_TAIL_CALL(((opcode_handler_t)zend_vm_get_opcode_handler(opcode, opline))(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_interrupt_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS);
@ -59223,7 +59222,7 @@ ZEND_API void zend_deserialize_opcode_handler(zend_op *op)
op->handler = zend_opcode_handlers[(zend_uintptr_t)op->handler];
}
ZEND_API const void *zend_get_real_opcode_handler(const zend_op *op)
ZEND_API const void *zend_get_opcode_handler_func(const zend_op *op)
{
#if ZEND_VM_KIND == ZEND_VM_KIND_CALL
return op->handler;
@ -59235,16 +59234,16 @@ ZEND_API const void *zend_get_real_opcode_handler(const zend_op *op)
}
zv = zend_hash_index_find(zend_handlers_table, (zend_long)(zend_uintptr_t)op->handler);
ZEND_ASSERT(zv != NULL);
return zend_opcode_real_handlers[Z_LVAL_P(zv)];
return zend_opcode_handler_funcs[Z_LVAL_P(zv)];
#else
return NULL;
#endif
}
ZEND_API const zend_op *zend_get_real_exit_op(void)
ZEND_API const zend_op *zend_get_halt_op(void)
{
#if ZEND_VM_KIND == ZEND_VM_KIND_HYBRID
return &hybrid_return_op;
return &hybrid_halt_op;
#else
return NULL;
#endif
@ -59306,23 +59305,6 @@ static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op*
return zend_vm_get_opcode_handler_ex(zend_spec_handlers[opcode], op);
}
static const void *zend_vm_get_real_opcode_handler(zend_uchar opcode, const zend_op* op)
{
const void *handler = zend_vm_get_opcode_handler_ex(zend_spec_handlers[opcode], op);
#if ZEND_VM_KIND == ZEND_VM_KIND_HYBRID
zval *zv;
if (!zend_handlers_table) {
init_opcode_serialiser();
}
zv = zend_hash_index_find(zend_handlers_table, (zend_long)(zend_uintptr_t)handler);
ZEND_ASSERT(zv != NULL);
return zend_opcode_real_handlers[Z_LVAL_P(zv)];
#else
return handler;
#endif
}
ZEND_API void zend_vm_set_opcode_handler(zend_op* op)
{
op->handler = zend_vm_get_opcode_handler(zend_user_opcodes[op->opcode], op);

View File

@ -83,7 +83,7 @@ ZEND_API void zend_deserialize_opcode_handler(zend_op *op)
op->handler = zend_opcode_handlers[(zend_uintptr_t)op->handler];
}
ZEND_API const void *zend_get_real_opcode_handler(const zend_op *op)
ZEND_API const void *zend_get_opcode_handler_func(const zend_op *op)
{
#if ZEND_VM_KIND == ZEND_VM_KIND_CALL
return op->handler;
@ -95,16 +95,16 @@ ZEND_API const void *zend_get_real_opcode_handler(const zend_op *op)
}
zv = zend_hash_index_find(zend_handlers_table, (zend_long)(zend_uintptr_t)op->handler);
ZEND_ASSERT(zv != NULL);
return zend_opcode_real_handlers[Z_LVAL_P(zv)];
return zend_opcode_handler_funcs[Z_LVAL_P(zv)];
#else
return NULL;
#endif
}
ZEND_API const zend_op *zend_get_real_exit_op(void)
ZEND_API const zend_op *zend_get_halt_op(void)
{
#if ZEND_VM_KIND == ZEND_VM_KIND_HYBRID
return &hybrid_return_op;
return &hybrid_halt_op;
#else
return NULL;
#endif

View File

@ -1540,7 +1540,7 @@ function gen_executor_code($f, $spec, $kind, $prolog, &$switch_labels = array())
out($f,"\tZEND_VM_NEXT_OPCODE(); /* Never reached */\n");
break;
case ZEND_VM_KIND_HYBRID:
out($f,"\t\t\tHYBRID_CASE(HYBRID_RETURN):\n");
out($f,"\t\t\tHYBRID_CASE(HYBRID_HALT):\n");
out($f,"\t\t\t\texecute_data = orig_execute_data;\n");
out($f,"\t\t\t\topline = orig_opline;\n");
out($f,"\t\t\t\treturn;\n");
@ -1583,12 +1583,18 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
out($f,"static int zend_handlers_count;\n");
if ($kind == ZEND_VM_KIND_HYBRID) {
out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n");
out($f,"static const void **zend_opcode_real_handlers;\n");
out($f,"static zend_op hybrid_return_op;\n");
out($f,"static const void **zend_opcode_handler_funcs;\n");
out($f,"static zend_op hybrid_halt_op;\n");
out($f,"#endif\n");
}
out($f,"static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op* op);\n");
out($f,"static const void *zend_vm_get_real_opcode_handler(zend_uchar opcode, const zend_op* op);\n\n");
out($f,"static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op* op);\n\n");
if ($kind == ZEND_VM_KIND_HYBRID) {
out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n");
out($f,"static const void *zend_vm_get_opcode_handler_func(zend_uchar opcode, const zend_op* op);\n");
out($f,"#else\n");
out($f,"# define zend_vm_get_opcode_handler_func zend_vm_get_opcode_handler\n");
out($f,"#endif\n\n");
}
switch ($kind) {
case ZEND_VM_KIND_HYBRID:
out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n");
@ -1634,7 +1640,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
out($f,"# endif\n");
if ($kind == ZEND_VM_KIND_HYBRID) {
out($f,"# if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n");
out($f,"# define ZEND_VM_RETURN() opline = &hybrid_return_op; return\n");
out($f,"# define ZEND_VM_RETURN() opline = &hybrid_halt_op; return\n");
out($f,"# define ZEND_VM_HOT zend_always_inline\n");
out($f,"# else\n");
out($f,"# define ZEND_VM_RETURN() opline = NULL; return\n");
@ -1691,7 +1697,11 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
out($f,"#endif\n");
out($f,"#define ZEND_VM_INTERRUPT() ZEND_VM_TAIL_CALL(zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n");
out($f,"#define ZEND_VM_LOOP_INTERRUPT() zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n");
out($f,"#define ZEND_VM_DISPATCH(opcode, opline) ZEND_VM_TAIL_CALL(((opcode_handler_t)zend_vm_get_real_opcode_handler(opcode, opline))(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n");
if ($kind == ZEND_VM_KIND_HYBRID) {
out($f,"#define ZEND_VM_DISPATCH(opcode, opline) ZEND_VM_TAIL_CALL(((opcode_handler_t)zend_vm_get_opcode_handler_func(opcode, opline))(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n");
} else {
out($f,"#define ZEND_VM_DISPATCH(opcode, opline) ZEND_VM_TAIL_CALL(((opcode_handler_t)zend_vm_get_opcode_handler(opcode, opline))(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n");
}
out($f,"\n");
out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS);");
out($f,"\n");
@ -1812,9 +1822,9 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
out($f,$prolog."\tzend_opcode_handlers = (const void **) labels;\n");
out($f,$prolog."\tzend_handlers_count = sizeof(labels) / sizeof(void*);\n");
if ($kind == ZEND_VM_KIND_HYBRID) {
out($f,$prolog."\tmemset(&hybrid_return_op, 0, sizeof(hybrid_return_op));\n");
out($f,$prolog."\thybrid_return_op.handler = (void*)&&HYBRID_RETURN_LABEL;\n");
out($f,$prolog."\tgoto HYBRID_RETURN_LABEL;\n");
out($f,$prolog."\tmemset(&hybrid_halt_op, 0, sizeof(hybrid_halt_op));\n");
out($f,$prolog."\thybrid_halt_op.handler = (void*)&&HYBRID_HALT_LABEL;\n");
out($f,$prolog."\tgoto HYBRID_HALT_LABEL;\n");
} else {
out($f,$prolog."\treturn;\n");
}
@ -1929,7 +1939,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
out($f,$prolog."};\n");
if ($kind == ZEND_VM_KIND_HYBRID) {
out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n");
out($f,$prolog."zend_opcode_real_handlers = labels;\n");
out($f,$prolog."zend_opcode_handler_funcs = labels;\n");
out($f,$prolog."zend_spec_handlers = specs;\n");
out($f,$prolog.$executor_name."_ex(NULL);\n");
out($f,"#else\n");
@ -2455,26 +2465,71 @@ function gen_vm($def, $skel) {
}
out($f, "}\n\n");
// Generate zend_vm_get_real_opcode_handler() function
out($f, "static const void *zend_vm_get_real_opcode_handler(zend_uchar opcode, const zend_op* op)\n");
out($f, "{\n");
if (!ZEND_VM_SPEC) {
out($f, "\tconst void *handler = zend_vm_get_opcode_handler_ex(opcode, op);\n");
} else {
out($f, "\tconst void *handler = zend_vm_get_opcode_handler_ex(zend_spec_handlers[opcode], op);\n");
if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
// Generate zend_vm_get_opcode_handler_func() function
out($f, "#if ZEND_VM_KIND == ZEND_VM_KIND_HYBRID\n");
out($f,"static const void *zend_vm_get_opcode_handler_func(zend_uchar opcode, const zend_op* op)\n");
out($f, "{\n");
out($f, "\tuint32_t spec = zend_spec_handlers[opcode];\n");
if (!ZEND_VM_SPEC) {
out($f, "\treturn zend_opcode_handler_funcs[spec];\n");
} else {
out($f, "\tstatic const int zend_vm_decode[] = {\n");
out($f, "\t\t_UNUSED_CODE, /* 0 */\n");
out($f, "\t\t_CONST_CODE, /* 1 = IS_CONST */\n");
out($f, "\t\t_TMP_CODE, /* 2 = IS_TMP_VAR */\n");
out($f, "\t\t_UNUSED_CODE, /* 3 */\n");
out($f, "\t\t_VAR_CODE, /* 4 = IS_VAR */\n");
out($f, "\t\t_UNUSED_CODE, /* 5 */\n");
out($f, "\t\t_UNUSED_CODE, /* 6 */\n");
out($f, "\t\t_UNUSED_CODE, /* 7 */\n");
out($f, "\t\t_UNUSED_CODE, /* 8 = IS_UNUSED */\n");
out($f, "\t\t_UNUSED_CODE, /* 9 */\n");
out($f, "\t\t_UNUSED_CODE, /* 10 */\n");
out($f, "\t\t_UNUSED_CODE, /* 11 */\n");
out($f, "\t\t_UNUSED_CODE, /* 12 */\n");
out($f, "\t\t_UNUSED_CODE, /* 13 */\n");
out($f, "\t\t_UNUSED_CODE, /* 14 */\n");
out($f, "\t\t_UNUSED_CODE, /* 15 */\n");
out($f, "\t\t_CV_CODE /* 16 = IS_CV */\n");
out($f, "\t};\n");
out($f, "\tuint32_t offset = 0;\n");
out($f, "\tif (spec & SPEC_RULE_OP1) offset = offset * 5 + zend_vm_decode[op->op1_type];\n");
out($f, "\tif (spec & SPEC_RULE_OP2) offset = offset * 5 + zend_vm_decode[op->op2_type];\n");
if (isset($used_extra_spec["OP_DATA"])) {
out($f, "\tif (spec & SPEC_RULE_OP_DATA) offset = offset * 5 + zend_vm_decode[(op + 1)->op1_type];\n");
}
if (isset($used_extra_spec["RETVAL"])) {
out($f, "\tif (spec & SPEC_RULE_RETVAL) offset = offset * 2 + (op->result_type != IS_UNUSED);\n");
}
if (isset($used_extra_spec["QUICK_ARG"])) {
out($f, "\tif (spec & SPEC_RULE_QUICK_ARG) offset = offset * 2 + (op->op2.num < MAX_ARG_FLAG_NUM);\n");
}
if (isset($used_extra_spec["SMART_BRANCH"])) {
out($f, "\tif (spec & SPEC_RULE_SMART_BRANCH) {\n");
out($f, "\t\toffset = offset * 3;\n");
out($f, "\t\tif ((op+1)->opcode == ZEND_JMPZ) {\n");
out($f, "\t\t\toffset += 1;\n");
out($f, "\t\t} else if ((op+1)->opcode == ZEND_JMPNZ) {\n");
out($f, "\t\t\toffset += 2;\n");
out($f, "\t\t}\n");
out($f, "\t}\n");
}
if (isset($used_extra_spec["DIM_OBJ"])) {
out($f, "\tif (spec & SPEC_RULE_DIM_OBJ) {\n");
out($f, "\t\toffset = offset * 3;\n");
out($f, "\t\tif (op->extended_value == ZEND_ASSIGN_DIM) {\n");
out($f, "\t\t\toffset += 1;\n");
out($f, "\t\t} else if (op->extended_value == ZEND_ASSIGN_OBJ) {\n");
out($f, "\t\t\toffset += 2;\n");
out($f, "\t\t}\n");
out($f, "\t}\n");
}
out($f, "\treturn zend_opcode_handler_funcs[(spec & SPEC_START_MASK) + offset];\n");
}
out($f, "}\n\n");
out($f, "#endif\n\n");
}
out($f, "#if ZEND_VM_KIND == ZEND_VM_KIND_HYBRID\n");
out($f, "\tzval *zv;\n\n");
out($f, "\tif (!zend_handlers_table) {\n");
out($f, "\tinit_opcode_serialiser();\n");
out($f, "\t}\n");
out($f, "\tzv = zend_hash_index_find(zend_handlers_table, (zend_long)(zend_uintptr_t)handler);\n");
out($f, "\tZEND_ASSERT(zv != NULL);\n");
out($f, "\treturn zend_opcode_real_handlers[Z_LVAL_P(zv)];\n");
out($f, "#else\n");
out($f, "\treturn handler;\n");
out($f, "#endif\n");
out($f, "}\n\n");
// Generate zend_vm_get_opcode_handler() function
out($f, "ZEND_API void zend_vm_set_opcode_handler(zend_op* op)\n");
@ -2556,9 +2611,9 @@ function gen_vm($def, $skel) {
out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n");
if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n");
out($f, "\thandler = (opcode_handler_t)zend_get_real_opcode_handler(opline);\n");
out($f, "\thandler = (opcode_handler_t)zend_vm_get_opcode_handler_func(opline->opcode, opline);\n");
out($f, "\thandler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n");
out($f, "\tif (EXPECTED(opline != &hybrid_return_op)) {\n");
out($f, "\tif (EXPECTED(opline != &hybrid_halt_op)) {\n");
out($f,"#else\n");
}
out($f, "\t((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n");