Beispiel #1
0
function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
{
    global $params, $skeleton_file, $line_no;
    $lineno = 0;
    foreach ($skl as $line) {
        // Skeleton file contains special markers in form %NAME% those are
        // substituted by custom code
        if (preg_match("/(.*)[{][%]([A-Z_]*)[%][}](.*)/", $line, $m)) {
            switch ($m[2]) {
                case "DEFINES":
                    out($f, "static const void **zend_opcode_handlers;\n");
                    out($f, "static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op* op);\n\n");
                    switch ($kind) {
                        case ZEND_VM_KIND_CALL:
                            out($f, "\n");
                            out($f, "#ifdef ZEND_VM_FP_GLOBAL_REG\n");
                            out($f, "#pragma GCC diagnostic ignored \"-Wvolatile-register-var\"\n");
                            out($f, "register zend_execute_data* volatile execute_data __asm__(ZEND_VM_FP_GLOBAL_REG);\n");
                            out($f, "#pragma GCC diagnostic warning \"-Wvolatile-register-var\"\n");
                            out($f, "#endif\n");
                            out($f, "\n");
                            out($f, "#ifdef ZEND_VM_IP_GLOBAL_REG\n");
                            out($f, "#pragma GCC diagnostic ignored \"-Wvolatile-register-var\"\n");
                            out($f, "register const zend_op* volatile opline __asm__(ZEND_VM_IP_GLOBAL_REG);\n");
                            out($f, "#pragma GCC diagnostic warning \"-Wvolatile-register-var\"\n");
                            out($f, "#endif\n");
                            out($f, "\n");
                            out($f, "#ifdef ZEND_VM_FP_GLOBAL_REG\n");
                            out($f, "# define ZEND_OPCODE_HANDLER_ARGS void\n");
                            out($f, "# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU\n");
                            out($f, "# define ZEND_OPCODE_HANDLER_ARGS_DC\n");
                            out($f, "# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC\n");
                            out($f, "#else\n");
                            out($f, "# define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data\n");
                            out($f, "# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU execute_data\n");
                            out($f, "# define ZEND_OPCODE_HANDLER_ARGS_DC , ZEND_OPCODE_HANDLER_ARGS\n");
                            out($f, "# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC , ZEND_OPCODE_HANDLER_ARGS_PASSTHRU\n");
                            out($f, "#endif\n");
                            out($f, "\n");
                            out($f, "#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n");
                            out($f, "# define ZEND_OPCODE_HANDLER_RET void\n");
                            out($f, "# define ZEND_VM_TAIL_CALL(call) call; return\n");
                            out($f, "# ifdef ZEND_VM_TAIL_CALL_DISPATCH\n");
                            out($f, "#  define ZEND_VM_CONTINUE()     ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); return\n");
                            out($f, "# else\n");
                            out($f, "#  define ZEND_VM_CONTINUE()     return\n");
                            out($f, "# endif\n");
                            out($f, "# define ZEND_VM_RETURN()        opline = NULL; return\n");
                            out($f, "#else\n");
                            out($f, "# define ZEND_OPCODE_HANDLER_RET int\n");
                            out($f, "# define ZEND_VM_TAIL_CALL(call) return call\n");
                            out($f, "# define ZEND_VM_CONTINUE()      return  0\n");
                            out($f, "# define ZEND_VM_RETURN()        return -1\n");
                            out($f, "#endif\n");
                            out($f, "\n");
                            out($f, "typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);\n");
                            out($f, "\n");
                            out($f, "#undef OPLINE\n");
                            out($f, "#undef DCL_OPLINE\n");
                            out($f, "#undef USE_OPLINE\n");
                            out($f, "#undef LOAD_OPLINE\n");
                            out($f, "#undef LOAD_OPLINE_EX\n");
                            out($f, "#undef SAVE_OPLINE\n");
                            out($f, "#define DCL_OPLINE\n");
                            out($f, "#ifdef ZEND_VM_IP_GLOBAL_REG\n");
                            out($f, "# define OPLINE opline\n");
                            out($f, "# define USE_OPLINE\n");
                            out($f, "# define LOAD_OPLINE() opline = EX(opline)\n");
                            out($f, "# define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n");
                            out($f, "# define SAVE_OPLINE() EX(opline) = opline\n");
                            out($f, "#else\n");
                            out($f, "# define OPLINE EX(opline)\n");
                            out($f, "# define USE_OPLINE const zend_op *opline = EX(opline);\n");
                            out($f, "# define LOAD_OPLINE()\n");
                            out($f, "# define LOAD_NEXT_OPLINE() ZEND_VM_INC_OPCODE()\n");
                            out($f, "# define SAVE_OPLINE()\n");
                            out($f, "#endif\n");
                            out($f, "#undef HANDLE_EXCEPTION\n");
                            out($f, "#undef HANDLE_EXCEPTION_LEAVE\n");
                            out($f, "#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n");
                            out($f, "#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n");
                            out($f, "#if defined(ZEND_VM_FP_GLOBAL_REG)\n");
                            out($f, "# define ZEND_VM_ENTER()           execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_CONTINUE()\n");
                            out($f, "# define ZEND_VM_LEAVE()           ZEND_VM_CONTINUE()\n");
                            out($f, "#elif defined(ZEND_VM_IP_GLOBAL_REG)\n");
                            out($f, "# define ZEND_VM_ENTER()           opline = EG(current_execute_data)->opline; return 1\n");
                            out($f, "# define ZEND_VM_LEAVE()           return  2\n");
                            out($f, "#else\n");
                            out($f, "# define ZEND_VM_ENTER()           return  1\n");
                            out($f, "# define ZEND_VM_LEAVE()           return  2\n");
                            out($f, "#endif\n");
                            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");
                            break;
                        case ZEND_VM_KIND_SWITCH:
                            out($f, "\n");
                            out($f, "#undef OPLINE\n");
                            out($f, "#undef DCL_OPLINE\n");
                            out($f, "#undef USE_OPLINE\n");
                            out($f, "#undef LOAD_OPLINE\n");
                            out($f, "#undef LOAD_NEXT_OPLINE\n");
                            out($f, "#undef SAVE_OPLINE\n");
                            out($f, "#define OPLINE opline\n");
                            out($f, "#ifdef ZEND_VM_IP_GLOBAL_REG\n");
                            out($f, "# define DCL_OPLINE register const zend_op *opline __asm__(ZEND_VM_IP_GLOBAL_REG);\n");
                            out($f, "#else\n");
                            out($f, "# define DCL_OPLINE const zend_op *opline;\n");
                            out($f, "#endif\n");
                            out($f, "#define USE_OPLINE\n");
                            out($f, "#define LOAD_OPLINE() opline = EX(opline)\n");
                            out($f, "#define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n");
                            out($f, "#define SAVE_OPLINE() EX(opline) = opline\n");
                            out($f, "#undef HANDLE_EXCEPTION\n");
                            out($f, "#undef HANDLE_EXCEPTION_LEAVE\n");
                            out($f, "#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n");
                            out($f, "#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n");
                            out($f, "#define ZEND_VM_CONTINUE() goto zend_vm_continue\n");
                            out($f, "#define ZEND_VM_RETURN()   return\n");
                            out($f, "#define ZEND_VM_ENTER()    execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_CONTINUE()\n");
                            out($f, "#define ZEND_VM_LEAVE()    ZEND_VM_CONTINUE()\n");
                            out($f, "#define ZEND_VM_DISPATCH(opcode, opline) dispatch_handler = zend_vm_get_opcode_handler(opcode, opline); goto zend_vm_dispatch;\n");
                            out($f, "\n");
                            break;
                        case ZEND_VM_KIND_GOTO:
                            out($f, "\n");
                            out($f, "#undef OPLINE\n");
                            out($f, "#undef DCL_OPLINE\n");
                            out($f, "#undef USE_OPLINE\n");
                            out($f, "#undef LOAD_OPLINE\n");
                            out($f, "#undef LOAD_NEXT_OPLINE\n");
                            out($f, "#undef SAVE_OPLINE\n");
                            out($f, "#define OPLINE opline\n");
                            out($f, "#ifdef ZEND_VM_IP_GLOBAL_REG\n");
                            out($f, "# define DCL_OPLINE register const zend_op *opline __asm__(ZEND_VM_IP_GLOBAL_REG);\n");
                            out($f, "#else\n");
                            out($f, "# define DCL_OPLINE const zend_op *opline;\n");
                            out($f, "#endif\n");
                            out($f, "#define USE_OPLINE\n");
                            out($f, "#define LOAD_OPLINE() opline = EX(opline)\n");
                            out($f, "#define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n");
                            out($f, "#define SAVE_OPLINE() EX(opline) = opline\n");
                            out($f, "#undef HANDLE_EXCEPTION\n");
                            out($f, "#undef HANDLE_EXCEPTION_LEAVE\n");
                            if (ZEND_VM_SPEC) {
                                out($f, "#define HANDLE_EXCEPTION() goto ZEND_HANDLE_EXCEPTION_SPEC_HANDLER\n");
                                out($f, "#define HANDLE_EXCEPTION_LEAVE() goto ZEND_HANDLE_EXCEPTION_SPEC_HANDLER\n");
                            } else {
                                out($f, "#define HANDLE_EXCEPTION() goto ZEND_HANDLE_EXCEPTION_HANDLER\n");
                                out($f, "#define HANDLE_EXCEPTION_LEAVE() goto ZEND_HANDLE_EXCEPTION_HANDLER\n");
                            }
                            out($f, "#define ZEND_VM_CONTINUE() goto *(void**)(OPLINE->handler)\n");
                            out($f, "#define ZEND_VM_RETURN()   return\n");
                            out($f, "#define ZEND_VM_ENTER()    execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_CONTINUE()\n");
                            out($f, "#define ZEND_VM_LEAVE()    ZEND_VM_CONTINUE()\n");
                            out($f, "#define ZEND_VM_DISPATCH(opcode, opline) goto *(void**)(zend_vm_get_opcode_handler(opcode, opline));\n");
                            out($f, "\n");
                            break;
                    }
                    break;
                case "EXECUTOR_NAME":
                    out($f, $m[1] . $executor_name . $m[3] . "\n");
                    break;
                case "HELPER_VARS":
                    if ($kind != ZEND_VM_KIND_CALL) {
                        if ($kind == ZEND_VM_KIND_SWITCH) {
                            out($f, $m[1] . "const void *dispatch_handler;\n");
                        }
                        // Emit local variables those are used for helpers' parameters
                        foreach ($params as $param => $x) {
                            out($f, $m[1] . $param . ";\n");
                        }
                        out($f, "#ifdef ZEND_VM_FP_GLOBAL_REG\n");
                        out($f, $m[1] . "register zend_execute_data *execute_data __asm__(ZEND_VM_FP_GLOBAL_REG) = ex;\n");
                        out($f, "#else\n");
                        out($f, $m[1] . "zend_execute_data *execute_data = ex;\n");
                        out($f, "#endif\n");
                    } else {
                        out($f, "#ifdef ZEND_VM_IP_GLOBAL_REG\n");
                        out($f, $m[1] . "const zend_op *orig_opline = opline;\n");
                        out($f, "#endif\n");
                        out($f, "#ifdef ZEND_VM_FP_GLOBAL_REG\n");
                        out($f, $m[1] . "zend_execute_data *orig_execute_data = execute_data;\n");
                        out($f, $m[1] . "execute_data = ex;\n");
                        out($f, "#else\n");
                        out($f, $m[1] . "zend_execute_data *execute_data = ex;\n");
                        out($f, "#endif\n");
                    }
                    break;
                case "INTERNAL_LABELS":
                    if ($kind == ZEND_VM_KIND_GOTO) {
                        // Emit array of labels of opcode handlers and code for
                        // zend_opcode_handlers initialization
                        $prolog = $m[1];
                        out($f, $prolog . "if (UNEXPECTED(execute_data == NULL)) {\n");
                        out($f, $prolog . "\tstatic const void* labels[] = {\n");
                        gen_labels($f, $spec, $kind, $prolog . "\t\t");
                        out($f, $prolog . "\t};\n");
                        out($f, $prolog . "\tzend_opcode_handlers = (const void **)labels;\n");
                        out($f, $prolog . "\treturn;\n");
                        out($f, $prolog . "}\n");
                    } else {
                        skip_blanks($f, $m[1], $m[3]);
                    }
                    break;
                case "ZEND_VM_CONTINUE_LABEL":
                    if ($kind == ZEND_VM_KIND_CALL) {
                        // Only SWITCH dispatch method use it
                        out($f, "#if !defined(ZEND_VM_FP_GLOBAL_REG) || !defined(ZEND_VM_IP_GLOBAL_REG)\n");
                        out($f, $m[1] . "\tint ret;" . $m[3] . "\n");
                        out($f, "#endif\n");
                    } else {
                        if ($kind == ZEND_VM_KIND_SWITCH) {
                            // Only SWITCH dispatch method use it
                            out($f, "zend_vm_continue:" . $m[3] . "\n");
                        } else {
                            skip_blanks($f, $m[1], $m[3]);
                        }
                    }
                    break;
                case "ZEND_VM_DISPATCH":
                    // Emit code that dispatches to opcode handler
                    switch ($kind) {
                        case ZEND_VM_KIND_CALL:
                            out($f, "#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n");
                            out($f, $m[1] . "((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n");
                            out($f, $m[1] . "if (UNEXPECTED(!OPLINE))" . $m[3] . "\n");
                            out($f, "#else\n");
                            out($f, $m[1] . "if (UNEXPECTED((ret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)) != 0))" . $m[3] . "\n");
                            out($f, "#endif\n");
                            break;
                        case ZEND_VM_KIND_SWITCH:
                            out($f, $m[1] . "dispatch_handler = OPLINE->handler;\nzend_vm_dispatch:\n" . $m[1] . "switch ((int)(uintptr_t)dispatch_handler)" . $m[3] . "\n");
                            break;
                        case ZEND_VM_KIND_GOTO:
                            out($f, $m[1] . "goto *(void**)(OPLINE->handler);" . $m[3] . "\n");
                            break;
                    }
                    break;
                case "INTERNAL_EXECUTOR":
                    if ($kind == ZEND_VM_KIND_CALL) {
                        // Executor is defined as a set of functions
                        out($f, "#ifdef ZEND_VM_FP_GLOBAL_REG\n" . $m[1] . "execute_data = orig_execute_data;\n" . "# ifdef ZEND_VM_IP_GLOBAL_REG\n" . $m[1] . "opline = orig_opline;\n" . "# endif\n" . $m[1] . "return;\n" . "#else\n" . $m[1] . "if (EXPECTED(ret > 0)) {\n" . $m[1] . "\texecute_data = EG(current_execute_data);\n" . $m[1] . "} else {\n" . "# ifdef ZEND_VM_IP_GLOBAL_REG\n" . $m[1] . "\topline = orig_opline;\n" . "# endif\n" . $m[1] . "\treturn;\n" . $m[1] . "}\n" . "#endif\n");
                    } else {
                        // Emit executor code
                        gen_executor_code($f, $spec, $kind, $m[1]);
                    }
                    break;
                case "EXTERNAL_EXECUTOR":
                    if ($kind == ZEND_VM_KIND_CALL) {
                        gen_executor_code($f, $spec, $kind, $m[1]);
                    }
                    break;
                case "INITIALIZER_NAME":
                    out($f, $m[1] . $initializer_name . $m[3] . "\n");
                    break;
                case "EXTERNAL_LABELS":
                    // Emit code that initializes zend_opcode_handlers array
                    $prolog = $m[1];
                    if ($kind == ZEND_VM_KIND_GOTO) {
                        // Labels are defined in the executor itself, so we call it
                        // with execute_data NULL and it sets zend_opcode_handlers array
                        out($f, $prolog . "");
                        out($f, $prolog . $executor_name . "_ex(NULL);\n");
                    } else {
                        out($f, $prolog . "static const void *labels[] = {\n");
                        gen_labels($f, $spec, $kind, $prolog . "\t");
                        out($f, $prolog . "};\n");
                        out($f, $prolog . "zend_opcode_handlers = labels;\n");
                    }
                    break;
                default:
                    die("ERROR: Unknown keyword " . $m[2] . " in skeleton file.\n");
            }
        } else {
            // Copy the line as is
            out($f, $line);
        }
    }
}
Beispiel #2
0
function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name, $old)
{
    global $params, $skeleton_file, $line_no;
    $lineno = 0;
    foreach ($skl as $line) {
        // Skeleton file contains special markers in form %NAME% those are
        // substituted by custom code
        if (preg_match("/(.*)[{][%]([A-Z_]*)[%][}](.*)/", $line, $m)) {
            switch ($m[2]) {
                case "DEFINES":
                    if (ZEND_VM_OLD_EXECUTOR && $spec) {
                        out($f, "static int zend_vm_old_executor = 0;\n\n");
                    }
                    out($f, "static opcode_handler_t zend_vm_get_opcode_handler(zend_uchar opcode, zend_op* op);\n\n");
                    switch ($kind) {
                        case ZEND_VM_KIND_CALL:
                            out($f, "\n");
                            out($f, "#undef OPLINE\n");
                            out($f, "#undef DCL_OPLINE\n");
                            out($f, "#undef USE_OPLINE\n");
                            out($f, "#undef LOAD_OPLINE\n");
                            out($f, "#undef SAVE_OPLINE\n");
                            out($f, "#define OPLINE EX(opline)\n");
                            out($f, "#define DCL_OPLINE\n");
                            out($f, "#define USE_OPLINE zend_op *opline = EX(opline);\n");
                            out($f, "#define LOAD_OPLINE()\n");
                            out($f, "#define SAVE_OPLINE()\n");
                            out($f, "#undef CHECK_EXCEPTION\n");
                            out($f, "#undef HANDLE_EXCEPTION\n");
                            out($f, "#undef HANDLE_EXCEPTION_LEAVE\n");
                            out($f, "#define CHECK_EXCEPTION() LOAD_OPLINE()\n");
                            out($f, "#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n");
                            out($f, "#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n");
                            out($f, "#define LOAD_REGS()\n");
                            out($f, "#define ZEND_VM_CONTINUE()         return 0\n");
                            out($f, "#define ZEND_VM_RETURN()           return 1\n");
                            out($f, "#define ZEND_VM_ENTER()            return 2\n");
                            out($f, "#define ZEND_VM_LEAVE()            return 3\n");
                            out($f, "#define ZEND_VM_DISPATCH(opcode, opline) return zend_vm_get_opcode_handler(opcode, opline)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n\n");
                            out($f, "#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n");
                            break;
                        case ZEND_VM_KIND_SWITCH:
                            out($f, "\n");
                            out($f, "#undef OPLINE\n");
                            out($f, "#undef DCL_OPLINE\n");
                            out($f, "#undef USE_OPLINE\n");
                            out($f, "#undef LOAD_OPLINE\n");
                            out($f, "#undef SAVE_OPLINE\n");
                            out($f, "#define OPLINE opline\n");
                            out($f, "#define DCL_OPLINE zend_op *opline;\n");
                            out($f, "#define USE_OPLINE\n");
                            out($f, "#define LOAD_OPLINE() opline = EX(opline)\n");
                            out($f, "#define SAVE_OPLINE() EX(opline) = opline\n");
                            out($f, "#undef CHECK_EXCEPTION\n");
                            out($f, "#undef HANDLE_EXCEPTION\n");
                            out($f, "#undef HANDLE_EXCEPTION_LEAVE\n");
                            out($f, "#define CHECK_EXCEPTION() LOAD_OPLINE()\n");
                            out($f, "#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n");
                            out($f, "#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n");
                            out($f, "#define LOAD_REGS()\n");
                            out($f, "#define ZEND_VM_CONTINUE() goto zend_vm_continue\n");
                            out($f, "#define ZEND_VM_RETURN()   EG(in_execution) = original_in_execution; return\n");
                            out($f, "#define ZEND_VM_ENTER()    goto zend_vm_enter\n");
                            out($f, "#define ZEND_VM_LEAVE()    ZEND_VM_CONTINUE()\n");
                            out($f, "#define ZEND_VM_DISPATCH(opcode, opline) dispatch_handler = zend_vm_get_opcode_handler(opcode, opline); goto zend_vm_dispatch;\n\n");
                            out($f, "#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n");
                            break;
                        case ZEND_VM_KIND_GOTO:
                            out($f, "\n");
                            out($f, "#undef OPLINE\n");
                            out($f, "#undef DCL_OPLINE\n");
                            out($f, "#undef USE_OPLINE\n");
                            out($f, "#undef LOAD_OPLINE\n");
                            out($f, "#undef SAVE_OPLINE\n");
                            out($f, "#define OPLINE opline\n");
                            out($f, "#define DCL_OPLINE zend_op *opline;\n");
                            out($f, "#define USE_OPLINE\n");
                            out($f, "#define LOAD_OPLINE() opline = EX(opline)\n");
                            out($f, "#define SAVE_OPLINE() EX(opline) = opline\n");
                            out($f, "#undef CHECK_EXCEPTION\n");
                            out($f, "#undef HANDLE_EXCEPTION\n");
                            out($f, "#undef HANDLE_EXCEPTION_LEAVE\n");
                            out($f, "#define CHECK_EXCEPTION() if (UNEXPECTED(EG(exception) != NULL)) goto ZEND_HANDLE_EXCEPTION_SPEC_HANDLER\n");
                            out($f, "#define HANDLE_EXCEPTION() goto ZEND_HANDLE_EXCEPTION_SPEC_HANDLER\n");
                            out($f, "#define HANDLE_EXCEPTION_LEAVE() goto ZEND_HANDLE_EXCEPTION_SPEC_HANDLER\n");
                            out($f, "#define LOAD_REGS()\n");
                            out($f, "#define ZEND_VM_CONTINUE() goto *(void**)(OPLINE->handler)\n");
                            out($f, "#define ZEND_VM_RETURN()   EG(in_execution) = original_in_execution; return\n");
                            out($f, "#define ZEND_VM_ENTER()    goto zend_vm_enter\n");
                            out($f, "#define ZEND_VM_LEAVE()    ZEND_VM_CONTINUE()\n");
                            out($f, "#define ZEND_VM_DISPATCH(opcode, opline) goto *(void**)(zend_vm_get_opcode_handler(opcode, opline));\n\n");
                            out($f, "#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n");
                            break;
                    }
                    break;
                case "EXECUTOR_NAME":
                    out($f, $m[1] . $executor_name . $m[3] . "\n");
                    break;
                case "HELPER_VARS":
                    if ($kind != ZEND_VM_KIND_CALL) {
                        if ($kind == ZEND_VM_KIND_SWITCH) {
                            out($f, $m[1] . "opcode_handler_t dispatch_handler;\n");
                        }
                        // Emit local variables those are used for helpers' parameters
                        foreach ($params as $param => $x) {
                            out($f, $m[1] . $param . ";\n");
                        }
                    } else {
                        skip_blanks($f, $m[1], $m[3] . "\n");
                    }
                    break;
                case "INTERNAL_LABELS":
                    if ($kind == ZEND_VM_KIND_GOTO) {
                        // Emit array of labels of opcode handlers and code for
                        // zend_opcode_handlers initialization
                        $prolog = $m[1];
                        out($f, $prolog . "if (execute_data == NULL) {\n");
                        out($f, $prolog . "\tstatic const opcode_handler_t labels[] = {\n");
                        gen_labels($f, $spec, $kind, $prolog . "\t\t");
                        out($f, $prolog . "\t};\n");
                        out($f, $prolog . "\tzend_opcode_handlers = (opcode_handler_t*)labels;\n");
                        out($f, $prolog . "\treturn;\n");
                        out($f, $prolog . "}\n");
                    } else {
                        skip_blanks($f, $m[1], $m[3]);
                    }
                    break;
                case "ZEND_VM_CONTINUE_LABEL":
                    if ($kind == ZEND_VM_KIND_CALL) {
                        // Only SWITCH dispatch method use it
                        out($f, $m[1] . "\tint ret;" . $m[3] . "\n");
                    } else {
                        if ($kind == ZEND_VM_KIND_SWITCH) {
                            // Only SWITCH dispatch method use it
                            out($f, "zend_vm_continue:" . $m[3] . "\n");
                        } else {
                            skip_blanks($f, $m[1], $m[3]);
                        }
                    }
                    break;
                case "ZEND_VM_DISPATCH":
                    // Emit code that dispatches to opcode handler
                    switch ($kind) {
                        case ZEND_VM_KIND_CALL:
                            out($f, $m[1] . "if ((ret = OPLINE->handler(execute_data TSRMLS_CC)) > 0)" . $m[3] . "\n");
                            break;
                        case ZEND_VM_KIND_SWITCH:
                            out($f, $m[1] . "dispatch_handler = OPLINE->handler;\nzend_vm_dispatch:\n" . $m[1] . "switch ((int)dispatch_handler)" . $m[3] . "\n");
                            break;
                        case ZEND_VM_KIND_GOTO:
                            out($f, $m[1] . "goto *(void**)(OPLINE->handler);" . $m[3] . "\n");
                            break;
                    }
                    break;
                case "INTERNAL_EXECUTOR":
                    if ($kind == ZEND_VM_KIND_CALL) {
                        // Executor is defined as a set of functions
                        out($f, $m[1] . "switch (ret) {\n" . $m[1] . "\tcase 1:\n" . $m[1] . "\t\tEG(in_execution) = original_in_execution;\n" . $m[1] . "\t\treturn;\n" . $m[1] . "\tcase 2:\n" . $m[1] . "\t\tgoto zend_vm_enter;\n" . $m[1] . "\t\tbreak;\n" . $m[1] . "\tcase 3:\n" . $m[1] . "\t\texecute_data = EG(current_execute_data);\n" . $m[1] . "\t\tbreak;\n" . $m[1] . "\tdefault:\n" . $m[1] . "\t\tbreak;\n" . $m[1] . "}" . $m[3] . "\n");
                    } else {
                        // Emit executor code
                        gen_executor_code($f, $spec, $kind, $m[1]);
                    }
                    break;
                case "EXTERNAL_EXECUTOR":
                    if ($kind == ZEND_VM_KIND_CALL) {
                        // Unspecialized executor with CALL threading is the same as the
                        // old one, so we don't need to produce code twitch
                        if (!$old || ZEND_VM_SPEC || ZEND_VM_KIND != ZEND_VM_KIND_CALL) {
                            // Emit executor code
                            gen_executor_code($f, $spec, $kind, $m[1]);
                        }
                    }
                    break;
                case "INITIALIZER_NAME":
                    out($f, $m[1] . $initializer_name . $m[3] . "\n");
                    break;
                case "EXTERNAL_LABELS":
                    // Emit code that initializes zend_opcode_handlers array
                    $prolog = $m[1];
                    if ($kind == ZEND_VM_KIND_GOTO) {
                        // Labels are defined in the executor itself, so we call it
                        // with execute_data NULL and it sets zend_opcode_handlers array
                        out($f, $prolog . "TSRMLS_FETCH();\n");
                        out($f, $prolog . $executor_name . "_ex(NULL TSRMLS_CC);\n");
                    } else {
                        if ($old) {
                            // Reserving space for user-defined opcodes
                            out($f, $prolog . "static opcode_handler_t labels[512] = {\n");
                        } else {
                            out($f, $prolog . "static const opcode_handler_t labels[] = {\n");
                        }
                        gen_labels($f, $spec, $kind, $prolog . "\t");
                        out($f, $prolog . "};\n");
                        out($f, $prolog . "zend_opcode_handlers = (opcode_handler_t*)labels;\n");
                        if ($old) {
                            // Setup old executor
                            out($f, $prolog . "zend_vm_old_executor = 1;\n");
                            out($f, $prolog . "zend_execute = old_execute;\n");
                        }
                    }
                    break;
                default:
                    die("ERROR: Unknown keyword " . $m[2] . " in skeleton file.\n");
            }
        } else {
            // Copy the line as is
            out($f, $line);
        }
    }
}
Beispiel #3
0
function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name, $old)
{
    global $params, $skeleton_file, $line_no;
    $lineno = 0;
    foreach ($skl as $line) {
        // Skeleton file contains special markers in form %NAME% those are
        // substituted by custom code
        if (preg_match("/(.*)[{][%]([A-Z_]*)[%][}](.*)/", $line, $m)) {
            switch ($m[2]) {
                case "DEFINES":
                    if (ZEND_VM_OLD_EXECUTOR) {
                        out($f, "static int zend_vm_old_executor = 0;\n\n");
                    }
                    out($f, "static opcode_handler_t zend_vm_get_opcode_handler(zend_uchar opcode, int op1_type, int op2_type);\n\n");
                    switch ($kind) {
                        case ZEND_VM_KIND_CALL:
                            out($f, "\n");
                            out($f, "#define ZEND_VM_CONTINUE() return 0\n");
                            out($f, "#define ZEND_VM_RETURN() return 1\n");
                            out($f, "#define ZEND_VM_DISPATCH(opcode, opline) return zend_vm_get_opcode_handler(opcode, opline->op1.op_type, opline->op2.op_type)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n\n");
                            out($f, "#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n");
                            break;
                        case ZEND_VM_KIND_SWITCH:
                            out($f, "\n");
                            out($f, "#define ZEND_VM_CONTINUE() goto zend_vm_continue\n");
                            out($f, "#define ZEND_VM_RETURN()   return\n");
                            out($f, "#define ZEND_VM_DISPATCH(opcode, opline) dispatch_handler = zend_vm_get_opcode_handler(opcode, opline->op1.op_type, opline->op2.op_type); goto zend_vm_dispatch;\n\n");
                            out($f, "#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL &execute_data TSRMLS_CC\n");
                            break;
                        case ZEND_VM_KIND_GOTO:
                            out($f, "\n");
                            out($f, "#define ZEND_VM_CONTINUE() goto *(void**)(EX(opline)->handler)\n");
                            out($f, "#define ZEND_VM_RETURN()   return\n");
                            out($f, "#define ZEND_VM_DISPATCH(opcode, opline) goto *(void**)(zend_vm_get_opcode_handler(opcode, opline->op1.op_type, opline->op2.op_type));\n\n");
                            out($f, "#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL &execute_data TSRMLS_CC\n");
                            break;
                        case ZEND_VM_KIND_GOTO2:
                            out($f, "\n");
                            out($f, "#define ZEND_VM_CONTINUE() goto *(void**)(EX(opline)->handler)\n");
                            //out($f,"#define ZEND_VM_RETURN()   return\n");
                            out($f, "#define ZEND_VM_RETURN()   goto ZEND_RETURN_HANDLER\n");
                            out($f, "#define ZEND_VM_DISPATCH(opcode, opline) goto *(void**)(zend_vm_get_opcode_handler(opcode, opline->op1.op_type, opline->op2.op_type));\n\n");
                            out($f, "#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n");
                            break;
                    }
                    out($f, "#undef EX\n");
                    if ($kind == ZEND_VM_KIND_GOTO2) {
                        out($f, "#define EX(element) execute_data->element\n");
                    } else {
                        out($f, "#define EX(element) execute_data.element\n");
                    }
                    out($f, "#define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data TSRMLS_DC\n");
                    out($f, "#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU execute_data TSRMLS_CC\n");
                    break;
                case "EXECUTOR_NAME":
                    out($f, $m[1] . $executor_name . $m[3] . "\n");
                    break;
                case "HELPER_VARS":
                    if ($kind != ZEND_VM_KIND_CALL) {
                        if ($kind == ZEND_VM_KIND_SWITCH) {
                            out($f, $m[1] . "opcode_handler_t dispatch_handler;\n");
                        }
                        // Emit local variables those are used for helpers' parameters
                        foreach ($params as $param => $x) {
                            out($f, $m[1] . $param . ";\n");
                        }
                    } else {
                        skip_blanks($f, $m[1], $m[3] . "\n");
                    }
                    if ($kind == ZEND_VM_KIND_GOTO2) {
                        out($f, $m[1] . "zend_execute_data* execute_data = do_alloca(sizeof(zend_execute_data));\n");
                    } else {
                        out($f, $m[1] . "zend_execute_data execute_data;\n");
                    }
                    break;
                case "INTERNAL_LABELS":
                    if ($kind == ZEND_VM_KIND_GOTO || $kind == ZEND_VM_KIND_GOTO2) {
                        // Emit array of labels of opcode handlers and code for
                        // zend_opcode_handlers initialization
                        $prolog = $m[1];
                        out($f, $prolog . "if (op_array == NULL) {\n");
                        out($f, $prolog . "\tstatic const opcode_handler_t labels[] = {\n");
                        gen_labels($f, $spec, $kind, $prolog . "\t\t");
                        out($f, $prolog . "\t};\n");
                        out($f, $prolog . "\tzend_opcode_handlers = (opcode_handler_t*)labels;\n");
                        out($f, $prolog . "\treturn;\n");
                        out($f, $prolog . "}\n");
                    } else {
                        skip_blanks($f, $m[1], $m[3]);
                    }
                    break;
                case "ZEND_VM_CONTINUE_LABEL":
                    if ($kind == ZEND_VM_KIND_SWITCH) {
                        // Only SWITCH dispatch method use it
                        out($f, "zend_vm_continue:" . $m[3] . "\n");
                    } else {
                        skip_blanks($f, $m[1], $m[3]);
                    }
                    break;
                case "ZEND_VM_DISPATCH":
                    // Emit code that dispatches to opcode handler
                    switch ($kind) {
                        case ZEND_VM_KIND_CALL:
                            out($f, $m[1] . "if (EX(opline)->handler(&execute_data TSRMLS_CC) > 0)" . $m[3] . "\n");
                            break;
                        case ZEND_VM_KIND_SWITCH:
                            out($f, $m[1] . "dispatch_handler = EX(opline)->handler;\nzend_vm_dispatch:\n" . $m[1] . "switch ((int)dispatch_handler)" . $m[3] . "\n");
                            break;
                        case ZEND_VM_KIND_GOTO:
                        case ZEND_VM_KIND_GOTO2:
                            out($f, $m[1] . "goto *(void**)(EX(opline)->handler);" . $m[3] . "\n");
                            break;
                    }
                    break;
                case "INTERNAL_EXECUTOR":
                    if ($kind == ZEND_VM_KIND_CALL) {
                        // Executor is defined as a set of functions
                        out($f, $m[1] . "return;" . $m[3] . "\n");
                    } else {
                        // Emit executor code
                        gen_executor_code($f, $spec, $kind, $m[1]);
                    }
                    break;
                case "EXTERNAL_EXECUTOR":
                    if ($kind == ZEND_VM_KIND_CALL) {
                        // Unspecialized executor with CALL threading is the same as the
                        // old one, so we don't need to produce code twitch
                        if (!$old || ZEND_VM_SPEC || ZEND_VM_KIND != ZEND_VM_KIND_CALL) {
                            out($f, "#undef EX\n");
                            out($f, "#define EX(element) execute_data->element\n\n");
                            // Emit executor code
                            gen_executor_code($f, $spec, $kind, $m[1]);
                        }
                    }
                    break;
                case "EXECUTE_DATA_ASSIGN":
                    if ($kind == ZEND_VM_KIND_GOTO2) {
                        out($f, $m[1] . "EG(current_execute_data) = execute_data;" . $m[3] . "\n");
                    } else {
                        out($f, $m[1] . "EG(current_execute_data) = &execute_data;" . $m[3] . "\n");
                    }
                    break;
                case "INITIALIZER_NAME":
                    out($f, $m[1] . $initializer_name . $m[3] . "\n");
                    break;
                case "EXTERNAL_LABELS":
                    // Emit code that initializes zend_opcode_handlers array
                    $prolog = $m[1];
                    if ($kind == ZEND_VM_KIND_GOTO || $kind == ZEND_VM_KIND_GOTO2) {
                        // Labels are defined in the executor itself, so we call it
                        // with op_array NULL and it sets zend_opcode_handlers array
                        out($f, $prolog . "TSRMLS_FETCH();\n");
                        out($f, $prolog . "zend_execute(NULL TSRMLS_CC);\n");
                    } else {
                        if ($old) {
                            // Reserving space for user-defined opcodes
                            out($f, $prolog . "static opcode_handler_t labels[512] = {\n");
                        } else {
                            out($f, $prolog . "static const opcode_handler_t labels[] = {\n");
                        }
                        gen_labels($f, $spec, $kind, $prolog . "\t");
                        out($f, $prolog . "};\n");
                        out($f, $prolog . "zend_opcode_handlers = (opcode_handler_t*)labels;\n");
                        if ($old) {
                            // Setup old executor
                            out($f, $prolog . "zend_vm_old_executor = 1;\n");
                            out($f, $prolog . "zend_execute = old_execute;\n");
                        }
                    }
                    break;
                default:
                    die("ERROR: Unknown keyword " . $m[2] . " in skeleton file.\n");
            }
        } else {
            // Copy the line as is
            out($f, $line);
        }
    }
}