From 0b62e90dad959d864e459fbb4670e50526d71ab3 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sun, 26 Nov 2023 20:59:25 +0100 Subject: [PATCH 01/16] wip --- Zend/Zend.m4 | 9 ++++ Zend/tests/bug73337.phpt | 8 ++- .../typed_properties_046.phpt | 2 +- Zend/zend_exceptions.c | 37 ++++++++++++++ Zend/zend_exceptions.h | 3 ++ Zend/zend_execute.c | 12 ++--- Zend/zend_fibers.c | 1 + Zend/zend_generators.c | 8 +++ Zend/zend_global_regs.h | 49 +++++++++++++++++++ Zend/zend_globals.h | 5 ++ Zend/zend_object_handlers.c | 1 + Zend/zend_observer.c | 1 + Zend/zend_vm_def.h | 8 +-- Zend/zend_vm_execute.h | 38 +++++++++++--- Zend/zend_vm_gen.php | 19 ++++++- 15 files changed, 178 insertions(+), 23 deletions(-) create mode 100644 Zend/zend_global_regs.h diff --git a/Zend/Zend.m4 b/Zend/Zend.m4 index abb89835a4e16..acb0f8ac3f942 100644 --- a/Zend/Zend.m4 +++ b/Zend/Zend.m4 @@ -337,6 +337,12 @@ AC_ARG_ENABLE([gcc-global-regs], [ZEND_GCC_GLOBAL_REGS=$enableval], [ZEND_GCC_GLOBAL_REGS=yes]) +AC_ARG_ENABLE([universal-global-regs], + [AS_HELP_STRING([--enable-universal-global-regs], + [whether to use GCC global register variables universally])], + [ZEND_UNIVERSAL_GLOBAL_REGS=$enableval], + [ZEND_UNIVERSAL_GLOBAL_REGS=no]) + AC_MSG_CHECKING(for global register variables support) if test "$ZEND_GCC_GLOBAL_REGS" != "no"; then AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ @@ -387,6 +393,9 @@ int emu(const opcode_handler_t *ip, void *fp) { fi if test "$ZEND_GCC_GLOBAL_REGS" = "yes"; then AC_DEFINE([HAVE_GCC_GLOBAL_REGS], 1, [Define if the target system has support for global register variables]) + if test "$ZEND_UNIVERSAL_GLOBAL_REGS" = "yes"; then + AC_DEFINE([ZEND_UNIVERSAL_GLOBAL_REGS], 1, [Define whether to use global register variables universally]) + fi fi AC_MSG_RESULT($ZEND_GCC_GLOBAL_REGS) diff --git a/Zend/tests/bug73337.phpt b/Zend/tests/bug73337.phpt index a338aa605c781..2ee21ed38569b 100644 --- a/Zend/tests/bug73337.phpt +++ b/Zend/tests/bug73337.phpt @@ -2,7 +2,13 @@ Bug #73337 (try/catch not working with two exceptions inside a same operation) --FILE-- --EXPECT-- diff --git a/Zend/tests/type_declarations/typed_properties_046.phpt b/Zend/tests/type_declarations/typed_properties_046.phpt index 2048455fe5f12..2618520857825 100644 --- a/Zend/tests/type_declarations/typed_properties_046.phpt +++ b/Zend/tests/type_declarations/typed_properties_046.phpt @@ -16,7 +16,7 @@ function bar() { for ($i = 0; $i < 5; $i++) { try { - foo()->{bar()} = str_repeat("a", 3); + foo()->{'bbb'} = str_repeat("a", 3); } catch (Throwable $e) { echo $e->getMessage() . "\n"; } diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 7dcf2ad65b7f6..fddfea5ce8fcb 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -29,6 +29,7 @@ #include "zend_smart_str.h" #include "zend_exceptions_arginfo.h" #include "zend_observer.h" +#include "zend_global_regs.h" ZEND_API zend_class_entry *zend_ce_throwable; ZEND_API zend_class_entry *zend_ce_exception; @@ -159,6 +160,24 @@ void zend_exception_restore(void) /* {{{ */ } /* }}} */ +static void zend_copy_exception_consts(bool op_data) +{ + uint32_t opnum = op_data ? 1 : 0; + const zend_op *orig_op = &EG(opline_before_exception)[opnum]; + zend_op *exception_op = &EG(exception_op)[opnum]; + + if (orig_op->op1_type == IS_CONST) { + zval *op1 = &EG(exception_consts)[opnum * 2]; + ZVAL_COPY_VALUE(op1, RT_CONSTANT(orig_op, orig_op->op1)); + exception_op->op1.constant = (char *)op1 - (char *)&EG(opline_before_exception)[0]; + } + if (orig_op->op2_type == IS_CONST) { + zval *op2 = &EG(exception_consts)[opnum * 2 + 1]; + ZVAL_COPY_VALUE(op2, RT_CONSTANT(orig_op, orig_op->op2)); + exception_op->op2.constant = (char *)op2 - (char *)&EG(opline_before_exception)[0]; + } +} + static zend_always_inline bool is_handle_exception_set(void) { zend_execute_data *execute_data = EG(current_execute_data); return !execute_data @@ -225,6 +244,24 @@ ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception) /* } EG(opline_before_exception) = EG(current_execute_data)->opline; EG(current_execute_data)->opline = EG(exception_op); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + bool has_opdata = (opline + 1)->opcode == ZEND_OP_DATA; + opline = EG(exception_op); + + /* The handler may still access opline. Make sure operands keep working. */ + const void *handler = EG(exception_op)[0].handler; + memcpy(&EG(exception_op)[0], EG(opline_before_exception), sizeof(EG(exception_op)[0])); + EG(exception_op)[0].opcode = ZEND_HANDLE_EXCEPTION; + EG(exception_op)[0].handler = handler; + zend_copy_exception_consts(/* op_data */ false); + if (has_opdata) { + memcpy(&EG(exception_op)[1], EG(opline_before_exception) + 1, sizeof(EG(exception_op)[1])); + EG(exception_op)[1].opcode = ZEND_OP_DATA; + zend_copy_exception_consts(/* op_data */ true); + } else { + memcpy(&EG(exception_op)[1], &EG(exception_op)[2], sizeof(EG(exception_op)[1])); + } +#endif } /* }}} */ diff --git a/Zend/zend_exceptions.h b/Zend/zend_exceptions.h index f61b5ecb304e2..3c53245a3cadf 100644 --- a/Zend/zend_exceptions.h +++ b/Zend/zend_exceptions.h @@ -86,6 +86,9 @@ static zend_always_inline void zend_rethrow_exception(zend_execute_data *execute EG(opline_before_exception) = EX(opline); EX(opline) = EG(exception_op); } + if (EG(exception_op)[1].opcode != ZEND_HANDLE_EXCEPTION) { + memcpy(&EG(exception_op)[1], &EG(exception_op)[2], sizeof(EG(exception_op)[1])); + } } END_EXTERN_C() diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 1819d0b671dc8..36e2787aedc90 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -44,6 +44,7 @@ #include "zend_system_id.h" #include "zend_call_stack.h" #include "Optimizer/zend_func_info.h" +#include "zend_global_regs.h" /* Virtual current working directory support */ #include "zend_virtual_cwd.h" @@ -51,22 +52,16 @@ #ifdef HAVE_GCC_GLOBAL_REGS # if defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(i386) # define ZEND_VM_FP_GLOBAL_REG "%esi" -# define ZEND_VM_IP_GLOBAL_REG "%edi" # elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__x86_64__) # define ZEND_VM_FP_GLOBAL_REG "%r14" -# define ZEND_VM_IP_GLOBAL_REG "%r15" # elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__powerpc64__) # define ZEND_VM_FP_GLOBAL_REG "r14" -# define ZEND_VM_IP_GLOBAL_REG "r15" # elif defined(__IBMC__) && ZEND_GCC_VERSION >= 4002 && defined(__powerpc64__) # define ZEND_VM_FP_GLOBAL_REG "r14" -# define ZEND_VM_IP_GLOBAL_REG "r15" # elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__aarch64__) # define ZEND_VM_FP_GLOBAL_REG "x27" -# define ZEND_VM_IP_GLOBAL_REG "x28" #elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__riscv) && __riscv_xlen == 64 # define ZEND_VM_FP_GLOBAL_REG "x18" -# define ZEND_VM_IP_GLOBAL_REG "x19" # endif #endif @@ -102,11 +97,10 @@ # define OPLINE_CC , OPLINE_C #endif -#if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)) +#if defined(ZEND_VM_IP_GLOBAL_REG) && !defined(ZEND_UNIVERSAL_GLOBAL_REGS) # pragma GCC diagnostic ignored "-Wvolatile-register-var" - register const zend_op* volatile opline __asm__(ZEND_VM_IP_GLOBAL_REG); +register const zend_op* volatile opline __asm__(ZEND_VM_IP_GLOBAL_REG); # pragma GCC diagnostic warning "-Wvolatile-register-var" -#else #endif #define _CONST_CODE 0 diff --git a/Zend/zend_fibers.c b/Zend/zend_fibers.c index e669ab6b53382..b78a152d9a316 100644 --- a/Zend/zend_fibers.c +++ b/Zend/zend_fibers.c @@ -27,6 +27,7 @@ #include "zend_mmap.h" #include "zend_compile.h" #include "zend_closures.h" +#include "zend_global_regs.h" #include "zend_fibers.h" #include "zend_fibers_arginfo.h" diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 0ab0257f87700..29f0ea2cc278a 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -25,6 +25,7 @@ #include "zend_closures.h" #include "zend_generators_arginfo.h" #include "zend_observer.h" +#include "zend_global_regs.h" ZEND_API zend_class_entry *zend_ce_generator; ZEND_API zend_class_entry *zend_ce_ClosedGeneratorException; @@ -458,6 +459,10 @@ static void zend_generator_throw_exception(zend_generator *generator, zval *exce * to pretend the exception happened during the YIELD opcode. */ EG(current_execute_data) = generator->execute_data; generator->execute_data->opline--; +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + original_execute_data->opline = opline; + opline = EG(current_execute_data)->opline; +#endif if (exception) { zend_throw_exception_object(exception); @@ -473,6 +478,9 @@ static void zend_generator_throw_exception(zend_generator *generator, zval *exce generator->execute_data->opline++; EG(current_execute_data) = original_execute_data; +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + opline = original_execute_data->opline; +#endif } static void zend_generator_add_child(zend_generator *generator, zend_generator *child) diff --git a/Zend/zend_global_regs.h b/Zend/zend_global_regs.h new file mode 100644 index 0000000000000..1991f2d56a467 --- /dev/null +++ b/Zend/zend_global_regs.h @@ -0,0 +1,49 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ +*/ + +#ifndef ZEND_GLOBAL_REGS_H +#define ZEND_GLOBAL_REGS_H + +#ifdef PHP_WIN32 +# include "../../../../main/config.w32.h" +#else +# include +#endif +#include "zend_vm_opcodes.h" + +#if defined(HAVE_GCC_GLOBAL_REGS) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)) +# if defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(i386) +# define ZEND_VM_IP_GLOBAL_REG "%edi" +# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__x86_64__) +# define ZEND_VM_IP_GLOBAL_REG "%r15" +# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__powerpc64__) +# define ZEND_VM_IP_GLOBAL_REG "r15" +# elif defined(__IBMC__) && ZEND_GCC_VERSION >= 4002 && defined(__powerpc64__) +# define ZEND_VM_IP_GLOBAL_REG "r15" +# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__aarch64__) +# define ZEND_VM_IP_GLOBAL_REG "x28" +# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__riscv) && __riscv_xlen == 64 +# define ZEND_VM_IP_GLOBAL_REG "x19" +# endif +#endif + +#if defined(ZEND_UNIVERSAL_GLOBAL_REGS) && defined(ZEND_VM_IP_GLOBAL_REG) +# pragma GCC diagnostic ignored "-Wvolatile-register-var" +register const zend_op* volatile opline __asm__(ZEND_VM_IP_GLOBAL_REG); +# pragma GCC diagnostic warning "-Wvolatile-register-var" +#endif + +#endif /* ZEND_GLOBAL_REGS_H */ diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 8900a5f416f53..b95eb168b840f 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -246,6 +246,11 @@ struct _zend_executor_globals { zend_object *exception, *prev_exception; const zend_op *opline_before_exception; zend_op exception_op[3]; +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + /* Consts copied over from opline during exceptions. Allows the throwing handler to access + * constants even after the opline register has been adjusted. */ + zval exception_consts[4]; +#endif struct _zend_module_entry *current_module; diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 573d9eb106df1..e559feaf5a04c 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -30,6 +30,7 @@ #include "zend_closures.h" #include "zend_compile.h" #include "zend_hash.h" +#include "zend_global_regs.h" #define DEBUG_OBJECT_HANDLERS 0 diff --git a/Zend/zend_observer.c b/Zend/zend_observer.c index 2cb4db914758a..18ad2c6188ad5 100644 --- a/Zend/zend_observer.c +++ b/Zend/zend_observer.c @@ -22,6 +22,7 @@ #include "zend_extensions.h" #include "zend_llist.h" #include "zend_vm.h" +#include "zend_global_regs.h" #define ZEND_OBSERVER_DATA(function) \ ZEND_OP_ARRAY_EXTENSION((&(function)->common), zend_observer_fcall_op_array_extension) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 909e8e43ecbd7..c36e678d7a6d9 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -4015,6 +4015,7 @@ ZEND_VM_HOT_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL,OBSERVER)) } if (UNEXPECTED(EG(exception) != NULL)) { + /* FIXME: Restore opline? */ zend_rethrow_exception(execute_data); HANDLE_EXCEPTION(); } @@ -4172,7 +4173,7 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL,OBSERVER)) ZEND_OBSERVER_FCALL_BEGIN(execute_data); ZEND_VM_ENTER_EX(); } else { - SAVE_OPLINE_EX(); + SAVE_OPLINE_EX2(); ZEND_OBSERVER_FCALL_BEGIN(execute_data); execute_data = EX(prev_execute_data); LOAD_OPLINE(); @@ -8782,7 +8783,8 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY, SPEC(OBSERVER)) uint32_t num_args = EX_NUM_ARGS(); zend_execute_data *call; - SAVE_OPLINE(); + /* May we delay this? Probably doesn't matter too much. */ + SAVE_OPLINE_EX2(); if (num_args) { zval *p = ZEND_CALL_ARG(execute_data, 1); @@ -8837,7 +8839,7 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY, SPEC(OBSERVER)) ZEND_OBSERVER_FCALL_BEGIN(execute_data); ZEND_VM_ENTER_EX(); } else { - SAVE_OPLINE_EX(); + SAVE_OPLINE_EX2(); ZEND_OBSERVER_FCALL_BEGIN(execute_data); execute_data = EX(prev_execute_data); if (execute_data) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index feeb1f6f6b090..fe62d5c8afc2c 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -393,7 +393,16 @@ static const void *zend_vm_get_opcode_handler_func(uint8_t opcode, const zend_op typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS); #define DCL_OPLINE -#ifdef ZEND_VM_IP_GLOBAL_REG +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +# define OPLINE opline +# define USE_OPLINE +# define LOAD_OPLINE() opline = EX(opline) +# define LOAD_OPLINE_EX() +# define LOAD_NEXT_OPLINE() opline = EX(opline) + 1 +# define SAVE_OPLINE() EX(opline) = opline +# define SAVE_OPLINE_EX() SAVE_OPLINE() +# define SAVE_OPLINE_EX2() SAVE_OPLINE() +#elif defined(ZEND_VM_IP_GLOBAL_REG) # define OPLINE opline # define USE_OPLINE # define LOAD_OPLINE() opline = EX(opline) @@ -1305,6 +1314,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_RETV } if (UNEXPECTED(EG(exception) != NULL)) { + /* FIXME: Restore opline? */ zend_rethrow_exception(execute_data); HANDLE_EXCEPTION(); } @@ -1367,6 +1377,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_RETV } if (UNEXPECTED(EG(exception) != NULL)) { + /* FIXME: Restore opline? */ zend_rethrow_exception(execute_data); HANDLE_EXCEPTION(); } @@ -1431,6 +1442,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_OBS } if (UNEXPECTED(EG(exception) != NULL)) { + /* FIXME: Restore opline? */ zend_rethrow_exception(execute_data); HANDLE_EXCEPTION(); } @@ -1826,7 +1838,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV ZEND_VM_ENTER_EX(); } else { - SAVE_OPLINE_EX(); + SAVE_OPLINE_EX2(); execute_data = EX(prev_execute_data); LOAD_OPLINE(); @@ -1935,7 +1947,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV ZEND_VM_ENTER_EX(); } else { - SAVE_OPLINE_EX(); + SAVE_OPLINE_EX2(); execute_data = EX(prev_execute_data); LOAD_OPLINE(); @@ -2044,7 +2056,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_OBS zend_observer_fcall_begin(execute_data); ZEND_VM_ENTER_EX(); } else { - SAVE_OPLINE_EX(); + SAVE_OPLINE_EX2(); zend_observer_fcall_begin(execute_data); execute_data = EX(prev_execute_data); LOAD_OPLINE(); @@ -3400,7 +3412,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z uint32_t num_args = EX_NUM_ARGS(); zend_execute_data *call; - SAVE_OPLINE(); + /* May we delay this? Probably doesn't matter too much. */ + SAVE_OPLINE_EX2(); if (num_args) { zval *p = ZEND_CALL_ARG(execute_data, 1); @@ -3455,7 +3468,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z ZEND_VM_ENTER_EX(); } else { - SAVE_OPLINE_EX(); + SAVE_OPLINE_EX2(); execute_data = EX(prev_execute_data); if (execute_data) { @@ -3540,7 +3553,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_OBSERVER_ uint32_t num_args = EX_NUM_ARGS(); zend_execute_data *call; - SAVE_OPLINE(); + /* May we delay this? Probably doesn't matter too much. */ + SAVE_OPLINE_EX2(); if (num_args) { zval *p = ZEND_CALL_ARG(execute_data, 1); @@ -3595,7 +3609,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_OBSERVER_ zend_observer_fcall_begin(execute_data); ZEND_VM_ENTER_EX(); } else { - SAVE_OPLINE_EX(); + SAVE_OPLINE_EX2(); zend_observer_fcall_begin(execute_data); execute_data = EX(prev_execute_data); if (execute_data) { @@ -65809,14 +65823,22 @@ ZEND_API int ZEND_FASTCALL zend_vm_call_opcode_handler(zend_execute_data* ex) if (EXPECTED(opline)) { #endif ret = execute_data != ex ? (int)(execute_data->prev_execute_data != ex) + 1 : 0; +#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG) + EX(opline) = opline; +#else SAVE_OPLINE(); +#endif } else { ret = -1; } #else ret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG) + EX(opline) = opline; +#else SAVE_OPLINE(); #endif +#endif #ifdef ZEND_VM_FP_GLOBAL_REG execute_data = orig_execute_data; #endif diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index f7b630bc5a048..449e4cac35e1c 100755 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -1900,7 +1900,16 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);\n"); out($f,"\n"); out($f,"#define DCL_OPLINE\n"); - out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n"); + out($f,"#ifdef ZEND_UNIVERSAL_GLOBAL_REGS\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_OPLINE_EX()\n"); + out($f,"# define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n"); + out($f,"# define SAVE_OPLINE() EX(opline) = opline\n"); + out($f,"# define SAVE_OPLINE_EX() SAVE_OPLINE()\n"); + out($f,"# define SAVE_OPLINE_EX2() SAVE_OPLINE()\n"); + out($f,"#elif defined(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"); @@ -2975,13 +2984,21 @@ function gen_vm($def, $skel) { out($f, "\tif (EXPECTED(opline)) {\n"); } out($f, "\t\tret = execute_data != ex ? (int)(execute_data->prev_execute_data != ex) + 1 : 0;\n"); + out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n"); + out($f, "\t\tEX(opline) = opline;\n"); + out($f,"#else\n"); out($f, "\t\tSAVE_OPLINE();\n"); + out($f,"#endif\n"); out($f, "\t} else {\n"); out($f, "\t\tret = -1;\n"); out($f, "\t}\n"); out($f, "#else\n"); out($f, "\tret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); + out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n"); + out($f, "\tEX(opline) = opline;\n"); + out($f,"#else\n"); out($f, "\tSAVE_OPLINE();\n"); + out($f,"#endif\n"); out($f, "#endif\n"); out($f, "#ifdef ZEND_VM_FP_GLOBAL_REG\n"); out($f, "\texecute_data = orig_execute_data;\n"); From c2bb539cfda7a673696bc41f53bfc3d4c368caa0 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 27 Nov 2023 00:44:43 +0100 Subject: [PATCH 02/16] Move copy exception ops --- Zend/zend_exceptions.c | 50 +++++++++++++++++++++++++++++------------- Zend/zend_exceptions.h | 11 +--------- 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index fddfea5ce8fcb..bb390064d4add 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -186,6 +186,40 @@ static zend_always_inline bool is_handle_exception_set(void) { || execute_data->opline->opcode == ZEND_HANDLE_EXCEPTION; } +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +static void zend_copy_exception_ops(void) +{ + const zend_op *orig_op = EG(opline_before_exception); + zend_op *exception_op = &EG(exception_op)[0]; + bool has_opdata = orig_op[1].opcode == ZEND_OP_DATA; + + /* The handler may still access opline. Make sure operands keep working. */ + const void *handler = exception_op->handler; + memcpy(exception_op, orig_op, sizeof(*exception_op)); + exception_op->opcode = ZEND_HANDLE_EXCEPTION; + exception_op->handler = handler; + zend_copy_exception_consts(/* op_data */ false); + if (has_opdata) { + memcpy(&exception_op[1], &orig_op[1], sizeof(exception_op[1])); + exception_op[1].opcode = ZEND_OP_DATA; + zend_copy_exception_consts(/* op_data */ true); + } else { + memcpy(&exception_op[1], &exception_op[2], sizeof(exception_op[1])); + } +} +#endif + +ZEND_API void zend_rethrow_exception(zend_execute_data *execute_data) +{ + if (EX(opline)->opcode != ZEND_HANDLE_EXCEPTION) { + EG(opline_before_exception) = EX(opline); + EX(opline) = EG(exception_op); + } +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + zend_copy_exception_ops(); +#endif +} + ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception) /* {{{ */ { #ifdef HAVE_DTRACE @@ -245,22 +279,8 @@ ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception) /* EG(opline_before_exception) = EG(current_execute_data)->opline; EG(current_execute_data)->opline = EG(exception_op); #ifdef ZEND_UNIVERSAL_GLOBAL_REGS - bool has_opdata = (opline + 1)->opcode == ZEND_OP_DATA; opline = EG(exception_op); - - /* The handler may still access opline. Make sure operands keep working. */ - const void *handler = EG(exception_op)[0].handler; - memcpy(&EG(exception_op)[0], EG(opline_before_exception), sizeof(EG(exception_op)[0])); - EG(exception_op)[0].opcode = ZEND_HANDLE_EXCEPTION; - EG(exception_op)[0].handler = handler; - zend_copy_exception_consts(/* op_data */ false); - if (has_opdata) { - memcpy(&EG(exception_op)[1], EG(opline_before_exception) + 1, sizeof(EG(exception_op)[1])); - EG(exception_op)[1].opcode = ZEND_OP_DATA; - zend_copy_exception_consts(/* op_data */ true); - } else { - memcpy(&EG(exception_op)[1], &EG(exception_op)[2], sizeof(EG(exception_op)[1])); - } + zend_copy_exception_ops(); #endif } /* }}} */ diff --git a/Zend/zend_exceptions.h b/Zend/zend_exceptions.h index 3c53245a3cadf..220b434b388cf 100644 --- a/Zend/zend_exceptions.h +++ b/Zend/zend_exceptions.h @@ -80,16 +80,7 @@ ZEND_API bool zend_is_graceful_exit(const zend_object *ex); #include "zend_globals.h" -static zend_always_inline void zend_rethrow_exception(zend_execute_data *execute_data) -{ - if (EX(opline)->opcode != ZEND_HANDLE_EXCEPTION) { - EG(opline_before_exception) = EX(opline); - EX(opline) = EG(exception_op); - } - if (EG(exception_op)[1].opcode != ZEND_HANDLE_EXCEPTION) { - memcpy(&EG(exception_op)[1], &EG(exception_op)[2], sizeof(EG(exception_op)[1])); - } -} +ZEND_API void zend_rethrow_exception(zend_execute_data *execute_data); END_EXTERN_C() From aabb072831144e075e044a353708a97130a0cb54 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 27 Nov 2023 01:46:16 +0100 Subject: [PATCH 03/16] Fix incorrect constant offset --- Zend/zend_exceptions.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index bb390064d4add..29a70c463ad98 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -169,12 +169,12 @@ static void zend_copy_exception_consts(bool op_data) if (orig_op->op1_type == IS_CONST) { zval *op1 = &EG(exception_consts)[opnum * 2]; ZVAL_COPY_VALUE(op1, RT_CONSTANT(orig_op, orig_op->op1)); - exception_op->op1.constant = (char *)op1 - (char *)&EG(opline_before_exception)[0]; + exception_op->op1.constant = (char *)op1 - (char *)&EG(exception_op)[0]; } if (orig_op->op2_type == IS_CONST) { zval *op2 = &EG(exception_consts)[opnum * 2 + 1]; ZVAL_COPY_VALUE(op2, RT_CONSTANT(orig_op, orig_op->op2)); - exception_op->op2.constant = (char *)op2 - (char *)&EG(opline_before_exception)[0]; + exception_op->op2.constant = (char *)op2 - (char *)&EG(exception_op)[0]; } } From d8c5b381ddfb2edfdd5b55bfffc4d2fe995e4863 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 28 Nov 2023 00:17:08 +0100 Subject: [PATCH 04/16] wip --- Zend/zend_exceptions.c | 12 ++++++++++++ Zend/zend_execute.c | 25 +++++++++++++++++-------- Zend/zend_execute_API.c | 15 +++++++++++---- Zend/zend_global_regs.h | 3 +++ Zend/zend_object_handlers.c | 8 ++++---- Zend/zend_vm_def.h | 7 +++---- Zend/zend_vm_execute.h | 17 +++++++---------- Zend/zend_vm_gen.php | 6 +++--- 8 files changed, 60 insertions(+), 33 deletions(-) diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 29a70c463ad98..7205c96a81bfb 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -276,7 +276,11 @@ ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception) /* /* no need to rethrow the exception */ return; } +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EG(opline_before_exception) = opline; +#else EG(opline_before_exception) = EG(current_execute_data)->opline; +#endif EG(current_execute_data)->opline = EG(exception_op); #ifdef ZEND_UNIVERSAL_GLOBAL_REGS opline = EG(exception_op); @@ -1074,7 +1078,11 @@ ZEND_API ZEND_COLD void zend_throw_unwind_exit(void) { ZEND_ASSERT(!EG(exception)); EG(exception) = zend_create_unwind_exit(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EG(opline_before_exception) = opline; +#else EG(opline_before_exception) = EG(current_execute_data)->opline; +#endif EG(current_execute_data)->opline = EG(exception_op); } @@ -1082,7 +1090,11 @@ ZEND_API ZEND_COLD void zend_throw_graceful_exit(void) { ZEND_ASSERT(!EG(exception)); EG(exception) = zend_create_graceful_exit(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EG(opline_before_exception) = opline; +#else EG(opline_before_exception) = EG(current_execute_data)->opline; +#endif EG(current_execute_data)->opline = EG(exception_op); } diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 36e2787aedc90..85c1152f34181 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -273,12 +273,12 @@ static zend_never_inline ZEND_COLD zval* zval_undefined_cv(uint32_t var EXECUTE_ static zend_never_inline ZEND_COLD zval* ZEND_FASTCALL _zval_undefined_op1(EXECUTE_DATA_D) { - return zval_undefined_cv(EX(opline)->op1.var EXECUTE_DATA_CC); + return zval_undefined_cv(ZEND_CURRENT_OPLINE->op1.var EXECUTE_DATA_CC); } static zend_never_inline ZEND_COLD zval* ZEND_FASTCALL _zval_undefined_op2(EXECUTE_DATA_D) { - return zval_undefined_cv(EX(opline)->op2.var EXECUTE_DATA_CC); + return zval_undefined_cv(ZEND_CURRENT_OPLINE->op2.var EXECUTE_DATA_CC); } #define ZVAL_UNDEFINED_OP1() _zval_undefined_op1(EXECUTE_DATA_C) @@ -1674,8 +1674,10 @@ static zend_never_inline zend_long zend_check_string_offset(zval *dim, int type ZEND_API ZEND_COLD void zend_wrong_string_offset_error(void) { const char *msg = NULL; +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS const zend_execute_data *execute_data = EG(current_execute_data); const zend_op *opline = execute_data->opline; +#endif if (UNEXPECTED(EG(exception) != NULL)) { return; @@ -5128,11 +5130,15 @@ zval * ZEND_FASTCALL zend_handle_named_arg( return arg; } -static zend_execute_data *start_fake_frame(zend_execute_data *call, const zend_op *opline) { +static zend_execute_data *start_fake_frame(zend_execute_data *call, const zend_op *op) { zend_execute_data *old_prev_execute_data = call->prev_execute_data; call->prev_execute_data = EG(current_execute_data); - call->opline = opline; + call->opline = op; EG(current_execute_data) = call; +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + old_prev_execute_data->opline = opline; + opline = op; +#endif return old_prev_execute_data; } @@ -5140,6 +5146,9 @@ static void end_fake_frame(zend_execute_data *call, zend_execute_data *old_prev_ zend_execute_data *prev_execute_data = call->prev_execute_data; EG(current_execute_data) = prev_execute_data; call->prev_execute_data = old_prev_execute_data; +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + opline = old_prev_execute_data->opline; +#endif if (UNEXPECTED(EG(exception)) && ZEND_USER_CODE(prev_execute_data->func->common.type)) { zend_rethrow_exception(prev_execute_data); } @@ -5300,7 +5309,7 @@ static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame(uint #define ZEND_VM_NEXT_OPCODE_EX(check_exception, skip) \ CHECK_SYMBOL_TABLES() \ if (check_exception) { \ - OPLINE = EX(opline) + (skip); \ + OPLINE = ZEND_CURRENT_OPLINE + (skip); \ } else { \ ZEND_ASSERT(!EG(exception)); \ OPLINE = opline + (skip); \ @@ -5348,7 +5357,7 @@ static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame(uint ZEND_VM_CONTINUE() #define ZEND_VM_SMART_BRANCH(_result, _check) do { \ if ((_check) && UNEXPECTED(EG(exception))) { \ - OPLINE = EX(opline); \ + OPLINE = ZEND_CURRENT_OPLINE; \ } else if (EXPECTED(opline->result_type == (IS_SMART_BRANCH_JMPZ|IS_TMP_VAR))) { \ if (_result) { \ ZEND_VM_SET_NEXT_OPCODE(opline + 2); \ @@ -5369,7 +5378,7 @@ static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame(uint } while (0) #define ZEND_VM_SMART_BRANCH_JMPZ(_result, _check) do { \ if ((_check) && UNEXPECTED(EG(exception))) { \ - OPLINE = EX(opline); \ + OPLINE = ZEND_CURRENT_OPLINE; \ } else if (_result) { \ ZEND_VM_SET_NEXT_OPCODE(opline + 2); \ } else { \ @@ -5379,7 +5388,7 @@ static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame(uint } while (0) #define ZEND_VM_SMART_BRANCH_JMPNZ(_result, _check) do { \ if ((_check) && UNEXPECTED(EG(exception))) { \ - OPLINE = EX(opline); \ + OPLINE = ZEND_CURRENT_OPLINE; \ } else if (!(_result)) { \ ZEND_VM_SET_NEXT_OPCODE(opline + 2); \ } else { \ diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index feeff659bd5f4..7430eba620e6a 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -38,6 +38,7 @@ #include "zend_inheritance.h" #include "zend_observer.h" #include "zend_call_stack.h" +#include "zend_global_regs.h" #ifdef HAVE_SYS_TIME_H #include #endif @@ -644,15 +645,21 @@ ZEND_API uint32_t zend_get_executed_lineno(void) /* {{{ */ ex = ex->prev_execute_data; } if (ex) { - if (!ex->opline) { +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + const zend_op *op = ex == EG(current_execute_data) ? opline : ex->opline; +#else + const zend_op *op = ex->opline; +#endif + + if (!op) { /* Missing SAVE_OPLINE()? Falling back to first line of function */ return ex->func->op_array.opcodes[0].lineno; } - if (EG(exception) && ex->opline->opcode == ZEND_HANDLE_EXCEPTION && - ex->opline->lineno == 0 && EG(opline_before_exception)) { + if (EG(exception) && op->opcode == ZEND_HANDLE_EXCEPTION && + op->lineno == 0 && EG(opline_before_exception)) { return EG(opline_before_exception)->lineno; } - return ex->opline->lineno; + return op->lineno; } else { return 0; } diff --git a/Zend/zend_global_regs.h b/Zend/zend_global_regs.h index 1991f2d56a467..e107b1cd2b98a 100644 --- a/Zend/zend_global_regs.h +++ b/Zend/zend_global_regs.h @@ -44,6 +44,9 @@ # pragma GCC diagnostic ignored "-Wvolatile-register-var" register const zend_op* volatile opline __asm__(ZEND_VM_IP_GLOBAL_REG); # pragma GCC diagnostic warning "-Wvolatile-register-var" +# define ZEND_CURRENT_OPLINE opline +#else +# define ZEND_CURRENT_OPLINE EX(opline) #endif #endif /* ZEND_GLOBAL_REGS_H */ diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index e559feaf5a04c..59ff5c053763d 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -868,10 +868,10 @@ found:; if (execute_data && EX(func) && ZEND_USER_CODE(EX(func)->common.type) - && EX(opline) - && EX(opline)->opcode == ZEND_ASSIGN_OBJ - && EX(opline)->result_type) { - ZVAL_COPY_DEREF(EX_VAR(EX(opline)->result.var), variable_ptr); + && ZEND_CURRENT_OPLINE + && ZEND_CURRENT_OPLINE->opcode == ZEND_ASSIGN_OBJ + && ZEND_CURRENT_OPLINE->result_type) { + ZVAL_COPY_DEREF(EX_VAR(ZEND_CURRENT_OPLINE->result.var), variable_ptr); variable_ptr = NULL; } rc_dtor_func(garbage); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index c36e678d7a6d9..1ff5ae1a31431 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -4173,7 +4173,7 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL,OBSERVER)) ZEND_OBSERVER_FCALL_BEGIN(execute_data); ZEND_VM_ENTER_EX(); } else { - SAVE_OPLINE_EX2(); + SAVE_OPLINE_EX(); ZEND_OBSERVER_FCALL_BEGIN(execute_data); execute_data = EX(prev_execute_data); LOAD_OPLINE(); @@ -8783,8 +8783,7 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY, SPEC(OBSERVER)) uint32_t num_args = EX_NUM_ARGS(); zend_execute_data *call; - /* May we delay this? Probably doesn't matter too much. */ - SAVE_OPLINE_EX2(); + SAVE_OPLINE_EX(); if (num_args) { zval *p = ZEND_CALL_ARG(execute_data, 1); @@ -8839,7 +8838,7 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY, SPEC(OBSERVER)) ZEND_OBSERVER_FCALL_BEGIN(execute_data); ZEND_VM_ENTER_EX(); } else { - SAVE_OPLINE_EX2(); + SAVE_OPLINE_EX(); ZEND_OBSERVER_FCALL_BEGIN(execute_data); execute_data = EX(prev_execute_data); if (execute_data) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index fe62d5c8afc2c..5b3901435b0b9 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -401,7 +401,6 @@ typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_H # define LOAD_NEXT_OPLINE() opline = EX(opline) + 1 # define SAVE_OPLINE() EX(opline) = opline # define SAVE_OPLINE_EX() SAVE_OPLINE() -# define SAVE_OPLINE_EX2() SAVE_OPLINE() #elif defined(ZEND_VM_IP_GLOBAL_REG) # define OPLINE opline # define USE_OPLINE @@ -1838,7 +1837,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV ZEND_VM_ENTER_EX(); } else { - SAVE_OPLINE_EX2(); + SAVE_OPLINE_EX(); execute_data = EX(prev_execute_data); LOAD_OPLINE(); @@ -1947,7 +1946,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV ZEND_VM_ENTER_EX(); } else { - SAVE_OPLINE_EX2(); + SAVE_OPLINE_EX(); execute_data = EX(prev_execute_data); LOAD_OPLINE(); @@ -2056,7 +2055,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_OBS zend_observer_fcall_begin(execute_data); ZEND_VM_ENTER_EX(); } else { - SAVE_OPLINE_EX2(); + SAVE_OPLINE_EX(); zend_observer_fcall_begin(execute_data); execute_data = EX(prev_execute_data); LOAD_OPLINE(); @@ -3412,8 +3411,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z uint32_t num_args = EX_NUM_ARGS(); zend_execute_data *call; - /* May we delay this? Probably doesn't matter too much. */ - SAVE_OPLINE_EX2(); + SAVE_OPLINE_EX(); if (num_args) { zval *p = ZEND_CALL_ARG(execute_data, 1); @@ -3468,7 +3466,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z ZEND_VM_ENTER_EX(); } else { - SAVE_OPLINE_EX2(); + SAVE_OPLINE_EX(); execute_data = EX(prev_execute_data); if (execute_data) { @@ -3553,8 +3551,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_OBSERVER_ uint32_t num_args = EX_NUM_ARGS(); zend_execute_data *call; - /* May we delay this? Probably doesn't matter too much. */ - SAVE_OPLINE_EX2(); + SAVE_OPLINE_EX(); if (num_args) { zval *p = ZEND_CALL_ARG(execute_data, 1); @@ -3609,7 +3606,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_OBSERVER_ zend_observer_fcall_begin(execute_data); ZEND_VM_ENTER_EX(); } else { - SAVE_OPLINE_EX2(); + SAVE_OPLINE_EX(); zend_observer_fcall_begin(execute_data); execute_data = EX(prev_execute_data); if (execute_data) { diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index 449e4cac35e1c..a65c80ddafe48 100755 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -1905,10 +1905,10 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"# define USE_OPLINE\n"); out($f,"# define LOAD_OPLINE() opline = EX(opline)\n"); out($f,"# define LOAD_OPLINE_EX()\n"); + /* Called on restored frames with a valid EX(opline). */ out($f,"# define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n"); out($f,"# define SAVE_OPLINE() EX(opline) = opline\n"); out($f,"# define SAVE_OPLINE_EX() SAVE_OPLINE()\n"); - out($f,"# define SAVE_OPLINE_EX2() SAVE_OPLINE()\n"); out($f,"#elif defined(ZEND_VM_IP_GLOBAL_REG)\n"); out($f,"# define OPLINE opline\n"); out($f,"# define USE_OPLINE\n"); @@ -1966,7 +1966,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"# define LOAD_OPLINE_EX() LOAD_OPLINE()\n"); out($f,"#define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n"); out($f,"#define SAVE_OPLINE() EX(opline) = opline\n"); - out($f,"#define SAVE_OPLINE_EX()\n"); + out($f,"#define SAVE_OPLINE_EX() SAVE_OPLINE()\n"); out($f,"#define HANDLE_EXCEPTION() ZEND_ASSERT(EG(exception)); LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); out($f,"#define HANDLE_EXCEPTION_LEAVE() ZEND_ASSERT(EG(exception)); LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); out($f,"#define ZEND_VM_CONTINUE() goto zend_vm_continue\n"); @@ -1992,7 +1992,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"#define LOAD_OPLINE_EX() LOAD_OPLINE()\n"); out($f,"#define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n"); out($f,"#define SAVE_OPLINE() EX(opline) = opline\n"); - out($f,"#define SAVE_OPLINE_EX()\n"); + out($f,"#define SAVE_OPLINE_EX() SAVE_OPLINE()\n"); if (ZEND_VM_SPEC) { out($f,"#define HANDLE_EXCEPTION() ZEND_ASSERT(EG(exception)); goto ZEND_HANDLE_EXCEPTION_SPEC_LABEL\n"); out($f,"#define HANDLE_EXCEPTION_LEAVE() ZEND_ASSERT(EG(exception)); goto ZEND_HANDLE_EXCEPTION_SPEC_LABEL\n"); From 1cf05b5b242010cbf37b62d64c26cd1078ed9c31 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 29 Nov 2023 11:57:02 +0100 Subject: [PATCH 05/16] Fixes --- Zend/zend_exceptions.c | 36 ++++++++++++++++++------------------ Zend/zend_execute.c | 8 ++++++-- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 7205c96a81bfb..d731005ea20e3 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -160,33 +160,32 @@ void zend_exception_restore(void) /* {{{ */ } /* }}} */ -static void zend_copy_exception_consts(bool op_data) +static zend_always_inline bool is_handle_exception_set(void) { + zend_execute_data *execute_data = EG(current_execute_data); + return !execute_data + || !execute_data->func + || !ZEND_USER_CODE(execute_data->func->common.type) + || execute_data->opline->opcode == ZEND_HANDLE_EXCEPTION; +} + +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +static void zend_copy_exception_consts(uint32_t opnum) { - uint32_t opnum = op_data ? 1 : 0; const zend_op *orig_op = &EG(opline_before_exception)[opnum]; zend_op *exception_op = &EG(exception_op)[opnum]; if (orig_op->op1_type == IS_CONST) { zval *op1 = &EG(exception_consts)[opnum * 2]; ZVAL_COPY_VALUE(op1, RT_CONSTANT(orig_op, orig_op->op1)); - exception_op->op1.constant = (char *)op1 - (char *)&EG(exception_op)[0]; + exception_op->op1.constant = (char *)op1 - (char *)exception_op; } if (orig_op->op2_type == IS_CONST) { zval *op2 = &EG(exception_consts)[opnum * 2 + 1]; ZVAL_COPY_VALUE(op2, RT_CONSTANT(orig_op, orig_op->op2)); - exception_op->op2.constant = (char *)op2 - (char *)&EG(exception_op)[0]; + exception_op->op2.constant = (char *)op2 - (char *)exception_op; } } -static zend_always_inline bool is_handle_exception_set(void) { - zend_execute_data *execute_data = EG(current_execute_data); - return !execute_data - || !execute_data->func - || !ZEND_USER_CODE(execute_data->func->common.type) - || execute_data->opline->opcode == ZEND_HANDLE_EXCEPTION; -} - -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS static void zend_copy_exception_ops(void) { const zend_op *orig_op = EG(opline_before_exception); @@ -195,16 +194,16 @@ static void zend_copy_exception_ops(void) /* The handler may still access opline. Make sure operands keep working. */ const void *handler = exception_op->handler; - memcpy(exception_op, orig_op, sizeof(*exception_op)); + *exception_op = *orig_op; exception_op->opcode = ZEND_HANDLE_EXCEPTION; exception_op->handler = handler; - zend_copy_exception_consts(/* op_data */ false); + zend_copy_exception_consts(/* opnum */ 0); if (has_opdata) { - memcpy(&exception_op[1], &orig_op[1], sizeof(exception_op[1])); + exception_op[1] = orig_op[1]; exception_op[1].opcode = ZEND_OP_DATA; - zend_copy_exception_consts(/* op_data */ true); + zend_copy_exception_consts(/* opnum */ 1); } else { - memcpy(&exception_op[1], &exception_op[2], sizeof(exception_op[1])); + exception_op[1] = exception_op[2]; } } #endif @@ -214,6 +213,7 @@ ZEND_API void zend_rethrow_exception(zend_execute_data *execute_data) if (EX(opline)->opcode != ZEND_HANDLE_EXCEPTION) { EG(opline_before_exception) = EX(opline); EX(opline) = EG(exception_op); + opline = EG(exception_op); } #ifdef ZEND_UNIVERSAL_GLOBAL_REGS zend_copy_exception_ops(); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 85c1152f34181..38a943fbd7ffa 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -5136,7 +5136,9 @@ static zend_execute_data *start_fake_frame(zend_execute_data *call, const zend_o call->opline = op; EG(current_execute_data) = call; #ifdef ZEND_UNIVERSAL_GLOBAL_REGS - old_prev_execute_data->opline = opline; + if (call->prev_execute_data) { + call->prev_execute_data->opline = opline; + } opline = op; #endif return old_prev_execute_data; @@ -5147,7 +5149,9 @@ static void end_fake_frame(zend_execute_data *call, zend_execute_data *old_prev_ EG(current_execute_data) = prev_execute_data; call->prev_execute_data = old_prev_execute_data; #ifdef ZEND_UNIVERSAL_GLOBAL_REGS - opline = old_prev_execute_data->opline; + if (prev_execute_data) { + opline = prev_execute_data->opline; + } #endif if (UNEXPECTED(EG(exception)) && ZEND_USER_CODE(prev_execute_data->func->common.type)) { zend_rethrow_exception(prev_execute_data); From c212ef2d43850f2ba6958106dbc7e6f9017918ee Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 29 Nov 2023 15:55:20 +0100 Subject: [PATCH 06/16] Fix restoring of exception op after destructors --- Zend/zend_objects.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index 4c4b3cf30c13d..94d6911d2d5d5 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -174,6 +174,11 @@ ZEND_API void zend_objects_destroy_object(zend_object *object) if (old_exception) { EG(opline_before_exception) = old_opline_before_exception; + if (EG(current_execute_data) + && EG(current_execute_data)->func + && ZEND_USER_CODE(EG(current_execute_data)->func->common.type)) { + zend_rethrow_exception(EG(current_execute_data)); + } if (EG(exception)) { zend_exception_set_previous(EG(exception), old_exception); } else { From ea5b12bc2ecd0be99359cba6077b7c21f64183a4 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Fri, 1 Dec 2023 22:01:03 +0100 Subject: [PATCH 07/16] wip --- Zend/zend_builtin_functions.c | 1 + Zend/zend_exceptions.c | 17 +++- Zend/zend_execute.c | 8 +- Zend/zend_execute.h | 1 + Zend/zend_execute_API.c | 3 + Zend/zend_generators.c | 21 +++-- Zend/zend_global_regs.h | 14 ++++ Zend/zend_vm_def.h | 33 ++++++-- Zend/zend_vm_execute.h | 140 +++++++++++++++++++++++++++----- Zend/zend_vm_gen.php | 10 ++- ext/reflection/php_reflection.c | 22 +++-- 11 files changed, 226 insertions(+), 44 deletions(-) diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 5ca335170a216..c17883ca3cd48 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -31,6 +31,7 @@ #include "zend_generators.h" #include "zend_builtin_functions_arginfo.h" #include "zend_smart_str.h" +#include "zend_global_regs.h" /* }}} */ diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index d731005ea20e3..7a27d3f674755 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -165,7 +165,11 @@ static zend_always_inline bool is_handle_exception_set(void) { return !execute_data || !execute_data->func || !ZEND_USER_CODE(execute_data->func->common.type) +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + || opline->opcode == ZEND_HANDLE_EXCEPTION; +#else || execute_data->opline->opcode == ZEND_HANDLE_EXCEPTION; +#endif } #ifdef ZEND_UNIVERSAL_GLOBAL_REGS @@ -210,12 +214,18 @@ static void zend_copy_exception_ops(void) ZEND_API void zend_rethrow_exception(zend_execute_data *execute_data) { +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + if (opline->opcode != ZEND_HANDLE_EXCEPTION) { + EG(opline_before_exception) = opline; + } +#else if (EX(opline)->opcode != ZEND_HANDLE_EXCEPTION) { EG(opline_before_exception) = EX(opline); - EX(opline) = EG(exception_op); - opline = EG(exception_op); } +#endif + EX(opline) = EG(exception_op); #ifdef ZEND_UNIVERSAL_GLOBAL_REGS + opline = EG(exception_op); zend_copy_exception_ops(); #endif } @@ -305,6 +315,9 @@ ZEND_API void zend_clear_exception(void) /* {{{ */ OBJ_RELEASE(exception); if (EG(current_execute_data)) { EG(current_execute_data)->opline = EG(opline_before_exception); + if (ZEND_USER_CODE(EG(current_execute_data)->func->type)) { + LOAD_CURRENT_OPLINE(); + } } #if ZEND_DEBUG EG(opline_before_exception) = NULL; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 38a943fbd7ffa..8f1662d3dfea5 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -178,6 +178,12 @@ ZEND_API const zend_internal_function zend_pass_function = { (((size) + ZEND_VM_STACK_HEADER_SLOTS * sizeof(zval) \ + ((page_size) - 1)) & ~((page_size) - 1)) +void init_executor_ex(void) +{ + opline = NULL; + execute_data = NULL; +} + ZEND_API void zend_vm_stack_init(void) { EG(vm_stack_page_size) = ZEND_VM_STACK_PAGE_SIZE; @@ -1674,7 +1680,7 @@ static zend_never_inline zend_long zend_check_string_offset(zval *dim, int type ZEND_API ZEND_COLD void zend_wrong_string_offset_error(void) { const char *msg = NULL; -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifndef ZEND_UNIVERSAL_GLOBAL_REGS const zend_execute_data *execute_data = EG(current_execute_data); const zend_op *opline = execute_data->opline; #endif diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index d0c18040ab46d..417a0f212d819 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -37,6 +37,7 @@ ZEND_API extern void (*zend_execute_internal)(zend_execute_data *execute_data, z ZEND_API extern zend_class_entry *(*zend_autoload)(zend_string *name, zend_string *lc_name); void init_executor(void); +void init_executor_ex(void); void shutdown_executor(void); void shutdown_destructors(void); ZEND_API void zend_shutdown_executor_values(bool fast_shutdown); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 7430eba620e6a..bbd41938400bd 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -133,6 +133,8 @@ void init_executor(void) /* {{{ */ { zend_init_fpu(); + init_executor_ex(); + ZVAL_NULL(&EG(uninitialized_zval)); ZVAL_ERROR(&EG(error_zval)); /* destroys stack frame, therefore makes core dumps worthless */ @@ -817,6 +819,7 @@ zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_ call = zend_vm_stack_push_call_frame(call_info, func, fci->param_count, object_or_called_scope); + SAVE_CURRENT_OPLINE(); if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_DEPRECATED)) { zend_deprecated_function(func); diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 29f0ea2cc278a..f2127547f6f11 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -457,12 +457,10 @@ static void zend_generator_throw_exception(zend_generator *generator, zval *exce /* Throw the exception in the context of the generator. Decrementing the opline * to pretend the exception happened during the YIELD opcode. */ + SAVE_CURRENT_OPLINE(); EG(current_execute_data) = generator->execute_data; generator->execute_data->opline--; -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS - original_execute_data->opline = opline; - opline = EG(current_execute_data)->opline; -#endif + LOAD_CURRENT_OPLINE(); if (exception) { zend_throw_exception_object(exception); @@ -478,9 +476,7 @@ static void zend_generator_throw_exception(zend_generator *generator, zval *exce generator->execute_data->opline++; EG(current_execute_data) = original_execute_data; -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS - opline = original_execute_data->opline; -#endif + LOAD_CURRENT_OPLINE(); } static void zend_generator_add_child(zend_generator *generator, zend_generator *child) @@ -573,6 +569,10 @@ ZEND_API zend_generator *zend_generator_update_current(zend_generator *generator /* Throw the exception in the context of the generator */ zend_execute_data *original_execute_data = EG(current_execute_data); EG(current_execute_data) = new_root->execute_data; +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + original_execute_data->opline = opline; + opline = EG(current_execute_data)->opline; +#endif if (new_root == generator) { new_root->execute_data->prev_execute_data = original_execute_data; @@ -586,6 +586,9 @@ ZEND_API zend_generator *zend_generator_update_current(zend_generator *generator zend_throw_exception(zend_ce_ClosedGeneratorException, "Generator yielded from aborted, no return value available", 0); EG(current_execute_data) = original_execute_data; +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + opline = EG(current_execute_data)->opline; +#endif if (!((old_root ? old_root : generator)->flags & ZEND_GENERATOR_CURRENTLY_RUNNING)) { new_root->node.parent = NULL; @@ -733,7 +736,9 @@ ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */ uint32_t original_jit_trace_num = EG(jit_trace_num); /* Set executor globals */ + SAVE_CURRENT_OPLINE(); EG(current_execute_data) = generator->execute_data; + LOAD_CURRENT_OPLINE(); EG(jit_trace_num) = 0; /* We want the backtrace to look as if the generator function was @@ -753,6 +758,7 @@ ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */ if (EXPECTED(zend_generator_get_next_delegated_value(generator) == SUCCESS)) { /* Restore executor globals */ EG(current_execute_data) = original_execute_data; + LOAD_CURRENT_OPLINE(); EG(jit_trace_num) = original_jit_trace_num; orig_generator->flags &= ~ZEND_GENERATOR_DO_INIT; @@ -791,6 +797,7 @@ ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */ /* Restore executor globals */ EG(current_execute_data) = original_execute_data; + LOAD_CURRENT_OPLINE(); EG(jit_trace_num) = original_jit_trace_num; /* If an exception was thrown in the generator we have to internally diff --git a/Zend/zend_global_regs.h b/Zend/zend_global_regs.h index e107b1cd2b98a..bce6d8c7cb5db 100644 --- a/Zend/zend_global_regs.h +++ b/Zend/zend_global_regs.h @@ -45,8 +45,22 @@ register const zend_op* volatile opline __asm__(ZEND_VM_IP_GLOBAL_REG); # pragma GCC diagnostic warning "-Wvolatile-register-var" # define ZEND_CURRENT_OPLINE opline +# define SAVE_CURRENT_OPLINE() \ + do { \ + if (EG(current_execute_data)) { \ + EG(current_execute_data)->opline = opline; \ + } \ + } while (0) +# define LOAD_CURRENT_OPLINE() \ + do { \ + if (EG(current_execute_data)) { \ + opline = EG(current_execute_data)->opline; \ + } \ + } while (0) #else # define ZEND_CURRENT_OPLINE EX(opline) +# define SAVE_CURRENT_OPLINE() +# define LOAD_CURRENT_OPLINE() #endif #endif /* ZEND_GLOBAL_REGS_H */ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 1ff5ae1a31431..f5a166b42a03d 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2853,10 +2853,13 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) { zend_execute_data *old_execute_data; uint32_t call_info = EX_CALL_INFO(); - SAVE_OPLINE(); + SAVE_OPLINE_EX(); if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED|ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) == 0)) { EG(current_execute_data) = EX(prev_execute_data); + if (EG(current_execute_data)) { + opline = EG(current_execute_data)->opline; + } i_free_compiled_variables(execute_data); #ifdef ZEND_PREFER_RELOAD @@ -2879,6 +2882,9 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) ZEND_VM_LEAVE(); } else if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP)) == 0)) { EG(current_execute_data) = EX(prev_execute_data); + if (EG(current_execute_data)) { + opline = EG(current_execute_data)->opline; + } i_free_compiled_variables(execute_data); #ifdef ZEND_PREFER_RELOAD @@ -2923,6 +2929,9 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) efree_size(EX(func), sizeof(zend_op_array)); old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); + if (EG(current_execute_data)) { + opline = EG(current_execute_data)->opline; + } zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); if (call_info & ZEND_CALL_NEEDS_REATTACH) { @@ -2942,6 +2951,9 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) } else { if (EXPECTED((call_info & ZEND_CALL_CODE) == 0)) { EG(current_execute_data) = EX(prev_execute_data); + if (EG(current_execute_data)) { + opline = EG(current_execute_data)->opline; + } i_free_compiled_variables(execute_data); #ifdef ZEND_PREFER_RELOAD call_info = EX_CALL_INFO(); @@ -2983,6 +2995,9 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) } } EG(current_execute_data) = EX(prev_execute_data); + if (EG(current_execute_data)) { + opline = EG(current_execute_data)->opline; + } ZEND_VM_RETURN(); } } @@ -3967,7 +3982,7 @@ ZEND_VM_HOT_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL,OBSERVER)) zval *ret; zval retval; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); EX(call) = call->prev_execute_data; call->prev_execute_data = execute_data; @@ -4031,7 +4046,7 @@ ZEND_VM_HOT_HANDLER(130, ZEND_DO_UCALL, ANY, ANY, SPEC(RETVAL,OBSERVER)) zend_function *fbc = call->func; zval *ret; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); EX(call) = call->prev_execute_data; ret = NULL; @@ -4056,7 +4071,7 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL,OBSERVER)) zend_function *fbc = call->func; zval *ret; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); EX(call) = call->prev_execute_data; if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { @@ -4154,7 +4169,7 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL,OBSERVER)) zend_function *fbc = call->func; zval *ret; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); EX(call) = call->prev_execute_data; if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { @@ -6388,7 +6403,7 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMPVAR|CV, ANY, EVAL, SPEC(OBSER zend_op_array *new_op_array; zval *inc_filename; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); inc_filename = GET_OP1_ZVAL_PTR(BP_VAR_R); new_op_array = zend_include_or_eval(inc_filename, opline->extended_value); if (UNEXPECTED(EG(exception) != NULL)) { @@ -8331,6 +8346,9 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMPVAR|CV|UNUSED /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -8437,6 +8455,9 @@ ZEND_VM_C_LABEL(yield_from_try_again): /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 5b3901435b0b9..bfb72d45ac03a 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -399,8 +399,8 @@ typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_H # define LOAD_OPLINE() opline = EX(opline) # define LOAD_OPLINE_EX() # define LOAD_NEXT_OPLINE() opline = EX(opline) + 1 -# define SAVE_OPLINE() EX(opline) = opline -# define SAVE_OPLINE_EX() SAVE_OPLINE() +# define SAVE_OPLINE() +# define SAVE_OPLINE_EX() EX(opline) = opline #elif defined(ZEND_VM_IP_GLOBAL_REG) # define OPLINE opline # define USE_OPLINE @@ -1117,10 +1117,13 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper { zend_execute_data *old_execute_data; uint32_t call_info = EX_CALL_INFO(); - SAVE_OPLINE(); + SAVE_OPLINE_EX(); if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED|ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) == 0)) { EG(current_execute_data) = EX(prev_execute_data); + if (EG(current_execute_data)) { + opline = EG(current_execute_data)->opline; + } i_free_compiled_variables(execute_data); #ifdef ZEND_PREFER_RELOAD @@ -1143,6 +1146,9 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper ZEND_VM_LEAVE(); } else if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP)) == 0)) { EG(current_execute_data) = EX(prev_execute_data); + if (EG(current_execute_data)) { + opline = EG(current_execute_data)->opline; + } i_free_compiled_variables(execute_data); #ifdef ZEND_PREFER_RELOAD @@ -1187,6 +1193,9 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper efree_size(EX(func), sizeof(zend_op_array)); old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); + if (EG(current_execute_data)) { + opline = EG(current_execute_data)->opline; + } zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); if (call_info & ZEND_CALL_NEEDS_REATTACH) { @@ -1206,6 +1215,9 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper } else { if (EXPECTED((call_info & ZEND_CALL_CODE) == 0)) { EG(current_execute_data) = EX(prev_execute_data); + if (EG(current_execute_data)) { + opline = EG(current_execute_data)->opline; + } i_free_compiled_variables(execute_data); #ifdef ZEND_PREFER_RELOAD call_info = EX_CALL_INFO(); @@ -1247,6 +1259,9 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper } } EG(current_execute_data) = EX(prev_execute_data); + if (EG(current_execute_data)) { + opline = EG(current_execute_data)->opline; + } ZEND_VM_RETURN(); } } @@ -1267,7 +1282,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_RETV zval *ret; zval retval; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); EX(call) = call->prev_execute_data; call->prev_execute_data = execute_data; @@ -1330,7 +1345,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_RETV zval *ret; zval retval; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); EX(call) = call->prev_execute_data; call->prev_execute_data = execute_data; @@ -1393,7 +1408,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_OBS zval *ret; zval retval; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); EX(call) = call->prev_execute_data; call->prev_execute_data = execute_data; @@ -1457,7 +1472,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UCALL_SPEC_RETV zend_function *fbc = call->func; zval *ret; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); EX(call) = call->prev_execute_data; ret = NULL; @@ -1481,7 +1496,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UCALL_SPEC_RETV zend_function *fbc = call->func; zval *ret; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); EX(call) = call->prev_execute_data; ret = NULL; @@ -1505,7 +1520,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UCALL_SPEC_OBS zend_function *fbc = call->func; zval *ret; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); EX(call) = call->prev_execute_data; ret = NULL; @@ -1530,7 +1545,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S zend_function *fbc = call->func; zval *ret; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); EX(call) = call->prev_execute_data; if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { @@ -1625,7 +1640,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S zend_function *fbc = call->func; zval *ret; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); EX(call) = call->prev_execute_data; if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { @@ -1720,7 +1735,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_ zend_function *fbc = call->func; zval *ret; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); EX(call) = call->prev_execute_data; if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { @@ -1818,7 +1833,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV zend_function *fbc = call->func; zval *ret; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); EX(call) = call->prev_execute_data; if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { @@ -1927,7 +1942,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV zend_function *fbc = call->func; zval *ret; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); EX(call) = call->prev_execute_data; if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { @@ -2036,7 +2051,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_OBS zend_function *fbc = call->func; zval *ret; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); EX(call) = call->prev_execute_data; if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { @@ -4985,7 +5000,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HAN zend_op_array *new_op_array; zval *inc_filename; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); inc_filename = RT_CONSTANT(opline, opline->op1); new_op_array = zend_include_or_eval(inc_filename, opline->extended_value); if (UNEXPECTED(EG(exception) != NULL)) { @@ -5068,7 +5083,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_OBSERVER_ zend_op_array *new_op_array; zval *inc_filename; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); inc_filename = get_zval_ptr(opline->op1_type, opline->op1, BP_VAR_R); new_op_array = zend_include_or_eval(inc_filename, opline->extended_value); if (UNEXPECTED(EG(exception) != NULL)) { @@ -5606,6 +5621,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_CONST_HANDLER( /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -7766,6 +7784,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CONST_HANDLER /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -10048,6 +10069,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMPVAR_HANDLE /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -10897,6 +10921,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLE /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -12432,6 +12459,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZE /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -14801,7 +14831,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMPVAR_HA zend_op_array *new_op_array; zval *inc_filename; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); inc_filename = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); new_op_array = zend_include_or_eval(inc_filename, opline->extended_value); if (UNEXPECTED(EG(exception) != NULL)) { @@ -14980,6 +15010,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_TMPVAR_HANDLER /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -20299,6 +20332,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(Z /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -20744,6 +20780,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_TMPVAR_HANDLER( /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -21204,6 +21243,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER( /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -21608,6 +21650,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -25572,6 +25617,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CONST_HANDLER(Z /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -28025,6 +28073,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_TMPVAR_HANDLER( /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -29980,6 +30031,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER( /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -32410,6 +32464,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -34602,6 +34659,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CONST_HANDLE /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -36486,6 +36546,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_TMPVAR_HANDL /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -37027,6 +37090,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDL /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -38979,6 +39045,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(Z /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -39836,7 +39905,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLE zend_op_array *new_op_array; zval *inc_filename; - SAVE_OPLINE(); + SAVE_OPLINE_EX(); inc_filename = _get_zval_ptr_cv_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC); new_op_array = zend_include_or_eval(inc_filename, opline->extended_value); if (UNEXPECTED(EG(exception) != NULL)) { @@ -40338,6 +40407,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_CV_HANDLER(ZEN /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -44322,6 +44394,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZE /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -47921,6 +47996,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CV_TMPVAR_HANDLER(Z /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -49779,6 +49857,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(Z /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -53404,6 +53485,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CV_HANDLER(ZEND_ /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); +#ifdef ZEND_UNIVERSAL_GLOBAL_REGS + EX(opline) = opline; +#endif ZEND_VM_RETURN(); } @@ -57083,10 +57167,13 @@ ZEND_API void execute_ex(zend_execute_data *ex) { zend_execute_data *old_execute_data; uint32_t call_info = EX_CALL_INFO(); - SAVE_OPLINE(); + SAVE_OPLINE_EX(); if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED|ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) == 0)) { EG(current_execute_data) = EX(prev_execute_data); + if (EG(current_execute_data)) { + opline = EG(current_execute_data)->opline; + } i_free_compiled_variables(execute_data); #ifdef ZEND_PREFER_RELOAD @@ -57109,6 +57196,9 @@ ZEND_API void execute_ex(zend_execute_data *ex) ZEND_VM_LEAVE(); } else if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP)) == 0)) { EG(current_execute_data) = EX(prev_execute_data); + if (EG(current_execute_data)) { + opline = EG(current_execute_data)->opline; + } i_free_compiled_variables(execute_data); #ifdef ZEND_PREFER_RELOAD @@ -57153,6 +57243,9 @@ ZEND_API void execute_ex(zend_execute_data *ex) efree_size(EX(func), sizeof(zend_op_array)); old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); + if (EG(current_execute_data)) { + opline = EG(current_execute_data)->opline; + } zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); if (call_info & ZEND_CALL_NEEDS_REATTACH) { @@ -57172,6 +57265,9 @@ ZEND_API void execute_ex(zend_execute_data *ex) } else { if (EXPECTED((call_info & ZEND_CALL_CODE) == 0)) { EG(current_execute_data) = EX(prev_execute_data); + if (EG(current_execute_data)) { + opline = EG(current_execute_data)->opline; + } i_free_compiled_variables(execute_data); #ifdef ZEND_PREFER_RELOAD call_info = EX_CALL_INFO(); @@ -57213,6 +57309,9 @@ ZEND_API void execute_ex(zend_execute_data *ex) } } EG(current_execute_data) = EX(prev_execute_data); + if (EG(current_execute_data)) { + opline = EG(current_execute_data)->opline; + } ZEND_VM_RETURN(); } } @@ -65364,6 +65463,7 @@ void zend_vm_init(void) #if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) zend_opcode_handler_funcs = labels; zend_spec_handlers = specs; + execute_data = NULL; execute_ex(NULL); #else zend_opcode_handlers = labels; diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index a65c80ddafe48..f56302a9f762e 100755 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -1907,8 +1907,8 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"# define LOAD_OPLINE_EX()\n"); /* Called on restored frames with a valid EX(opline). */ out($f,"# define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n"); - out($f,"# define SAVE_OPLINE() EX(opline) = opline\n"); - out($f,"# define SAVE_OPLINE_EX() SAVE_OPLINE()\n"); + out($f,"# define SAVE_OPLINE()\n"); + out($f,"# define SAVE_OPLINE_EX() EX(opline) = opline\n"); out($f,"#elif defined(ZEND_VM_IP_GLOBAL_REG)\n"); out($f,"# define OPLINE opline\n"); out($f,"# define USE_OPLINE\n"); @@ -2066,6 +2066,11 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"#endif\n"); out($f,$m[1]."} vm_stack_data;\n"); out($f,"#endif\n"); + // out($f,"#ifdef ZEND_UNIVERSAL_GLOBAL_REGS\n"); + // out($f,$m[1]."if (EG(current_execute_data) && EG(current_execute_data) != ex && opline) {\n"); + // out($f,$m[1]."\tEG(current_execute_data)->opline = opline;\n"); + // out($f,$m[1]."}\n"); + // out($f,"#endif\n"); out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n"); out($f,$m[1]."vm_stack_data.orig_opline = opline;\n"); out($f,"#endif\n"); @@ -2217,6 +2222,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); out($f,$prolog."zend_opcode_handler_funcs = labels;\n"); out($f,$prolog."zend_spec_handlers = specs;\n"); + out($f,$prolog."execute_data = NULL;\n"); out($f,$prolog.$executor_name."_ex(NULL);\n"); out($f,"#else\n"); } diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index a725573aa9076..dec43064ccc6e 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -45,6 +45,7 @@ #include "zend_smart_str.h" #include "zend_enum.h" #include "zend_fibers.h" +#include "zend_global_regs.h" #define REFLECTION_ATTRIBUTE_IS_INSTANCEOF (1 << 1) @@ -2250,6 +2251,8 @@ ZEND_METHOD(ReflectionGenerator, getTrace) RETURN_THROWS(); } + SAVE_CURRENT_OPLINE(); + REFLECTION_CHECK_VALID_GENERATOR(ex) root_generator = zend_generator_get_current(generator); @@ -2264,8 +2267,10 @@ ZEND_METHOD(ReflectionGenerator, getTrace) } EG(current_execute_data) = root_generator->execute_data; + LOAD_CURRENT_OPLINE(); zend_fetch_debug_backtrace(return_value, 0, options, 0); EG(current_execute_data) = ex_backup; + LOAD_CURRENT_OPLINE(); root_generator->execute_data->prev_execute_data = root_prev; generator->execute_data->prev_execute_data = cur_prev; @@ -6673,7 +6678,7 @@ static int call_attribute_constructor( /* Set up dummy call frame that makes it look like the attribute was invoked * from where it occurs in the code. */ zend_function dummy_func; - zend_op *opline; + zend_op *op; memset(&dummy_func, 0, sizeof(zend_function)); @@ -6683,15 +6688,16 @@ static int call_attribute_constructor( ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_function), sizeof(zval)), 0, &dummy_func, 0, NULL); - opline = (zend_op*)(call + 1); - memset(opline, 0, sizeof(zend_op)); - opline->opcode = ZEND_DO_FCALL; - opline->lineno = attr->lineno; + op = (zend_op*)(call + 1); + memset(op, 0, sizeof(zend_op)); + op->opcode = ZEND_DO_FCALL; + op->lineno = attr->lineno; - call->opline = opline; + call->opline = op; call->call = NULL; call->return_value = NULL; call->func = (zend_function*)(call->opline + 1); + SAVE_CURRENT_OPLINE(); call->prev_execute_data = EG(current_execute_data); memset(call->func, 0, sizeof(zend_function)); @@ -6702,12 +6708,14 @@ static int call_attribute_constructor( call->func->op_array.filename = filename; EG(current_execute_data) = call; + LOAD_CURRENT_OPLINE(); } zend_call_known_function(ctor, obj, obj->ce, NULL, argc, args, named_params); if (filename) { EG(current_execute_data) = call->prev_execute_data; + LOAD_CURRENT_OPLINE(); zend_vm_stack_free_call_frame(call); } @@ -7093,6 +7101,7 @@ ZEND_METHOD(ReflectionFiber, getTrace) fiber->stack_bottom->prev_execute_data = NULL; if (EG(active_fiber) != fiber) { + SAVE_CURRENT_OPLINE(); // No need to replace current execute data if within the current fiber. EG(current_execute_data) = fiber->execute_data; } @@ -7100,6 +7109,7 @@ ZEND_METHOD(ReflectionFiber, getTrace) zend_fetch_debug_backtrace(return_value, 0, options, 0); EG(current_execute_data) = execute_data; // Restore original execute data. + LOAD_CURRENT_OPLINE(); fiber->stack_bottom->prev_execute_data = prev_execute_data; // Restore prev execute data on fiber stack. } From b4e222fa1887d3f0ec6c1fcce76dec34daa353a1 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 2 Dec 2023 01:52:29 +0100 Subject: [PATCH 08/16] Test benchmark --- .github/workflows/push.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 61c425fe93b4f..8e5bf2f16e678 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -249,7 +249,9 @@ jobs: --with-mysqli=mysqlnd \ --with-openssl \ --with-pdo-sqlite \ - --with-valgrind + --with-valgrind \ + --enable-universal-global-regs \ + CFLAGS="-ffixed-r15 -O2" - name: make run: make -j$(/usr/bin/nproc) >/dev/null - name: make install From a127f60ee804d1ff3707b61df7e2ecb6f3b29644 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 2 Dec 2023 15:14:33 +0100 Subject: [PATCH 09/16] Rename, build system --- .github/workflows/push.yml | 3 +- Zend/Zend.m4 | 58 ++++++++++++++++--- Zend/zend_builtin_functions.c | 2 +- Zend/zend_exceptions.c | 18 +++--- Zend/zend_execute.c | 10 ++-- Zend/zend_execute_API.c | 4 +- Zend/zend_fibers.c | 2 +- Zend/zend_generators.c | 6 +- Zend/zend_globals.h | 2 +- Zend/zend_object_handlers.c | 2 +- Zend/zend_observer.c | 2 +- ...zend_global_regs.h => zend_universal_ip.h} | 2 +- Zend/zend_vm_def.h | 4 +- Zend/zend_vm_execute.h | 48 +++++++-------- Zend/zend_vm_gen.php | 4 +- ext/reflection/php_reflection.c | 2 +- 16 files changed, 104 insertions(+), 65 deletions(-) rename Zend/{zend_global_regs.h => zend_universal_ip.h} (97%) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 8e5bf2f16e678..0de556ff13786 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -250,8 +250,7 @@ jobs: --with-openssl \ --with-pdo-sqlite \ --with-valgrind \ - --enable-universal-global-regs \ - CFLAGS="-ffixed-r15 -O2" + --enable-universal-ip - name: make run: make -j$(/usr/bin/nproc) >/dev/null - name: make install diff --git a/Zend/Zend.m4 b/Zend/Zend.m4 index acb0f8ac3f942..1027b59b16839 100644 --- a/Zend/Zend.m4 +++ b/Zend/Zend.m4 @@ -337,12 +337,6 @@ AC_ARG_ENABLE([gcc-global-regs], [ZEND_GCC_GLOBAL_REGS=$enableval], [ZEND_GCC_GLOBAL_REGS=yes]) -AC_ARG_ENABLE([universal-global-regs], - [AS_HELP_STRING([--enable-universal-global-regs], - [whether to use GCC global register variables universally])], - [ZEND_UNIVERSAL_GLOBAL_REGS=$enableval], - [ZEND_UNIVERSAL_GLOBAL_REGS=no]) - AC_MSG_CHECKING(for global register variables support) if test "$ZEND_GCC_GLOBAL_REGS" != "no"; then AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ @@ -391,14 +385,60 @@ int emu(const opcode_handler_t *ip, void *fp) { ZEND_GCC_GLOBAL_REGS=no ]) fi + if test "$ZEND_GCC_GLOBAL_REGS" = "yes"; then AC_DEFINE([HAVE_GCC_GLOBAL_REGS], 1, [Define if the target system has support for global register variables]) - if test "$ZEND_UNIVERSAL_GLOBAL_REGS" = "yes"; then - AC_DEFINE([ZEND_UNIVERSAL_GLOBAL_REGS], 1, [Define whether to use global register variables universally]) - fi fi AC_MSG_RESULT($ZEND_GCC_GLOBAL_REGS) +AC_ARG_ENABLE([universal-ip], + [AS_HELP_STRING([--enable-universal-ip], + [whether to use a GCC global register variables for IP universally])], + [ZEND_UNIVERSAL_IP=$enableval], + [ZEND_UNIVERSAL_IP=no]) + +if test "$ZEND_UNIVERSAL_IP" = "yes"; then + if test "$ZEND_GCC_GLOBAL_REGS" != "yes"; then + AC_MSG_ERROR(May not enable universal IP without --enable-universal-ip) + fi + + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include + +#if defined(__GNUC__) +# define ZEND_GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) +#else +# define ZEND_GCC_VERSION 0 +#endif +#if defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(i386) +# define ZEND_VM_IP_GLOBAL_REG "edi" +#elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__x86_64__) +# define ZEND_VM_IP_GLOBAL_REG "r15" +#elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__powerpc64__) +# define ZEND_VM_IP_GLOBAL_REG "r29" +#elif defined(__IBMC__) && ZEND_GCC_VERSION >= 4002 && defined(__powerpc64__) +# define ZEND_VM_IP_GLOBAL_REG "r29" +#elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__aarch64__) +# define ZEND_VM_IP_GLOBAL_REG "x28" +#elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__riscv) && __riscv_xlen == 64 +# define ZEND_VM_IP_GLOBAL_REG "x19" +#else +# error "global register variables are not supported" +#endif + +int main(void) { + fprintf(stderr, "%s\n", ZEND_VM_IP_GLOBAL_REG); + return 0; +} + ]])], + [zend_ip_reg=$(./conftest$EXEEXT 2>&1)], + [AC_MSG_ERROR(Unexpected, guarded above)]) + + AC_DEFINE([ZEND_UNIVERSAL_IP], 1, [Define whether to use global register variables universally]) + CFLAGS="$CFLAGS -ffixed-$zend_ip_reg" +fi + dnl Check whether __cpuid_count is available. AC_CACHE_CHECK(whether __cpuid_count is available, ac_cv_cpuid_count_available, [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index c17883ca3cd48..93d922876163b 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -31,7 +31,7 @@ #include "zend_generators.h" #include "zend_builtin_functions_arginfo.h" #include "zend_smart_str.h" -#include "zend_global_regs.h" +#include "zend_universal_ip.h" /* }}} */ diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 7a27d3f674755..b5d1f52e826e9 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -29,7 +29,7 @@ #include "zend_smart_str.h" #include "zend_exceptions_arginfo.h" #include "zend_observer.h" -#include "zend_global_regs.h" +#include "zend_universal_ip.h" ZEND_API zend_class_entry *zend_ce_throwable; ZEND_API zend_class_entry *zend_ce_exception; @@ -165,14 +165,14 @@ static zend_always_inline bool is_handle_exception_set(void) { return !execute_data || !execute_data->func || !ZEND_USER_CODE(execute_data->func->common.type) -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP || opline->opcode == ZEND_HANDLE_EXCEPTION; #else || execute_data->opline->opcode == ZEND_HANDLE_EXCEPTION; #endif } -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP static void zend_copy_exception_consts(uint32_t opnum) { const zend_op *orig_op = &EG(opline_before_exception)[opnum]; @@ -214,7 +214,7 @@ static void zend_copy_exception_ops(void) ZEND_API void zend_rethrow_exception(zend_execute_data *execute_data) { -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP if (opline->opcode != ZEND_HANDLE_EXCEPTION) { EG(opline_before_exception) = opline; } @@ -224,7 +224,7 @@ ZEND_API void zend_rethrow_exception(zend_execute_data *execute_data) } #endif EX(opline) = EG(exception_op); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP opline = EG(exception_op); zend_copy_exception_ops(); #endif @@ -286,13 +286,13 @@ ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception) /* /* no need to rethrow the exception */ return; } -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EG(opline_before_exception) = opline; #else EG(opline_before_exception) = EG(current_execute_data)->opline; #endif EG(current_execute_data)->opline = EG(exception_op); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP opline = EG(exception_op); zend_copy_exception_ops(); #endif @@ -1091,7 +1091,7 @@ ZEND_API ZEND_COLD void zend_throw_unwind_exit(void) { ZEND_ASSERT(!EG(exception)); EG(exception) = zend_create_unwind_exit(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EG(opline_before_exception) = opline; #else EG(opline_before_exception) = EG(current_execute_data)->opline; @@ -1103,7 +1103,7 @@ ZEND_API ZEND_COLD void zend_throw_graceful_exit(void) { ZEND_ASSERT(!EG(exception)); EG(exception) = zend_create_graceful_exit(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EG(opline_before_exception) = opline; #else EG(opline_before_exception) = EG(current_execute_data)->opline; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 8f1662d3dfea5..25f0cc90e3ede 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -44,7 +44,7 @@ #include "zend_system_id.h" #include "zend_call_stack.h" #include "Optimizer/zend_func_info.h" -#include "zend_global_regs.h" +#include "zend_universal_ip.h" /* Virtual current working directory support */ #include "zend_virtual_cwd.h" @@ -97,7 +97,7 @@ # define OPLINE_CC , OPLINE_C #endif -#if defined(ZEND_VM_IP_GLOBAL_REG) && !defined(ZEND_UNIVERSAL_GLOBAL_REGS) +#if defined(ZEND_VM_IP_GLOBAL_REG) && !defined(ZEND_UNIVERSAL_IP) # pragma GCC diagnostic ignored "-Wvolatile-register-var" register const zend_op* volatile opline __asm__(ZEND_VM_IP_GLOBAL_REG); # pragma GCC diagnostic warning "-Wvolatile-register-var" @@ -1680,7 +1680,7 @@ static zend_never_inline zend_long zend_check_string_offset(zval *dim, int type ZEND_API ZEND_COLD void zend_wrong_string_offset_error(void) { const char *msg = NULL; -#ifndef ZEND_UNIVERSAL_GLOBAL_REGS +#ifndef ZEND_UNIVERSAL_IP const zend_execute_data *execute_data = EG(current_execute_data); const zend_op *opline = execute_data->opline; #endif @@ -5141,7 +5141,7 @@ static zend_execute_data *start_fake_frame(zend_execute_data *call, const zend_o call->prev_execute_data = EG(current_execute_data); call->opline = op; EG(current_execute_data) = call; -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP if (call->prev_execute_data) { call->prev_execute_data->opline = opline; } @@ -5154,7 +5154,7 @@ static void end_fake_frame(zend_execute_data *call, zend_execute_data *old_prev_ zend_execute_data *prev_execute_data = call->prev_execute_data; EG(current_execute_data) = prev_execute_data; call->prev_execute_data = old_prev_execute_data; -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP if (prev_execute_data) { opline = prev_execute_data->opline; } diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index bbd41938400bd..06999961d948d 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -38,7 +38,7 @@ #include "zend_inheritance.h" #include "zend_observer.h" #include "zend_call_stack.h" -#include "zend_global_regs.h" +#include "zend_universal_ip.h" #ifdef HAVE_SYS_TIME_H #include #endif @@ -647,7 +647,7 @@ ZEND_API uint32_t zend_get_executed_lineno(void) /* {{{ */ ex = ex->prev_execute_data; } if (ex) { -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP const zend_op *op = ex == EG(current_execute_data) ? opline : ex->opline; #else const zend_op *op = ex->opline; diff --git a/Zend/zend_fibers.c b/Zend/zend_fibers.c index b78a152d9a316..6b515c5116a3f 100644 --- a/Zend/zend_fibers.c +++ b/Zend/zend_fibers.c @@ -27,7 +27,7 @@ #include "zend_mmap.h" #include "zend_compile.h" #include "zend_closures.h" -#include "zend_global_regs.h" +#include "zend_universal_ip.h" #include "zend_fibers.h" #include "zend_fibers_arginfo.h" diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index f2127547f6f11..2669f68912379 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -25,7 +25,7 @@ #include "zend_closures.h" #include "zend_generators_arginfo.h" #include "zend_observer.h" -#include "zend_global_regs.h" +#include "zend_universal_ip.h" ZEND_API zend_class_entry *zend_ce_generator; ZEND_API zend_class_entry *zend_ce_ClosedGeneratorException; @@ -569,7 +569,7 @@ ZEND_API zend_generator *zend_generator_update_current(zend_generator *generator /* Throw the exception in the context of the generator */ zend_execute_data *original_execute_data = EG(current_execute_data); EG(current_execute_data) = new_root->execute_data; -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP original_execute_data->opline = opline; opline = EG(current_execute_data)->opline; #endif @@ -586,7 +586,7 @@ ZEND_API zend_generator *zend_generator_update_current(zend_generator *generator zend_throw_exception(zend_ce_ClosedGeneratorException, "Generator yielded from aborted, no return value available", 0); EG(current_execute_data) = original_execute_data; -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP opline = EG(current_execute_data)->opline; #endif diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index b95eb168b840f..4b2067f725458 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -246,7 +246,7 @@ struct _zend_executor_globals { zend_object *exception, *prev_exception; const zend_op *opline_before_exception; zend_op exception_op[3]; -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP /* Consts copied over from opline during exceptions. Allows the throwing handler to access * constants even after the opline register has been adjusted. */ zval exception_consts[4]; diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 59ff5c053763d..09620f891402c 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -30,7 +30,7 @@ #include "zend_closures.h" #include "zend_compile.h" #include "zend_hash.h" -#include "zend_global_regs.h" +#include "zend_universal_ip.h" #define DEBUG_OBJECT_HANDLERS 0 diff --git a/Zend/zend_observer.c b/Zend/zend_observer.c index 18ad2c6188ad5..f05fd773cf84f 100644 --- a/Zend/zend_observer.c +++ b/Zend/zend_observer.c @@ -22,7 +22,7 @@ #include "zend_extensions.h" #include "zend_llist.h" #include "zend_vm.h" -#include "zend_global_regs.h" +#include "zend_universal_ip.h" #define ZEND_OBSERVER_DATA(function) \ ZEND_OP_ARRAY_EXTENSION((&(function)->common), zend_observer_fcall_op_array_extension) diff --git a/Zend/zend_global_regs.h b/Zend/zend_universal_ip.h similarity index 97% rename from Zend/zend_global_regs.h rename to Zend/zend_universal_ip.h index bce6d8c7cb5db..4fd0747c22fb5 100644 --- a/Zend/zend_global_regs.h +++ b/Zend/zend_universal_ip.h @@ -40,7 +40,7 @@ # endif #endif -#if defined(ZEND_UNIVERSAL_GLOBAL_REGS) && defined(ZEND_VM_IP_GLOBAL_REG) +#if defined(ZEND_UNIVERSAL_IP) && defined(ZEND_VM_IP_GLOBAL_REG) # pragma GCC diagnostic ignored "-Wvolatile-register-var" register const zend_op* volatile opline __asm__(ZEND_VM_IP_GLOBAL_REG); # pragma GCC diagnostic warning "-Wvolatile-register-var" diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index f5a166b42a03d..339df545c9a77 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -8346,7 +8346,7 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMPVAR|CV|UNUSED /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -8455,7 +8455,7 @@ ZEND_VM_C_LABEL(yield_from_try_again): /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index bfb72d45ac03a..7b73a2060d312 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -393,7 +393,7 @@ static const void *zend_vm_get_opcode_handler_func(uint8_t opcode, const zend_op typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS); #define DCL_OPLINE -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP # define OPLINE opline # define USE_OPLINE # define LOAD_OPLINE() opline = EX(opline) @@ -5621,7 +5621,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_CONST_HANDLER( /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -7784,7 +7784,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CONST_HANDLER /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -10069,7 +10069,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMPVAR_HANDLE /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -10921,7 +10921,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLE /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -12459,7 +12459,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZE /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -15010,7 +15010,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_TMPVAR_HANDLER /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -20332,7 +20332,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(Z /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -20780,7 +20780,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_TMPVAR_HANDLER( /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -21243,7 +21243,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER( /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -21650,7 +21650,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -25617,7 +25617,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CONST_HANDLER(Z /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -28073,7 +28073,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_TMPVAR_HANDLER( /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -30031,7 +30031,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER( /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -32464,7 +32464,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -34659,7 +34659,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CONST_HANDLE /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -36546,7 +36546,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_TMPVAR_HANDL /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -37090,7 +37090,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDL /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -39045,7 +39045,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(Z /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -40407,7 +40407,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_CV_HANDLER(ZEN /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -44394,7 +44394,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZE /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -47996,7 +47996,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CV_TMPVAR_HANDLER(Z /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -49857,7 +49857,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(Z /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif @@ -53485,7 +53485,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CV_HANDLER(ZEND_ /* The GOTO VM uses a local opline variable. We need to set the opline * variable in execute_data so we don't resume at an old position. */ SAVE_OPLINE(); -#ifdef ZEND_UNIVERSAL_GLOBAL_REGS +#ifdef ZEND_UNIVERSAL_IP EX(opline) = opline; #endif diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index f56302a9f762e..a2053fb472b5c 100755 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -1900,7 +1900,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);\n"); out($f,"\n"); out($f,"#define DCL_OPLINE\n"); - out($f,"#ifdef ZEND_UNIVERSAL_GLOBAL_REGS\n"); + out($f,"#ifdef ZEND_UNIVERSAL_IP\n"); out($f,"# define OPLINE opline\n"); out($f,"# define USE_OPLINE\n"); out($f,"# define LOAD_OPLINE() opline = EX(opline)\n"); @@ -2066,7 +2066,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"#endif\n"); out($f,$m[1]."} vm_stack_data;\n"); out($f,"#endif\n"); - // out($f,"#ifdef ZEND_UNIVERSAL_GLOBAL_REGS\n"); + // out($f,"#ifdef ZEND_UNIVERSAL_IP\n"); // out($f,$m[1]."if (EG(current_execute_data) && EG(current_execute_data) != ex && opline) {\n"); // out($f,$m[1]."\tEG(current_execute_data)->opline = opline;\n"); // out($f,$m[1]."}\n"); diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index dec43064ccc6e..1fc0cdb10529a 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -45,7 +45,7 @@ #include "zend_smart_str.h" #include "zend_enum.h" #include "zend_fibers.h" -#include "zend_global_regs.h" +#include "zend_universal_ip.h" #define REFLECTION_ATTRIBUTE_IS_INSTANCEOF (1 << 1) From 4d1fa0fb072d5967aa5ff49e1bbb05943f119959 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 2 Dec 2023 15:45:19 +0100 Subject: [PATCH 10/16] Renaming --- Zend/tests/bug73337.phpt | 8 +----- .../typed_properties_046.phpt | 2 +- Zend/zend_builtin_functions.c | 1 - Zend/zend_exceptions.c | 16 ++++++------ Zend/zend_execute.c | 26 ++++++++++++++++++- Zend/zend_execute_API.c | 2 +- Zend/zend_generators.c | 10 +++---- Zend/zend_universal_ip.h | 8 +++--- ext/reflection/php_reflection.c | 12 ++++----- 9 files changed, 49 insertions(+), 36 deletions(-) diff --git a/Zend/tests/bug73337.phpt b/Zend/tests/bug73337.phpt index 2ee21ed38569b..a338aa605c781 100644 --- a/Zend/tests/bug73337.phpt +++ b/Zend/tests/bug73337.phpt @@ -2,13 +2,7 @@ Bug #73337 (try/catch not working with two exceptions inside a same operation) --FILE-- --EXPECT-- diff --git a/Zend/tests/type_declarations/typed_properties_046.phpt b/Zend/tests/type_declarations/typed_properties_046.phpt index 2618520857825..2048455fe5f12 100644 --- a/Zend/tests/type_declarations/typed_properties_046.phpt +++ b/Zend/tests/type_declarations/typed_properties_046.phpt @@ -16,7 +16,7 @@ function bar() { for ($i = 0; $i < 5; $i++) { try { - foo()->{'bbb'} = str_repeat("a", 3); + foo()->{bar()} = str_repeat("a", 3); } catch (Throwable $e) { echo $e->getMessage() . "\n"; } diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 93d922876163b..5ca335170a216 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -31,7 +31,6 @@ #include "zend_generators.h" #include "zend_builtin_functions_arginfo.h" #include "zend_smart_str.h" -#include "zend_universal_ip.h" /* }}} */ diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index b5d1f52e826e9..75bbdca3e6ffd 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -166,7 +166,7 @@ static zend_always_inline bool is_handle_exception_set(void) { || !execute_data->func || !ZEND_USER_CODE(execute_data->func->common.type) #ifdef ZEND_UNIVERSAL_IP - || opline->opcode == ZEND_HANDLE_EXCEPTION; + || zend_universal_ip->opcode == ZEND_HANDLE_EXCEPTION; #else || execute_data->opline->opcode == ZEND_HANDLE_EXCEPTION; #endif @@ -215,8 +215,8 @@ static void zend_copy_exception_ops(void) ZEND_API void zend_rethrow_exception(zend_execute_data *execute_data) { #ifdef ZEND_UNIVERSAL_IP - if (opline->opcode != ZEND_HANDLE_EXCEPTION) { - EG(opline_before_exception) = opline; + if (zend_universal_ip->opcode != ZEND_HANDLE_EXCEPTION) { + EG(opline_before_exception) = zend_universal_ip; } #else if (EX(opline)->opcode != ZEND_HANDLE_EXCEPTION) { @@ -225,7 +225,7 @@ ZEND_API void zend_rethrow_exception(zend_execute_data *execute_data) #endif EX(opline) = EG(exception_op); #ifdef ZEND_UNIVERSAL_IP - opline = EG(exception_op); + zend_universal_ip = EG(exception_op); zend_copy_exception_ops(); #endif } @@ -287,13 +287,13 @@ ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception) /* return; } #ifdef ZEND_UNIVERSAL_IP - EG(opline_before_exception) = opline; + EG(opline_before_exception) = zend_universal_ip; #else EG(opline_before_exception) = EG(current_execute_data)->opline; #endif EG(current_execute_data)->opline = EG(exception_op); #ifdef ZEND_UNIVERSAL_IP - opline = EG(exception_op); + zend_universal_ip = EG(exception_op); zend_copy_exception_ops(); #endif } @@ -1092,7 +1092,7 @@ ZEND_API ZEND_COLD void zend_throw_unwind_exit(void) ZEND_ASSERT(!EG(exception)); EG(exception) = zend_create_unwind_exit(); #ifdef ZEND_UNIVERSAL_IP - EG(opline_before_exception) = opline; + EG(opline_before_exception) = zend_universal_ip; #else EG(opline_before_exception) = EG(current_execute_data)->opline; #endif @@ -1104,7 +1104,7 @@ ZEND_API ZEND_COLD void zend_throw_graceful_exit(void) ZEND_ASSERT(!EG(exception)); EG(exception) = zend_create_graceful_exit(); #ifdef ZEND_UNIVERSAL_IP - EG(opline_before_exception) = opline; + EG(opline_before_exception) = zend_universal_ip; #else EG(opline_before_exception) = EG(current_execute_data)->opline; #endif diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 25f0cc90e3ede..f8b94043b052b 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -44,7 +44,6 @@ #include "zend_system_id.h" #include "zend_call_stack.h" #include "Optimizer/zend_func_info.h" -#include "zend_universal_ip.h" /* Virtual current working directory support */ #include "zend_virtual_cwd.h" @@ -65,12 +64,37 @@ # endif #endif +#if defined(HAVE_GCC_GLOBAL_REGS) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)) +# if defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(i386) +# define ZEND_VM_IP_GLOBAL_REG "%edi" +# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__x86_64__) +# define ZEND_VM_IP_GLOBAL_REG "%r15" +# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__powerpc64__) +# define ZEND_VM_IP_GLOBAL_REG "r15" +# elif defined(__IBMC__) && ZEND_GCC_VERSION >= 4002 && defined(__powerpc64__) +# define ZEND_VM_IP_GLOBAL_REG "r15" +# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__aarch64__) +# define ZEND_VM_IP_GLOBAL_REG "x28" +# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__riscv) && __riscv_xlen == 64 +# define ZEND_VM_IP_GLOBAL_REG "x19" +# endif +#endif + #if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)) # pragma GCC diagnostic ignored "-Wvolatile-register-var" register zend_execute_data* volatile execute_data __asm__(ZEND_VM_FP_GLOBAL_REG); # pragma GCC diagnostic warning "-Wvolatile-register-var" #endif +#if defined(ZEND_UNIVERSAL_IP) && defined(ZEND_VM_IP_GLOBAL_REG) +# pragma GCC diagnostic ignored "-Wvolatile-register-var" +register const zend_op* volatile opline __asm__(ZEND_VM_IP_GLOBAL_REG); +# pragma GCC diagnostic warning "-Wvolatile-register-var" +# define ZEND_CURRENT_OPLINE opline +#else +# define ZEND_CURRENT_OPLINE EX(opline) +#endif + #if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)) # define EXECUTE_DATA_D void # define EXECUTE_DATA_C diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 06999961d948d..8ed4e655ff505 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -648,7 +648,7 @@ ZEND_API uint32_t zend_get_executed_lineno(void) /* {{{ */ } if (ex) { #ifdef ZEND_UNIVERSAL_IP - const zend_op *op = ex == EG(current_execute_data) ? opline : ex->opline; + const zend_op *op = ex == EG(current_execute_data) ? zend_universal_ip : ex->opline; #else const zend_op *op = ex->opline; #endif diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 2669f68912379..e972c077babe2 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -568,11 +568,9 @@ ZEND_API zend_generator *zend_generator_update_current(zend_generator *generator if (Z_ISUNDEF(new_root_parent->retval)) { /* Throw the exception in the context of the generator */ zend_execute_data *original_execute_data = EG(current_execute_data); + SAVE_CURRENT_OPLINE(); EG(current_execute_data) = new_root->execute_data; -#ifdef ZEND_UNIVERSAL_IP - original_execute_data->opline = opline; - opline = EG(current_execute_data)->opline; -#endif + LOAD_CURRENT_OPLINE(); if (new_root == generator) { new_root->execute_data->prev_execute_data = original_execute_data; @@ -586,9 +584,7 @@ ZEND_API zend_generator *zend_generator_update_current(zend_generator *generator zend_throw_exception(zend_ce_ClosedGeneratorException, "Generator yielded from aborted, no return value available", 0); EG(current_execute_data) = original_execute_data; -#ifdef ZEND_UNIVERSAL_IP - opline = EG(current_execute_data)->opline; -#endif + LOAD_CURRENT_OPLINE(); if (!((old_root ? old_root : generator)->flags & ZEND_GENERATOR_CURRENTLY_RUNNING)) { new_root->node.parent = NULL; diff --git a/Zend/zend_universal_ip.h b/Zend/zend_universal_ip.h index 4fd0747c22fb5..61e8e28eaca37 100644 --- a/Zend/zend_universal_ip.h +++ b/Zend/zend_universal_ip.h @@ -42,19 +42,19 @@ #if defined(ZEND_UNIVERSAL_IP) && defined(ZEND_VM_IP_GLOBAL_REG) # pragma GCC diagnostic ignored "-Wvolatile-register-var" -register const zend_op* volatile opline __asm__(ZEND_VM_IP_GLOBAL_REG); +register const zend_op* volatile zend_universal_ip __asm__(ZEND_VM_IP_GLOBAL_REG); # pragma GCC diagnostic warning "-Wvolatile-register-var" -# define ZEND_CURRENT_OPLINE opline +# define ZEND_CURRENT_OPLINE zend_universal_ip # define SAVE_CURRENT_OPLINE() \ do { \ if (EG(current_execute_data)) { \ - EG(current_execute_data)->opline = opline; \ + EG(current_execute_data)->opline = zend_universal_ip; \ } \ } while (0) # define LOAD_CURRENT_OPLINE() \ do { \ if (EG(current_execute_data)) { \ - opline = EG(current_execute_data)->opline; \ + zend_universal_ip = EG(current_execute_data)->opline; \ } \ } while (0) #else diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 1fc0cdb10529a..c27592663853d 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -6678,7 +6678,7 @@ static int call_attribute_constructor( /* Set up dummy call frame that makes it look like the attribute was invoked * from where it occurs in the code. */ zend_function dummy_func; - zend_op *op; + zend_op *opline; memset(&dummy_func, 0, sizeof(zend_function)); @@ -6688,12 +6688,12 @@ static int call_attribute_constructor( ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_function), sizeof(zval)), 0, &dummy_func, 0, NULL); - op = (zend_op*)(call + 1); - memset(op, 0, sizeof(zend_op)); - op->opcode = ZEND_DO_FCALL; - op->lineno = attr->lineno; + opline = (zend_op*)(call + 1); + memset(opline, 0, sizeof(zend_op)); + opline->opcode = ZEND_DO_FCALL; + opline->lineno = attr->lineno; - call->opline = op; + call->opline = opline; call->call = NULL; call->return_value = NULL; call->func = (zend_function*)(call->opline + 1); From 2d14c7e64a6fc9f5a37321b92f28d6ccfc74cc77 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 2 Dec 2023 15:47:55 +0100 Subject: [PATCH 11/16] Test linux with universal ip --- .github/workflows/push.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 0de556ff13786..5846582201ae2 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -123,6 +123,7 @@ jobs: configurationParameters: >- --${{ matrix.debug && 'enable' || 'disable' }}-debug --${{ matrix.zts && 'enable' || 'disable' }}-zts + --enable-universal-ip ${{ matrix.asan && 'CFLAGS="-fsanitize=undefined,address -DZEND_TRACK_ARENA_ALLOC" LDFLAGS="-fsanitize=undefined,address" CC=clang-16 CXX=clang++-16 --disable-opcache-jit' || '' }} skipSlow: ${{ matrix.asan }} - name: make From 77f62f9d12820099c4f60ddb1d370654a4b503ed Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 2 Dec 2023 15:59:30 +0100 Subject: [PATCH 12/16] Reduce diff --- Zend/zend_execute.c | 39 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index f8b94043b052b..1bb654ab91c6a 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -51,31 +51,21 @@ #ifdef HAVE_GCC_GLOBAL_REGS # if defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(i386) # define ZEND_VM_FP_GLOBAL_REG "%esi" +# define ZEND_VM_IP_GLOBAL_REG "%edi" # elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__x86_64__) # define ZEND_VM_FP_GLOBAL_REG "%r14" +# define ZEND_VM_IP_GLOBAL_REG "%r15" # elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__powerpc64__) # define ZEND_VM_FP_GLOBAL_REG "r14" +# define ZEND_VM_IP_GLOBAL_REG "r15" # elif defined(__IBMC__) && ZEND_GCC_VERSION >= 4002 && defined(__powerpc64__) # define ZEND_VM_FP_GLOBAL_REG "r14" +# define ZEND_VM_IP_GLOBAL_REG "r15" # elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__aarch64__) # define ZEND_VM_FP_GLOBAL_REG "x27" +# define ZEND_VM_IP_GLOBAL_REG "x28" #elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__riscv) && __riscv_xlen == 64 # define ZEND_VM_FP_GLOBAL_REG "x18" -# endif -#endif - -#if defined(HAVE_GCC_GLOBAL_REGS) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)) -# if defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(i386) -# define ZEND_VM_IP_GLOBAL_REG "%edi" -# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__x86_64__) -# define ZEND_VM_IP_GLOBAL_REG "%r15" -# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__powerpc64__) -# define ZEND_VM_IP_GLOBAL_REG "r15" -# elif defined(__IBMC__) && ZEND_GCC_VERSION >= 4002 && defined(__powerpc64__) -# define ZEND_VM_IP_GLOBAL_REG "r15" -# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__aarch64__) -# define ZEND_VM_IP_GLOBAL_REG "x28" -# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__riscv) && __riscv_xlen == 64 # define ZEND_VM_IP_GLOBAL_REG "x19" # endif #endif @@ -86,15 +76,6 @@ # pragma GCC diagnostic warning "-Wvolatile-register-var" #endif -#if defined(ZEND_UNIVERSAL_IP) && defined(ZEND_VM_IP_GLOBAL_REG) -# pragma GCC diagnostic ignored "-Wvolatile-register-var" -register const zend_op* volatile opline __asm__(ZEND_VM_IP_GLOBAL_REG); -# pragma GCC diagnostic warning "-Wvolatile-register-var" -# define ZEND_CURRENT_OPLINE opline -#else -# define ZEND_CURRENT_OPLINE EX(opline) -#endif - #if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)) # define EXECUTE_DATA_D void # define EXECUTE_DATA_C @@ -121,12 +102,18 @@ register const zend_op* volatile opline __asm__(ZEND_VM_IP_GLOBAL_REG); # define OPLINE_CC , OPLINE_C #endif -#if defined(ZEND_VM_IP_GLOBAL_REG) && !defined(ZEND_UNIVERSAL_IP) +#if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)) # pragma GCC diagnostic ignored "-Wvolatile-register-var" -register const zend_op* volatile opline __asm__(ZEND_VM_IP_GLOBAL_REG); + register const zend_op* volatile opline __asm__(ZEND_VM_IP_GLOBAL_REG); # pragma GCC diagnostic warning "-Wvolatile-register-var" #endif +#ifdef ZEND_UNIVERSAL_IP +# define ZEND_CURRENT_OPLINE opline +#else +# define ZEND_CURRENT_OPLINE EX(opline) +#endif + #define _CONST_CODE 0 #define _TMP_CODE 1 #define _VAR_CODE 2 From e98fe542fcbc949fe988133160e20348f0ac91d3 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 2 Dec 2023 16:12:27 +0100 Subject: [PATCH 13/16] Simplify further --- Zend/zend_execute.c | 13 +++++++------ Zend/zend_execute.h | 1 - Zend/zend_execute_API.c | 14 ++++++-------- Zend/zend_fibers.c | 1 - Zend/zend_observer.c | 1 - Zend/zend_vm_def.h | 20 +++++--------------- Zend/zend_vm_execute.h | 40 ++++++++++------------------------------ 7 files changed, 28 insertions(+), 62 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 1bb654ab91c6a..0c4303dbc5ad4 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -110,8 +110,15 @@ #ifdef ZEND_UNIVERSAL_IP # define ZEND_CURRENT_OPLINE opline +# define LOAD_CURRENT_OPLINE() \ + do { \ + if (EG(current_execute_data)) { \ + opline = EG(current_execute_data)->opline; \ + } \ + } while (0) #else # define ZEND_CURRENT_OPLINE EX(opline) +# define LOAD_CURRENT_OPLINE() #endif #define _CONST_CODE 0 @@ -189,12 +196,6 @@ ZEND_API const zend_internal_function zend_pass_function = { (((size) + ZEND_VM_STACK_HEADER_SLOTS * sizeof(zval) \ + ((page_size) - 1)) & ~((page_size) - 1)) -void init_executor_ex(void) -{ - opline = NULL; - execute_data = NULL; -} - ZEND_API void zend_vm_stack_init(void) { EG(vm_stack_page_size) = ZEND_VM_STACK_PAGE_SIZE; diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 417a0f212d819..d0c18040ab46d 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -37,7 +37,6 @@ ZEND_API extern void (*zend_execute_internal)(zend_execute_data *execute_data, z ZEND_API extern zend_class_entry *(*zend_autoload)(zend_string *name, zend_string *lc_name); void init_executor(void); -void init_executor_ex(void); void shutdown_executor(void); void shutdown_destructors(void); ZEND_API void zend_shutdown_executor_values(bool fast_shutdown); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 8ed4e655ff505..c654e0bc1a1a4 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -133,8 +133,6 @@ void init_executor(void) /* {{{ */ { zend_init_fpu(); - init_executor_ex(); - ZVAL_NULL(&EG(uninitialized_zval)); ZVAL_ERROR(&EG(error_zval)); /* destroys stack frame, therefore makes core dumps worthless */ @@ -648,20 +646,20 @@ ZEND_API uint32_t zend_get_executed_lineno(void) /* {{{ */ } if (ex) { #ifdef ZEND_UNIVERSAL_IP - const zend_op *op = ex == EG(current_execute_data) ? zend_universal_ip : ex->opline; + const zend_op *opline = ex == EG(current_execute_data) ? zend_universal_ip : ex->opline; #else - const zend_op *op = ex->opline; + const zend_op *opline = ex->opline; #endif - if (!op) { + if (!opline) { /* Missing SAVE_OPLINE()? Falling back to first line of function */ return ex->func->op_array.opcodes[0].lineno; } - if (EG(exception) && op->opcode == ZEND_HANDLE_EXCEPTION && - op->lineno == 0 && EG(opline_before_exception)) { + if (EG(exception) && opline->opcode == ZEND_HANDLE_EXCEPTION && + opline->lineno == 0 && EG(opline_before_exception)) { return EG(opline_before_exception)->lineno; } - return op->lineno; + return opline->lineno; } else { return 0; } diff --git a/Zend/zend_fibers.c b/Zend/zend_fibers.c index 6b515c5116a3f..e669ab6b53382 100644 --- a/Zend/zend_fibers.c +++ b/Zend/zend_fibers.c @@ -27,7 +27,6 @@ #include "zend_mmap.h" #include "zend_compile.h" #include "zend_closures.h" -#include "zend_universal_ip.h" #include "zend_fibers.h" #include "zend_fibers_arginfo.h" diff --git a/Zend/zend_observer.c b/Zend/zend_observer.c index f05fd773cf84f..2cb4db914758a 100644 --- a/Zend/zend_observer.c +++ b/Zend/zend_observer.c @@ -22,7 +22,6 @@ #include "zend_extensions.h" #include "zend_llist.h" #include "zend_vm.h" -#include "zend_universal_ip.h" #define ZEND_OBSERVER_DATA(function) \ ZEND_OP_ARRAY_EXTENSION((&(function)->common), zend_observer_fcall_op_array_extension) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 339df545c9a77..c66d5c4ff3bbc 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2857,9 +2857,7 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED|ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) == 0)) { EG(current_execute_data) = EX(prev_execute_data); - if (EG(current_execute_data)) { - opline = EG(current_execute_data)->opline; - } + LOAD_CURRENT_OPLINE(); i_free_compiled_variables(execute_data); #ifdef ZEND_PREFER_RELOAD @@ -2882,9 +2880,7 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) ZEND_VM_LEAVE(); } else if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP)) == 0)) { EG(current_execute_data) = EX(prev_execute_data); - if (EG(current_execute_data)) { - opline = EG(current_execute_data)->opline; - } + LOAD_CURRENT_OPLINE(); i_free_compiled_variables(execute_data); #ifdef ZEND_PREFER_RELOAD @@ -2929,9 +2925,7 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) efree_size(EX(func), sizeof(zend_op_array)); old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); - if (EG(current_execute_data)) { - opline = EG(current_execute_data)->opline; - } + LOAD_CURRENT_OPLINE(); zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); if (call_info & ZEND_CALL_NEEDS_REATTACH) { @@ -2951,9 +2945,7 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) } else { if (EXPECTED((call_info & ZEND_CALL_CODE) == 0)) { EG(current_execute_data) = EX(prev_execute_data); - if (EG(current_execute_data)) { - opline = EG(current_execute_data)->opline; - } + LOAD_CURRENT_OPLINE(); i_free_compiled_variables(execute_data); #ifdef ZEND_PREFER_RELOAD call_info = EX_CALL_INFO(); @@ -2995,9 +2987,7 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) } } EG(current_execute_data) = EX(prev_execute_data); - if (EG(current_execute_data)) { - opline = EG(current_execute_data)->opline; - } + LOAD_CURRENT_OPLINE(); ZEND_VM_RETURN(); } } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 7b73a2060d312..e95e3c810d097 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1121,9 +1121,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED|ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) == 0)) { EG(current_execute_data) = EX(prev_execute_data); - if (EG(current_execute_data)) { - opline = EG(current_execute_data)->opline; - } + LOAD_CURRENT_OPLINE(); i_free_compiled_variables(execute_data); #ifdef ZEND_PREFER_RELOAD @@ -1146,9 +1144,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper ZEND_VM_LEAVE(); } else if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP)) == 0)) { EG(current_execute_data) = EX(prev_execute_data); - if (EG(current_execute_data)) { - opline = EG(current_execute_data)->opline; - } + LOAD_CURRENT_OPLINE(); i_free_compiled_variables(execute_data); #ifdef ZEND_PREFER_RELOAD @@ -1193,9 +1189,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper efree_size(EX(func), sizeof(zend_op_array)); old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); - if (EG(current_execute_data)) { - opline = EG(current_execute_data)->opline; - } + LOAD_CURRENT_OPLINE(); zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); if (call_info & ZEND_CALL_NEEDS_REATTACH) { @@ -1215,9 +1209,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper } else { if (EXPECTED((call_info & ZEND_CALL_CODE) == 0)) { EG(current_execute_data) = EX(prev_execute_data); - if (EG(current_execute_data)) { - opline = EG(current_execute_data)->opline; - } + LOAD_CURRENT_OPLINE(); i_free_compiled_variables(execute_data); #ifdef ZEND_PREFER_RELOAD call_info = EX_CALL_INFO(); @@ -1259,9 +1251,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper } } EG(current_execute_data) = EX(prev_execute_data); - if (EG(current_execute_data)) { - opline = EG(current_execute_data)->opline; - } + LOAD_CURRENT_OPLINE(); ZEND_VM_RETURN(); } } @@ -57171,9 +57161,7 @@ ZEND_API void execute_ex(zend_execute_data *ex) if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED|ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) == 0)) { EG(current_execute_data) = EX(prev_execute_data); - if (EG(current_execute_data)) { - opline = EG(current_execute_data)->opline; - } + LOAD_CURRENT_OPLINE(); i_free_compiled_variables(execute_data); #ifdef ZEND_PREFER_RELOAD @@ -57196,9 +57184,7 @@ ZEND_API void execute_ex(zend_execute_data *ex) ZEND_VM_LEAVE(); } else if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP)) == 0)) { EG(current_execute_data) = EX(prev_execute_data); - if (EG(current_execute_data)) { - opline = EG(current_execute_data)->opline; - } + LOAD_CURRENT_OPLINE(); i_free_compiled_variables(execute_data); #ifdef ZEND_PREFER_RELOAD @@ -57243,9 +57229,7 @@ ZEND_API void execute_ex(zend_execute_data *ex) efree_size(EX(func), sizeof(zend_op_array)); old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); - if (EG(current_execute_data)) { - opline = EG(current_execute_data)->opline; - } + LOAD_CURRENT_OPLINE(); zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); if (call_info & ZEND_CALL_NEEDS_REATTACH) { @@ -57265,9 +57249,7 @@ ZEND_API void execute_ex(zend_execute_data *ex) } else { if (EXPECTED((call_info & ZEND_CALL_CODE) == 0)) { EG(current_execute_data) = EX(prev_execute_data); - if (EG(current_execute_data)) { - opline = EG(current_execute_data)->opline; - } + LOAD_CURRENT_OPLINE(); i_free_compiled_variables(execute_data); #ifdef ZEND_PREFER_RELOAD call_info = EX_CALL_INFO(); @@ -57309,9 +57291,7 @@ ZEND_API void execute_ex(zend_execute_data *ex) } } EG(current_execute_data) = EX(prev_execute_data); - if (EG(current_execute_data)) { - opline = EG(current_execute_data)->opline; - } + LOAD_CURRENT_OPLINE(); ZEND_VM_RETURN(); } } From 67ac7b881871f4099759b4fb1a0e7ed81eea85a8 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 2 Dec 2023 17:03:06 +0100 Subject: [PATCH 14/16] Clean gen.php --- Zend/zend_vm_execute.h | 13 ++----------- Zend/zend_vm_gen.php | 18 ++---------------- 2 files changed, 4 insertions(+), 27 deletions(-) diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index e95e3c810d097..0f2a74e9c222b 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -65443,7 +65443,6 @@ void zend_vm_init(void) #if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) zend_opcode_handler_funcs = labels; zend_spec_handlers = specs; - execute_data = NULL; execute_ex(NULL); #else zend_opcode_handlers = labels; @@ -65900,21 +65899,13 @@ ZEND_API int ZEND_FASTCALL zend_vm_call_opcode_handler(zend_execute_data* ex) if (EXPECTED(opline)) { #endif ret = execute_data != ex ? (int)(execute_data->prev_execute_data != ex) + 1 : 0; -#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG) - EX(opline) = opline; -#else - SAVE_OPLINE(); -#endif + SAVE_OPLINE_EX(); } else { ret = -1; } #else ret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); -#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG) - EX(opline) = opline; -#else - SAVE_OPLINE(); -#endif + SAVE_OPLINE_EX(); #endif #ifdef ZEND_VM_FP_GLOBAL_REG execute_data = orig_execute_data; diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index a2053fb472b5c..6231a774df645 100755 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -2066,11 +2066,6 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"#endif\n"); out($f,$m[1]."} vm_stack_data;\n"); out($f,"#endif\n"); - // out($f,"#ifdef ZEND_UNIVERSAL_IP\n"); - // out($f,$m[1]."if (EG(current_execute_data) && EG(current_execute_data) != ex && opline) {\n"); - // out($f,$m[1]."\tEG(current_execute_data)->opline = opline;\n"); - // out($f,$m[1]."}\n"); - // out($f,"#endif\n"); out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n"); out($f,$m[1]."vm_stack_data.orig_opline = opline;\n"); out($f,"#endif\n"); @@ -2222,7 +2217,6 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); out($f,$prolog."zend_opcode_handler_funcs = labels;\n"); out($f,$prolog."zend_spec_handlers = specs;\n"); - out($f,$prolog."execute_data = NULL;\n"); out($f,$prolog.$executor_name."_ex(NULL);\n"); out($f,"#else\n"); } @@ -2990,21 +2984,13 @@ function gen_vm($def, $skel) { out($f, "\tif (EXPECTED(opline)) {\n"); } out($f, "\t\tret = execute_data != ex ? (int)(execute_data->prev_execute_data != ex) + 1 : 0;\n"); - out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n"); - out($f, "\t\tEX(opline) = opline;\n"); - out($f,"#else\n"); - out($f, "\t\tSAVE_OPLINE();\n"); - out($f,"#endif\n"); + out($f, "\t\tSAVE_OPLINE_EX();\n"); out($f, "\t} else {\n"); out($f, "\t\tret = -1;\n"); out($f, "\t}\n"); out($f, "#else\n"); out($f, "\tret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); - out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n"); - out($f, "\tEX(opline) = opline;\n"); - out($f,"#else\n"); - out($f, "\tSAVE_OPLINE();\n"); - out($f,"#endif\n"); + out($f, "\tSAVE_OPLINE_EX();\n"); out($f, "#endif\n"); out($f, "#ifdef ZEND_VM_FP_GLOBAL_REG\n"); out($f, "\texecute_data = orig_execute_data;\n"); From 2ce861199ea4a0a11a3423802906d7cbea7d4b1b Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sun, 3 Dec 2023 23:47:14 +0100 Subject: [PATCH 15/16] Fix yield from exception throwing --- Zend/zend_generators.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index e972c077babe2..bd6e8c636d24b 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -581,6 +581,7 @@ ZEND_API zend_generator *zend_generator_update_current(zend_generator *generator /* ZEND_YIELD(_FROM) already advance, so decrement opline to throw from correct place */ new_root->execute_data->opline--; + LOAD_CURRENT_OPLINE(); zend_throw_exception(zend_ce_ClosedGeneratorException, "Generator yielded from aborted, no return value available", 0); EG(current_execute_data) = original_execute_data; @@ -609,6 +610,7 @@ ZEND_API zend_generator *zend_generator_update_current(zend_generator *generator static zend_result zend_generator_get_next_delegated_value(zend_generator *generator) /* {{{ */ { --generator->execute_data->opline; + LOAD_CURRENT_OPLINE(); zval *value; if (Z_TYPE(generator->values) == IS_ARRAY) { @@ -692,6 +694,7 @@ static zend_result zend_generator_get_next_delegated_value(zend_generator *gener } ++generator->execute_data->opline; + LOAD_CURRENT_OPLINE(); return SUCCESS; failure: @@ -699,6 +702,7 @@ static zend_result zend_generator_get_next_delegated_value(zend_generator *gener ZVAL_UNDEF(&generator->values); ++generator->execute_data->opline; + LOAD_CURRENT_OPLINE(); return FAILURE; } /* }}} */ From 4e490fcd70d5f97c827d966629d479171093820b Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sun, 3 Dec 2023 23:53:36 +0100 Subject: [PATCH 16/16] Temporarily exclude JIT benchmarks --- benchmark/benchmark.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/benchmark/benchmark.php b/benchmark/benchmark.php index a0c01ca766233..e08b06cdedded 100644 --- a/benchmark/benchmark.php +++ b/benchmark/benchmark.php @@ -22,11 +22,11 @@ function main() { $data['branch'] = $branch; } $data['Zend/bench.php'] = runBench(false); - $data['Zend/bench.php JIT'] = runBench(true); + // $data['Zend/bench.php JIT'] = runBench(true); $data['Symfony Demo 2.2.3'] = runSymfonyDemo(false); - $data['Symfony Demo 2.2.3 JIT'] = runSymfonyDemo(true); + // $data['Symfony Demo 2.2.3 JIT'] = runSymfonyDemo(true); $data['Wordpress 6.2'] = runWordpress(false); - $data['Wordpress 6.2 JIT'] = runWordpress(true); + // $data['Wordpress 6.2 JIT'] = runWordpress(true); $result = json_encode($data, JSON_PRETTY_PRINT) . "\n"; fwrite(STDOUT, $result);