HYBRID VM cleanup
authorDmitry Stogov <dmitry@zend.com>
Tue, 16 May 2017 06:24:23 +0000 (09:24 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 16 May 2017 06:24:23 +0000 (09:24 +0300)
Zend/zend_vm.h
Zend/zend_vm_execute.h
Zend/zend_vm_execute.skl
Zend/zend_vm_gen.php

index cff9487ed321fa71ad1803a22b5234943315ff22..caa896d3e139b5b936c2ca5fafcdff17e4274a64 100644 (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);
 
index f6e91b17bc5d1bb33620043cda107fc2367ceb1a..1183d930622c04198b3107ae2e620b68fbef77df 100644 (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);
index 81397ce20bcfc267221ecfa83ecb2d16bc1ef01e..eb60787042d8eb5ef5254fa42b80941076eb4d94 100644 (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
index fc51425e890cb328083ed8eda3e08eecbd070f2a..2b49d20a4d2530dea2b99e4054836f5e28cceda2 100644 (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");