php-src/sapi/phpdbg
Arnaud Le Blanc 76d7c616bb
Pass opline as argument to opcode handlers in CALL VM
This changes the signature of opcode handlers in the CALL VM so that the opline
is passed directly via arguments. This reduces the number of memory operations
on EX(opline), and makes the CALL VM considerably faster.

Additionally, this unifies the CALL and HYBRID VMs a bit, as EX(opline) is now
handled in the same way in both VMs.

This is a part of GH-17849.

Currently we have two VMs:

 * HYBRID: Used when compiling with GCC. execute_data and opline are global
   register variables
 * CALL: Used when compiling with something else. execute_data is passed as
   opcode handler arg, but opline is passed via execute_data->opline
   (EX(opline)).

The Call VM looks like this:

    while (1) {
        ret = execute_data->opline->handler(execute_data);
        if (UNEXPECTED(ret != 0)) {
            if (ret > 0) { // returned by ZEND_VM_ENTER() / ZEND_VM_LEAVE()
                execute_data = EG(current_execute_data);
            } else {       // returned by ZEND_VM_RETURN()
                return;
            }
        }
    }

    // example op handler
    int ZEND_INIT_FCALL_SPEC_CONST_HANDLER(zend_execute_data *execute_data) {
        // load opline
        const zend_op *opline = execute_data->opline;

        // instruction execution

        // dispatch
        // ZEND_VM_NEXT_OPCODE():
        execute_data->opline++;
        return 0; // ZEND_VM_CONTINUE()
    }

Opcode handlers return a positive value to signal that the loop must load a
new execute_data from EG(current_execute_data), typically when entering
or leaving a function.

Here I make the following changes:

 * Pass opline as opcode handler argument
 * Return next opline from opcode handlers
 * ZEND_VM_ENTER / ZEND_VM_LEAVE return opline|(1<<0) to signal that
   execute_data must be reloaded from EG(current_execute_data)

This gives us:

    while (1) {
        opline = opline->handler(execute_data, opline);
        if (UNEXPECTED((uintptr_t) opline & ZEND_VM_ENTER_BIT) {
            opline = opline & ~ZEND_VM_ENTER_BIT;
            if (opline != 0) { // ZEND_VM_ENTER() / ZEND_VM_LEAVE()
                execute_data = EG(current_execute_data);
            } else {           // ZEND_VM_RETURN()
                return;
            }
        }
    }

    // example op handler
    const zend_op * ZEND_INIT_FCALL_SPEC_CONST_HANDLER(zend_execute_data *execute_data, const zend_op *opline) {
        // opline already loaded

        // instruction execution

        // dispatch
        // ZEND_VM_NEXT_OPCODE():
        return ++opline;
    }

bench.php is 23% faster on Linux / x86_64, 18% faster on MacOS / M1.

Symfony Demo is 2.8% faster.

When using the HYBRID VM, JIT'ed code stores execute_data/opline in two fixed
callee-saved registers and rarely touches EX(opline), just like the VM.

Since the registers are callee-saved, the JIT'ed code doesn't have to
save them before calling other functions, and can assume they always
contain execute_data/opline. The code also avoids saving/restoring them in
prologue/epilogue, as execute_ex takes care of that (JIT'ed code is called
exclusively from there).

The CALL VM can now use a fixed register for execute_data/opline as well, but
we can't rely on execute_ex to save the registers for us as it may use these
registers itself. So we have to save/restore the two registers in JIT'ed code
prologue/epilogue.

Closes GH-17952
2025-04-15 18:51:54 +02:00
..
tests Pass opline as argument to opcode handlers in CALL VM 2025-04-15 18:51:54 +02:00
.gdbinit
.phpdbginit
config.m4 Remove phpdbg binary during make clean (#16085) 2024-09-27 16:24:17 +02:00
config.w32 Avoid duplicate build rules 2025-02-01 11:21:09 +01:00
create-test.php Update http->https in license (#6945) 2021-05-06 12:16:35 +02:00
CREDITS
Makefile.frag Remove phpdbg binary during make clean (#16085) 2024-09-27 16:24:17 +02:00
phpdbg.1.in Update http links to https and sync www.php.net URLs (#14854) 2024-07-07 04:23:08 +02:00
phpdbg.c Exclude unused functions from compilation units (GH-17686) 2025-02-10 18:00:19 +01:00
phpdbg.h sapi: Fix some variable shadowing (#16485) 2024-10-17 22:46:23 +01:00
phpdbg.init.d
phpdbg.stub.php Declare phpdbg constants in stubs (#9392) 2022-08-21 19:05:17 +02:00
phpdbg_arginfo.h Do not generate frameless info items when func info generation is disabled 2024-02-18 11:39:00 +01:00
phpdbg_bp.c sapi: Fix some variable shadowing (#16485) 2024-10-17 22:46:23 +01:00
phpdbg_bp.h zend_compiler, ...: use uint8_t instead of zend_uchar (#10621) 2023-02-23 14:56:54 +00:00
phpdbg_break.c replace phpdbg custom opcode dumper with O+ dump (#7227) 2021-07-13 15:32:14 +02:00
phpdbg_break.h Update http->https in license (#6945) 2021-05-06 12:16:35 +02:00
phpdbg_btree.c Update http->https in license (#6945) 2021-05-06 12:16:35 +02:00
phpdbg_btree.h Update http->https in license (#6945) 2021-05-06 12:16:35 +02:00
phpdbg_cmd.c Merge branch 'PHP-8.3' 2024-08-02 08:38:35 +02:00
phpdbg_cmd.h remove specialized printing from phpdbg (#7156) 2021-06-17 14:22:33 +02:00
phpdbg_frame.c sapi/phpdbg: Use HASH_FOREACH macro (#16211) 2024-10-07 00:17:30 +01:00
phpdbg_frame.h Update http->https in license (#6945) 2021-05-06 12:16:35 +02:00
phpdbg_help.c [skip ci] Update PHP version in phpdbg help (#14965) 2024-07-16 07:02:05 +02:00
phpdbg_help.h Make globals const (part 2) (#10610) 2023-02-18 19:52:53 +00:00
phpdbg_info.c phpdbg: Call enums “Enum” and traits “Trait” in info classes (#17191) 2024-12-17 19:32:47 +01:00
phpdbg_info.h Update http->https in license (#6945) 2021-05-06 12:16:35 +02:00
phpdbg_io.c Preferably include from build dir (#13516) 2024-06-26 00:26:43 +02:00
phpdbg_io.h ditch remote 2021-06-13 21:08:35 +02:00
phpdbg_lexer.h Update http->https in license (#6945) 2021-05-06 12:16:35 +02:00
phpdbg_lexer.l Partially fix GH-17387 2025-01-30 19:28:23 +01:00
phpdbg_list.c Support specifying start position in compile_string 2021-09-30 10:21:33 +02:00
phpdbg_list.h ZEND_ELEMENT_COUNT usage reduction. (#13324) 2024-02-04 19:09:15 +00:00
phpdbg_out.c Fix GH-14553: Bug in phpdbg8.3 (also 8.1 and 8.2) echo output - trimmed at NULL byte (?) 2024-07-04 18:43:42 +02:00
phpdbg_out.h Merge branch 'PHP-8.3' 2024-07-04 18:44:29 +02:00
phpdbg_parser.y Suppress unused-but-set-variable warning in parsers 2022-07-28 22:29:42 +02:00
phpdbg_print.c Remove useless NULL-check in phpdbg_print (#13853) 2024-04-02 18:17:21 +02:00
phpdbg_print.h replace phpdbg custom opcode dumper with O+ dump (#7227) 2021-07-13 15:32:14 +02:00
phpdbg_prompt.c Merge branch 'PHP-8.4' 2025-01-30 19:32:28 +01:00
phpdbg_prompt.h drop phpdbg web helper extension and wait command (#7144) 2021-06-13 14:02:11 +02:00
phpdbg_set.c replace phpdbg custom opcode dumper with O+ dump (#7227) 2021-07-13 15:32:14 +02:00
phpdbg_set.h replace phpdbg custom opcode dumper with O+ dump (#7227) 2021-07-13 15:32:14 +02:00
phpdbg_sigsafe.c Replace zend_bool uses with bool 2021-01-15 12:33:06 +01:00
phpdbg_sigsafe.h Replace zend_bool uses with bool 2021-01-15 12:33:06 +01:00
phpdbg_utils.c phpdbg: change uses of sprintf into snprintf 2024-06-14 08:12:03 -07:00
phpdbg_utils.h remove specialized printing from phpdbg (#7156) 2021-06-17 14:22:33 +02:00
phpdbg_watch.c sapi: Fix some variable shadowing (#16485) 2024-10-17 22:46:23 +01:00
phpdbg_watch.h Drop zend_mm_set_custom_debug_handlers() (#13457) 2024-02-26 14:04:33 +01:00
phpdbg_win.c Remove more unused local variables (GH-17688) 2025-02-03 20:06:29 +01:00
phpdbg_win.h Update http->https in license (#6945) 2021-05-06 12:16:35 +02:00
test.php Apply tidy formatting 2020-02-03 13:41:31 +01:00
web-bootstrap.php