]> granicus.if.org Git - php/commitdiff
Squashed commit of the following:
authorDmitry Stogov <dmitry@zend.com>
Fri, 10 Apr 2015 20:01:00 +0000 (23:01 +0300)
committerDmitry Stogov <dmitry@zend.com>
Fri, 10 Apr 2015 20:01:00 +0000 (23:01 +0300)
commit 2399fc84c541da9c2176c5b7f6dd039a3c84dc64
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Fri Apr 10 12:38:08 2015 +0300

    Removed useless assignment

commit 796b6338174348eee0d74a67706d77b7ce1a60c3
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Fri Apr 10 12:35:31 2015 +0300

    Fixed execution with overriden zend_execute_ex()

commit 4a9fb125aa999059f8bc42ebb6ee573c7866b35b
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Fri Apr 10 02:02:58 2015 +0300

    Fixed executor without global registers

commit d456c30e00589ccda35a4b57ae903ef2d3c07d95
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Fri Apr 10 01:30:35 2015 +0300

    Restored original behavior for tests/classes/__call_004.phpt

commit 479646d37fef050536f1afb12b082618f1f1a3d0
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Fri Apr 10 00:32:17 2015 +0300

    Fixed test. We don't keep stack frame for fake function anymore.

commit 9ae61e33e24b2c811d4ab1ca4ab22847c64a780e
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Fri Apr 10 00:30:09 2015 +0300

    Use ZEND_ACC_CALL_VIA_TRAMPOLINE instead of ZEND_ACC_CALL_VIA_HANDLER. Keep ZEND_ACC_CALL_VIA_HANDLER for compatibility.

commit 0a8403a2a0c27aa3db271774f8559739a6b8400e
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Fri Apr 10 00:05:43 2015 +0300

    Rename PROXY_CALL into CALL_TRAMPLINE.
    Generalize API to allow reuse EG(trampline) for other purposes.

commit 4ea0525c10554e36185a0b8b6303106813b6a1c2
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Thu Apr 9 23:22:25 2015 +0300

    Reuse EG(proxy_call_op) for all proxy. Move proxy related functions from zend_objects_API to zend_object_handlers.

commit 529bf737ca388ad56fb4ae20ccb81e6276f25ec0
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Thu Apr 9 21:42:23 2015 +0300

    Accurate use of proxy_call

commit 5d62837d5ba3855743fe1981786ebd65d9da0b63
Merge: 83e749f 690843f
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Thu Apr 9 19:40:00 2015 +0300

    Merge branch 'master' into opcodefy-call

    * master:
      Fixed GOTO executor
      Fixed typo
      Changed ArrayIterator implementation using zend_hash_iterator_... API. Allowed modification of itterated ArrayObject using the same behavior as proposed in `Fix "foreach" behavior`. Removed "Array was modified outside object and internal position is no longer valid" hack.

commit 83e749ff3b6623e39b236a72e9b907d5b788ae5e
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Thu Apr 9 19:39:10 2015 +0300

    Improved ZEND_PROXY_CALL

commit 0c829afc534e6d5ff27a0dea3a4815da303bd1ef
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Thu Apr 9 15:14:49 2015 +0300

    Reverted white-space changes

commit df65144488afa3e9020d75e1ada5529b138afc5a
Merge: 5fd2f97 97756d9
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Thu Apr 9 14:37:07 2015 +0300

    Merge branch 'opcodefy-call' of github.com:laruence/php-src into opcodefy-call

    * 'opcodefy-call' of github.com:laruence/php-src:
      Ready for PR
      Fixed static call
      Improve performance by using prealloated op_arrray
      Respect called_scope
      Support internal magical __call/__callStatic
      opcode-fy magical __callStatic
      Opcode-fy magical __call

commit 97756d9190e07a072a7b48135304dc25a964845f
Author: Xinchen Hui <laruence@gmail.com>
Date:   Thu Apr 9 19:07:59 2015 +0800

    Ready for PR

commit 74f993084627061e783645a866390b68e2981698
Author: Xinchen Hui <laruence@gmail.com>
Date:   Thu Apr 9 19:03:00 2015 +0800

    Fixed static call

commit ec1d9eb592db0c3b7b0e3d21e7f445ed8bccfd4d
Author: Xinchen Hui <laruence@gmail.com>
Date:   Thu Apr 9 18:23:17 2015 +0800

    Improve performance by using prealloated op_arrray

commit df7fbbf949c99f2c5ae3da2a1199235651c7cc82
Author: Xinchen Hui <laruence@gmail.com>
Date:   Thu Apr 9 15:10:02 2015 +0800

    Respect called_scope

commit 769d1d59fb48b6f7f93d7412eefbf26135fa3e59
Author: Xinchen Hui <laruence@gmail.com>
Date:   Thu Apr 9 12:19:23 2015 +0800

    Support internal magical __call/__callStatic

commit a980fedd5b0e0683713dd4f6eaad62adf4b4732f
Author: Xinchen Hui <laruence@gmail.com>
Date:   Wed Apr 8 18:35:41 2015 +0800

    opcode-fy magical __callStatic

commit 73855f7d53baa2efc2b8a88314f51c784c81b59d
Author: Xinchen Hui <laruence@gmail.com>
Date:   Wed Apr 8 14:21:55 2015 +0800

    Opcode-fy magical __call

16 files changed:
NEWS
Zend/tests/bug50383.phpt
Zend/tests/bug68412.phpt [new file with mode: 0644]
Zend/zend.c
Zend/zend_API.c
Zend/zend_builtin_functions.c
Zend/zend_compile.h
Zend/zend_execute_API.c
Zend/zend_globals.h
Zend/zend_object_handlers.c
Zend/zend_object_handlers.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Zend/zend_vm_opcodes.c
Zend/zend_vm_opcodes.h
ext/reflection/php_reflection.c

diff --git a/NEWS b/NEWS
index fbdf82474f7d90f78f8031e26b721553194d349a..fc8cf3556b059dad7ac3dc2f5cc529da43a144c8 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,9 @@
   . Update the MIME type list from the one shipped by Apache HTTPD. (Adam)
 
 - Core:
+  . Improved __call() and __callStatic() magic method handling. Now they are
+    called in a stackless way using ZEND_CALL_TRAMPOLINE opcode, without
+    additional stack frame. (Laruence, Dmitry)
   . Fixed weird operators behavior. Division by zero now emits warning and 
     returns +/-INF, modulo by zero and intdid() throws an exception, shifts
     by negative offset throw exceptions. Compile-time evaluation of division
index 2210c4bc3569594070ce541379273d1649ac3377..de81facd053c14ce5e2421195b5d9a047469c536 100644 (file)
@@ -58,19 +58,6 @@ Array
         )
 
     [1] => Array
-        (
-            [file] => %s
-            [line] => 13
-            [function] => ThrowException
-            [class] => myClass
-            [type] => ::
-            [args] => Array
-                (
-                )
-
-        )
-
-    [2] => Array
         (
             [file] => %s
             [line] => 21
@@ -104,19 +91,6 @@ Array
         )
 
     [1] => Array
-        (
-            [file] => %s
-            [line] => 17
-            [function] => foo
-            [class] => myClass
-            [type] => ->
-            [args] => Array
-                (
-                )
-
-        )
-
-    [2] => Array
         (
             [file] => %s
             [line] => 28
diff --git a/Zend/tests/bug68412.phpt b/Zend/tests/bug68412.phpt
new file mode 100644 (file)
index 0000000..c6f413c
--- /dev/null
@@ -0,0 +1,19 @@
+--TEST--
+Bug #68412 (Infinite recursion with __call can make the program crash/segfault)
+--FILE--
+<?php
+class C {
+  public function __call($x, $y) {
+    global $z;
+    $z->bar();
+  }
+}
+$z = new C;
+function main() {
+  global $z;
+  $z->foo();
+}
+main();
+?>
+--EXPECTF--
+Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %sbug68412.php on line %d
index 38b5bd6bc266ef9f309e0937bf433ecc3b3ac166..77e0b624c01c459cbffc737adbf52b90c3baab96 100644 (file)
@@ -432,6 +432,17 @@ static void zend_init_exception_op(void) /* {{{ */
 }
 /* }}} */
 
+static void zend_init_call_trampoline_op(void) /* {{{ */
+{
+       memset(&EG(call_trampoline_op), 0, sizeof(EG(call_trampoline_op)));
+       EG(call_trampoline_op).opcode = ZEND_CALL_TRAMPOLINE;
+       EG(call_trampoline_op).op1_type = IS_UNUSED;
+       EG(call_trampoline_op).op2_type = IS_UNUSED;
+       EG(call_trampoline_op).result_type = IS_UNUSED;
+       ZEND_VM_SET_OPCODE_HANDLER(&EG(call_trampoline_op));
+}
+/* }}} */
+
 #ifdef ZTS
 static void function_copy_ctor(zval *zv)
 {
@@ -511,6 +522,8 @@ static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{
        zend_copy_constants(EG(zend_constants), GLOBAL_CONSTANTS_TABLE);
        zend_init_rsrc_plist();
        zend_init_exception_op();
+       zend_init_call_trampoline_op();
+       memset(&executor_globals->trampoline, 0, sizeof(zend_op_array));
        executor_globals->lambda_count = 0;
        ZVAL_UNDEF(&executor_globals->user_error_handler);
        ZVAL_UNDEF(&executor_globals->user_exception_handler);
@@ -722,6 +735,7 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions) /
 #ifndef ZTS
        zend_init_rsrc_plist();
        zend_init_exception_op();
+       zend_init_call_trampoline_op();
 #endif
 
        zend_ini_startup();
index 273e9e9f6ab6c0e37d110f9a6dc45f3798603f15..5e1a8185fd074a2b17b21941978a2dfb9da7a082 100644 (file)
@@ -3070,16 +3070,7 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca
 get_function_via_handler:
                if (fcc->object && fcc->calling_scope == ce_org) {
                        if (strict_class && ce_org->__call) {
-                               fcc->function_handler = emalloc(sizeof(zend_internal_function));
-                               fcc->function_handler->internal_function.type = ZEND_INTERNAL_FUNCTION;
-                               fcc->function_handler->internal_function.module = (ce_org->type == ZEND_INTERNAL_CLASS) ? ce_org->info.internal.module : NULL;
-                               fcc->function_handler->internal_function.handler = zend_std_call_user_call;
-                               fcc->function_handler->internal_function.arg_info = NULL;
-                               fcc->function_handler->internal_function.num_args = 0;
-                               fcc->function_handler->internal_function.scope = ce_org;
-                               fcc->function_handler->internal_function.fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
-                               fcc->function_handler->internal_function.function_name = mname;
-                               zend_string_addref(mname);
+                               fcc->function_handler = zend_get_call_trampoline_func(ce_org, mname, 0);
                                call_via_handler = 1;
                                retval = 1;
                        } else if (fcc->object->handlers->get_method) {
@@ -3088,15 +3079,15 @@ get_function_via_handler:
                                        if (strict_class &&
                                            (!fcc->function_handler->common.scope ||
                                             !instanceof_function(ce_org, fcc->function_handler->common.scope))) {
-                                               if ((fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0) {
+                                               if (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
                                                        if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) {
                                                                zend_string_release(fcc->function_handler->common.function_name);
                                                        }
-                                                       efree(fcc->function_handler);
+                                                       zend_free_trampoline(fcc->function_handler);
                                                }
                                        } else {
                                                retval = 1;
-                                               call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0;
+                                               call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;
                                        }
                                }
                        }
@@ -3108,7 +3099,7 @@ get_function_via_handler:
                        }
                        if (fcc->function_handler) {
                                retval = 1;
-                               call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0;
+                               call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;
                                if (call_via_handler && !fcc->object && EG(current_execute_data) && Z_OBJ(EG(current_execute_data)->This) &&
                                    instanceof_function(Z_OBJCE(EG(current_execute_data)->This), fcc->calling_scope)) {
                                        fcc->object = Z_OBJ(EG(current_execute_data)->This);
@@ -3250,14 +3241,13 @@ again:
                        ret = zend_is_callable_check_func(check_flags, callable, fcc, 0, error);
                        if (fcc == &fcc_local &&
                            fcc->function_handler &&
-                               ((fcc->function_handler->type == ZEND_INTERNAL_FUNCTION &&
-                             (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER)) ||
+                               ((fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) ||
                             fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
                             fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
                                if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) {
                                        zend_string_release(fcc->function_handler->common.function_name);
                                }
-                               efree(fcc->function_handler);
+                               zend_free_trampoline(fcc->function_handler);
                        }
                        return ret;
 
@@ -3338,14 +3328,13 @@ again:
                                        ret = zend_is_callable_check_func(check_flags, method, fcc, strict_class, error);
                                        if (fcc == &fcc_local &&
                                            fcc->function_handler &&
-                                               ((fcc->function_handler->type == ZEND_INTERNAL_FUNCTION &&
-                                             (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER)) ||
+                                               ((fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) ||
                                             fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
                                             fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
                                                if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) {
                                                        zend_string_release(fcc->function_handler->common.function_name);
                                                }
-                                               efree(fcc->function_handler);
+                                               zend_free_trampoline(fcc->function_handler);
                                        }
                                        return ret;
 
@@ -3414,14 +3403,13 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zend_string **callable_nam
                        add_next_index_str(callable, zend_string_copy(fcc.function_handler->common.function_name));
                }
                if (fcc.function_handler &&
-                       ((fcc.function_handler->type == ZEND_INTERNAL_FUNCTION &&
-                     (fcc.function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER)) ||
+                       ((fcc.function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) ||
                     fcc.function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
                     fcc.function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
                        if (fcc.function_handler->type != ZEND_OVERLOADED_FUNCTION) {
                                zend_string_release(fcc.function_handler->common.function_name);
                        }
-                       efree(fcc.function_handler);
+                       zend_free_trampoline(fcc.function_handler);
                }
                return 1;
        }
index c7d12bf1285435d5cae14b84d32728277665bef4..be6b11f6a84c00bc6082e2a8203ddd748a0115dd 100644 (file)
@@ -1285,16 +1285,14 @@ ZEND_FUNCTION(method_exists)
                && Z_OBJ_HT_P(klass)->get_method != NULL
                && (func = Z_OBJ_HT_P(klass)->get_method(&Z_OBJ_P(klass), method_name, NULL)) != NULL
                ) {
-                       if (func->type == ZEND_INTERNAL_FUNCTION
-                       && (func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0
-                       ) {
+                       if (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
                                /* Returns true to the fake Closure's __invoke */
                                RETVAL_BOOL(func->common.scope == zend_ce_closure
                                        && zend_string_equals_literal(method_name, ZEND_INVOKE_FUNC_NAME));
 
                                zend_string_release(lcname);
                                zend_string_release(func->common.function_name);
-                               efree(func);
+                               zend_free_trampoline(func);
                                return;
                        }
                        zend_string_release(lcname);
@@ -2508,8 +2506,7 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
                                if (prev_call &&
                                    prev_call->func &&
                                        !ZEND_USER_CODE(prev_call->func->common.type) &&
-                                       !(prev_call->func->common.type == ZEND_INTERNAL_FUNCTION &&
-                                               (prev_call->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER))) {
+                                       !(prev_call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
                                        break;
                                }
                                if (prev->func && ZEND_USER_CODE(prev->func->common.type)) {
index 322a7d32e711ac779cb64f230dc6f49fd8703581..57b234a12a541e0415e069a1b25aa8ec78204ba3 100644 (file)
@@ -226,8 +226,11 @@ typedef struct _zend_try_catch_element {
 #define ZEND_ACC_CLOSURE              0x100000
 #define ZEND_ACC_GENERATOR            0x800000
 
-/* function flag for internal user call handlers __call, __callstatic */
-#define ZEND_ACC_CALL_VIA_HANDLER     0x200000
+/* call through user function trampoline. e.g. __call, __callstatic */
+#define ZEND_ACC_CALL_VIA_TRAMPOLINE  0x200000
+
+/* call through internal function handler. e.g. Closure::invoke() */
+#define ZEND_ACC_CALL_VIA_HANDLER     ZEND_ACC_CALL_VIA_TRAMPOLINE
 
 /* disable inline caching */
 #define ZEND_ACC_NEVER_CACHE          0x400000
index d37c2cd1d8eb90e60e1a8546901fcb3e9cd76ff2..f79169232d8597833d9d3b6c16071b5c6e62dd63 100644 (file)
@@ -803,7 +803,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
                        Z_ADDREF_P(arg);
                } else {
                        if (Z_ISREF_P(arg) &&
-                           (func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0 ) {
+                           !(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
                                /* don't separate references for __call */
                                arg = Z_REFVAL_P(arg);
                        }
@@ -827,6 +827,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
        }
 
        if (func->type == ZEND_USER_FUNCTION) {
+               int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;
                EG(scope) = func->common.scope;
                call->symbol_table = fci->symbol_table;
                if (UNEXPECTED(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
@@ -839,8 +840,12 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
                } else {
                        zend_generator_create_zval(call, &func->op_array, fci->retval);
                }
+               if (call_via_handler) {
+                       /* We must re-initialize function again */
+                       fci_cache->initialized = 0;
+               }
        } else if (func->type == ZEND_INTERNAL_FUNCTION) {
-               int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0;
+               int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;
                ZVAL_NULL(fci->retval);
                if (func->common.scope) {
                        EG(scope) = func->common.scope;
index afd668afb87152385ea19cc373b75537bb5259b5..c1b1531eab862247178bacb93ff74b5f6503d3c7 100644 (file)
@@ -36,6 +36,7 @@
 #include "zend_modules.h"
 #include "zend_float.h"
 #include "zend_multibyte.h"
+#include "zend_multiply.h"
 #include "zend_arena.h"
 
 /* Define ZTS if you want a thread-safe Zend */
@@ -237,6 +238,9 @@ struct _zend_executor_globals {
        XPFPA_CW_DATATYPE saved_fpu_cw;
 #endif
 
+       zend_function trampoline;
+       zend_op       call_trampoline_op;
+
        void *reserved[ZEND_MAX_RESERVED_RESOURCES];
 };
 
index 00fb17451ea616b247e343563bbaa342429d5fbd..753c2abc780a99be93b00d381cb66fba24e82c43 100644 (file)
@@ -915,47 +915,6 @@ static void zend_std_unset_dimension(zval *object, zval *offset) /* {{{ */
 }
 /* }}} */
 
-ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
-{
-       zend_internal_function *func = (zend_internal_function *)EX(func);
-       zval method_name, method_args;
-       zval method_result;
-       zend_class_entry *ce = Z_OBJCE_P(getThis());
-
-       array_init_size(&method_args, ZEND_NUM_ARGS());
-
-       if (UNEXPECTED(zend_copy_parameters_array(ZEND_NUM_ARGS(), &method_args) == FAILURE)) {
-               zval_dtor(&method_args);
-               zend_error(E_EXCEPTION | E_ERROR, "Cannot get arguments for __call");
-               RETURN_FALSE;
-       }
-
-       ZVAL_STR(&method_name, func->function_name); /* no dup - it's a copy */
-
-       /* __call handler is called with two arguments:
-          method name
-          array of method parameters
-
-       */
-       zend_call_method_with_2_params(getThis(), ce, &ce->__call, ZEND_CALL_FUNC_NAME, &method_result, &method_name, &method_args);
-
-       if (Z_TYPE(method_result) != IS_UNDEF) {
-               RETVAL_ZVAL_FAST(&method_result);
-               zval_ptr_dtor(&method_result);
-       }
-
-       /* now destruct all auxiliaries */
-       zval_ptr_dtor(&method_args);
-       zval_ptr_dtor(&method_name);
-
-       /* destruct the function also, then - we have allocated it in get_method */
-       efree_size(func, sizeof(zend_internal_function));
-#if ZEND_DEBUG
-       execute_data->func = NULL;
-#endif
-}
-/* }}} */
-
 /* Ensures that we're allowed to call a private method.
  * Returns the function address that should be called, or NULL
  * if no such function exists.
@@ -1034,25 +993,48 @@ ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope)
 }
 /* }}} */
 
-static inline union _zend_function *zend_get_user_call_function(zend_class_entry *ce, zend_string *method_name) /* {{{ */
+ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend_string *method_name, int is_static) /* {{{ */
 {
-       zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function));
-       call_user_call->type = ZEND_INTERNAL_FUNCTION;
-       call_user_call->module = (ce->type == ZEND_INTERNAL_CLASS) ? ce->info.internal.module : NULL;
-       call_user_call->handler = zend_std_call_user_call;
-       call_user_call->arg_info = NULL;
-       call_user_call->num_args = 0;
-       call_user_call->scope = ce;
-       call_user_call->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
+       zend_op_array *func;
+       zend_function *fbc = is_static ? ce->__callstatic : ce->__call;
+
+       ZEND_ASSERT(fbc);
+
+       if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
+               func = &EG(trampoline).op_array;
+       } else {
+               func = ecalloc(1, sizeof(zend_op_array));
+       }
+
+       func->type = ZEND_USER_FUNCTION;
+       func->fn_flags = ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_PUBLIC;
+       if (is_static) {
+               func->fn_flags |= ZEND_ACC_STATIC;
+       }
+       func->this_var = -1;
+       func->opcodes = &EG(call_trampoline_op);
+
+       func->scope = ce;
+       func->prototype = fbc;
+       func->filename = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.filename : STR_EMPTY_ALLOC();
+       func->line_start = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.line_start : 0;
+       func->line_end = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.line_end : 0;
+
        //??? keep compatibility for "\0" characters
        //??? see: Zend/tests/bug46238.phpt
        if (UNEXPECTED(strlen(method_name->val) != method_name->len)) {
-               call_user_call->function_name = zend_string_init(method_name->val, strlen(method_name->val), 0);
+               func->function_name = zend_string_init(method_name->val, strlen(method_name->val), 0);
        } else {
-               call_user_call->function_name = zend_string_copy(method_name);
+               func->function_name = zend_string_copy(method_name);
        }
 
-       return (union _zend_function *)call_user_call;
+       return (zend_function*)func;
+}
+/* }}} */
+
+static zend_always_inline zend_function *zend_get_user_call_function(zend_class_entry *ce, zend_string *method_name) /* {{{ */
+{
+       return zend_get_call_trampoline_func(ce, method_name, 0);
 }
 /* }}} */
 
@@ -1141,70 +1123,12 @@ static union _zend_function *zend_std_get_method(zend_object **obj_ptr, zend_str
 }
 /* }}} */
 
-ZEND_API void zend_std_callstatic_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
-{
-       zend_internal_function *func = (zend_internal_function *)EX(func);
-       zval method_name, method_args;
-       zval method_result;
-       zend_class_entry *ce = EG(scope);
-
-       array_init_size(&method_args, ZEND_NUM_ARGS());
-
-       if (UNEXPECTED(zend_copy_parameters_array(ZEND_NUM_ARGS(), &method_args) == FAILURE)) {
-               zval_dtor(&method_args);
-               zend_error(E_EXCEPTION | E_ERROR, "Cannot get arguments for " ZEND_CALLSTATIC_FUNC_NAME);
-               RETURN_FALSE;
-       }
-
-       ZVAL_STR(&method_name, func->function_name); /* no dup - it's a copy */
-
-       /* __callStatic handler is called with two arguments:
-          method name
-          array of method parameters
-       */
-       zend_call_method_with_2_params(NULL, ce, &ce->__callstatic, ZEND_CALLSTATIC_FUNC_NAME, &method_result, &method_name, &method_args);
-
-       if (Z_TYPE(method_result) != IS_UNDEF) {
-               RETVAL_ZVAL_FAST(&method_result);
-               zval_ptr_dtor(&method_result);
-       }
-
-       /* now destruct all auxiliaries */
-       zval_ptr_dtor(&method_args);
-       zval_ptr_dtor(&method_name);
-
-       /* destruct the function also, then - we have allocated it in get_method */
-       efree_size(func, sizeof(zend_internal_function));
-#if ZEND_DEBUG
-       execute_data->func = NULL;
-#endif
-}
-/* }}} */
-
-static inline union _zend_function *zend_get_user_callstatic_function(zend_class_entry *ce, zend_string *method_name) /* {{{ */
+static zend_always_inline zend_function *zend_get_user_callstatic_function(zend_class_entry *ce, zend_string *method_name) /* {{{ */
 {
-       zend_internal_function *callstatic_user_call = emalloc(sizeof(zend_internal_function));
-       callstatic_user_call->type     = ZEND_INTERNAL_FUNCTION;
-       callstatic_user_call->module   = (ce->type == ZEND_INTERNAL_CLASS) ? ce->info.internal.module : NULL;
-       callstatic_user_call->handler  = zend_std_callstatic_user_call;
-       callstatic_user_call->arg_info = NULL;
-       callstatic_user_call->num_args = 0;
-       callstatic_user_call->scope    = ce;
-       callstatic_user_call->fn_flags = ZEND_ACC_STATIC | ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER;
-       //??? keep compatibility for "\0" characters
-       //??? see: Zend/tests/bug46238.phpt
-       if (UNEXPECTED(strlen(method_name->val) != method_name->len)) {
-               callstatic_user_call->function_name = zend_string_init(method_name->val, strlen(method_name->val), 0);
-       } else {
-               callstatic_user_call->function_name = zend_string_copy(method_name);
-       }
-
-       return (zend_function *)callstatic_user_call;
+       return zend_get_call_trampoline_func(ce, method_name, 1);
 }
 /* }}} */
 
-/* This is not (yet?) in the API, but it belongs in the built-in objects callbacks */
-
 ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_string *function_name, const zval *key) /* {{{ */
 {
        zend_function *fbc = NULL;
@@ -1239,7 +1163,15 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_st
                        if (ce->__call &&
                            Z_OBJ(EG(current_execute_data)->This) &&
                            instanceof_function(Z_OBJCE(EG(current_execute_data)->This), ce)) {
-                               return zend_get_user_call_function(ce, function_name);
+                               /* Call the top-level defined __call().
+                                * see: tests/classes/__call_004.phpt  */
+
+                               zend_class_entry *call_ce = Z_OBJCE(EG(current_execute_data)->This);
+
+                               while (!call_ce->__call) {
+                                       call_ce = call_ce->parent;
+                               }
+                               return zend_get_user_call_function(call_ce, function_name);
                        } else if (ce->__callstatic) {
                                return zend_get_user_callstatic_function(ce, function_name);
                        } else {
index c537a1617303e9892d21ba907bf93473b3805500..77ac85039f066703e2c884bbd33e03610e232243 100644 (file)
@@ -22,7 +22,6 @@
 #ifndef ZEND_OBJECT_HANDLERS_H
 #define ZEND_OBJECT_HANDLERS_H
 
-union _zend_function;
 struct _zend_property_info;
 
 #define ZEND_WRONG_PROPERTY_INFO \
@@ -179,7 +178,16 @@ ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope)
 
 ZEND_API int zend_check_property_access(zend_object *zobj, zend_string *prop_info_name);
 
-ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS);
+ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend_string *method_name, int is_static);
+
+#define zend_free_trampoline(func) do { \
+               if ((func) == &EG(trampoline)) { \
+                       EG(trampoline).common.function_name = NULL; \
+               } else { \
+                       efree(func); \
+               } \
+       } while (0)
+
 END_EXTERN_C()
 
 #endif
index 17c2041b3d0680c308a255a5e728d5605b4c452b..8859d674ebeb1b4c8aab06260fee5b78eb2bf705 100644 (file)
@@ -2890,7 +2890,7 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMPVAR|UNUSED|CV, CONST|TMPVAR|CV)
                }
                if (OP2_TYPE == IS_CONST &&
                    EXPECTED(fbc->type <= ZEND_USER_FUNCTION) &&
-                   EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) &&
+                   EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
                    EXPECTED(obj == orig_obj)) {
                        CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc);
                }
@@ -2978,7 +2978,7 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMPVAR|UNUSE
                }
                if (OP2_TYPE == IS_CONST &&
                    EXPECTED(fbc->type <= ZEND_USER_FUNCTION) &&
-                   EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) {
+                   EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
                        if (OP1_TYPE == IS_CONST) {
                                CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc);
                        } else {
@@ -4433,7 +4433,7 @@ ZEND_VM_C_LABEL(send_array):
                                Z_ADDREF_P(arg);
                        } else{
                                if (Z_ISREF_P(arg) &&
-                                   (EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) {
+                                   !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
                                        /* don't separate references for __call */
                                        arg = Z_REFVAL_P(arg);
                                }
@@ -4494,7 +4494,7 @@ ZEND_VM_HANDLER(120, ZEND_SEND_USER, VAR|CV, ANY)
                Z_ADDREF_P(arg);
        } else {
                if (Z_ISREF_P(arg) &&
-                   (EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) {
+                   !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
                        /* don't separate references for __call */
                        arg = Z_REFVAL_P(arg);
                }
@@ -6937,9 +6937,9 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
                                }
                                OBJ_RELEASE(Z_OBJ(call->This));
                        }
-                       if (call->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) {
+                       if (call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
                                zend_string_release(call->func->common.function_name);
-                               efree(call->func);
+                               zend_free_trampoline(call->func);
                        }
 
                        EX(call) = call->prev_execute_data;
@@ -7558,3 +7558,142 @@ ZEND_VM_HANDLER(157, ZEND_FETCH_CLASS_NAME, ANY, ANY)
        ZEND_VM_NEXT_OPCODE();
 }
 
+ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY)
+{
+       zend_array *args;
+       zend_function *fbc = EX(func);
+       zend_object *object = Z_OBJ(EX(This));
+       zval *ret = EX(return_value);
+       zend_call_kind call_kind = EX_CALL_KIND();
+       zend_class_entry *scope = EX(called_scope);
+       uint32_t num_args = EX_NUM_ARGS();
+       zend_execute_data *call;
+       USE_OPLINE
+
+       args = emalloc(sizeof(zend_array));
+       zend_hash_init(args, num_args, NULL, ZVAL_PTR_DTOR, 0);
+       if (num_args) {
+               zval *p = ZEND_CALL_ARG(execute_data, 1);
+               zval *end = p + num_args;
+
+               zend_hash_real_init(args, 1);
+               ZEND_HASH_FILL_PACKED(args) {
+                       do {
+                               ZEND_HASH_FILL_ADD(p);
+                               p++;
+                       } while (p != end);
+               } ZEND_HASH_FILL_END();
+       }
+
+       SAVE_OPLINE();
+       call = execute_data;
+       execute_data = EG(current_execute_data) = EX(prev_execute_data);
+       zend_vm_stack_free_call_frame(call);
+       call = zend_vm_stack_push_call_frame(call_kind, fbc->common.prototype, 2, scope, object, execute_data);
+
+       ZVAL_STR(ZEND_CALL_ARG(call, 1), fbc->common.function_name);
+       ZVAL_ARR(ZEND_CALL_ARG(call, 2), args);
+       zend_free_trampoline(fbc);
+       fbc = call->func;
+
+       if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
+
+               ZEND_ASSERT(!(fbc->common.fn_flags & ZEND_ACC_GENERATOR));
+
+               /* This must be already set on invokation of trampoline function */
+               /*EG(scope) = fbc->common.scope;*/
+               call->symbol_table = NULL;
+               i_init_func_execute_data(call, &fbc->op_array,
+                               ret, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0);
+
+               if (EXPECTED(zend_execute_ex == execute_ex)) {
+                       ZEND_VM_ENTER();
+               } else {
+                       ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
+                       zend_execute_ex(call);
+               }
+       } else {
+               zval retval;
+
+               ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
+
+               EG(scope) = object ? NULL : fbc->common.scope;
+               EG(current_execute_data) = call;
+
+               if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
+                       uint32_t i;
+                       uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
+                       zval *p = ZEND_CALL_ARG(call, 1);
+
+                       EG(current_execute_data) = call;
+
+                       for (i = 0; i < num_args; ++i) {
+                               zend_verify_internal_arg_type(fbc, i + 1, p);
+                               if (UNEXPECTED(EG(exception) != NULL)) {
+                                       EG(current_execute_data) = call->prev_execute_data;
+                                       zend_vm_stack_free_args(call);
+                                       zend_vm_stack_free_call_frame(call);
+                                       if (ret) {
+                                               ZVAL_UNDEF(ret);
+                                       }
+                                       ZEND_VM_C_GOTO(call_trampoline_end);
+                               }
+                               p++;
+                       }
+               }
+
+               if (ret == NULL) {
+                       ZVAL_NULL(&retval);
+                       ret = &retval;
+               }
+               Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0;
+
+               if (!zend_execute_internal) {
+                       /* saves one function call if zend_execute_internal is not used */
+                       fbc->internal_function.handler(call, ret);
+               } else {
+                       zend_execute_internal(call, ret);
+               }
+
+#if ZEND_DEBUG
+               ZEND_ASSERT(
+                       !call->func ||
+                       !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
+                       zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var)));
+#endif
+
+               EG(current_execute_data) = call->prev_execute_data;
+
+               zend_vm_stack_free_args(call);
+               zend_vm_stack_free_call_frame(call);
+
+               if (ret == &retval) {
+                       zval_ptr_dtor(ret);
+               }
+       }
+
+ZEND_VM_C_LABEL(call_trampoline_end):
+       execute_data = EG(current_execute_data);
+
+       if (!EX(func) || !ZEND_USER_CODE(EX(func)->type) || (call_kind & ZEND_CALL_TOP)) {
+               ZEND_VM_RETURN();
+       }
+
+       LOAD_OPLINE();
+
+       if (object) {
+               OBJ_RELEASE(object);
+       }
+       EG(scope) = EX(func)->op_array.scope;
+
+       if (UNEXPECTED(EG(exception) != NULL)) {
+               zend_throw_exception_internal(NULL);
+               if (RETURN_VALUE_USED(opline)) {
+                       zval_ptr_dtor(EX_VAR(opline->result.var));
+               }
+               HANDLE_EXCEPTION_LEAVE();
+       }
+
+       ZEND_VM_INC_OPCODE();
+       ZEND_VM_LEAVE();
+}
index 8c23e7c5b14b6fd9749b9ea81f66f95368cadebe..f1ad2aa7d619d25908ede6d723e9f57a8c33a5ec 100644 (file)
@@ -1168,7 +1168,7 @@ send_array:
                                Z_ADDREF_P(arg);
                        } else{
                                if (Z_ISREF_P(arg) &&
-                                   (EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) {
+                                   !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
                                        /* don't separate references for __call */
                                        arg = Z_REFVAL_P(arg);
                                }
@@ -1551,9 +1551,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(
                                }
                                OBJ_RELEASE(Z_OBJ(call->This));
                        }
-                       if (call->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) {
+                       if (call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
                                zend_string_release(call->func->common.function_name);
-                               efree(call->func);
+                               zend_free_trampoline(call->func);
                        }
 
                        EX(call) = call->prev_execute_data;
@@ -1772,6 +1772,145 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_NAME_SPEC_HANDLER(
        ZEND_VM_NEXT_OPCODE();
 }
 
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+       zend_array *args;
+       zend_function *fbc = EX(func);
+       zend_object *object = Z_OBJ(EX(This));
+       zval *ret = EX(return_value);
+       zend_call_kind call_kind = EX_CALL_KIND();
+       zend_class_entry *scope = EX(called_scope);
+       uint32_t num_args = EX_NUM_ARGS();
+       zend_execute_data *call;
+       USE_OPLINE
+
+       args = emalloc(sizeof(zend_array));
+       zend_hash_init(args, num_args, NULL, ZVAL_PTR_DTOR, 0);
+       if (num_args) {
+               zval *p = ZEND_CALL_ARG(execute_data, 1);
+               zval *end = p + num_args;
+
+               zend_hash_real_init(args, 1);
+               ZEND_HASH_FILL_PACKED(args) {
+                       do {
+                               ZEND_HASH_FILL_ADD(p);
+                               p++;
+                       } while (p != end);
+               } ZEND_HASH_FILL_END();
+       }
+
+       SAVE_OPLINE();
+       call = execute_data;
+       execute_data = EG(current_execute_data) = EX(prev_execute_data);
+       zend_vm_stack_free_call_frame(call);
+       call = zend_vm_stack_push_call_frame(call_kind, fbc->common.prototype, 2, scope, object, execute_data);
+
+       ZVAL_STR(ZEND_CALL_ARG(call, 1), fbc->common.function_name);
+       ZVAL_ARR(ZEND_CALL_ARG(call, 2), args);
+       zend_free_trampoline(fbc);
+       fbc = call->func;
+
+       if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
+
+               ZEND_ASSERT(!(fbc->common.fn_flags & ZEND_ACC_GENERATOR));
+
+               /* This must be already set on invokation of trampoline function */
+               /*EG(scope) = fbc->common.scope;*/
+               call->symbol_table = NULL;
+               i_init_func_execute_data(call, &fbc->op_array,
+                               ret, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0);
+
+               if (EXPECTED(zend_execute_ex == execute_ex)) {
+                       ZEND_VM_ENTER();
+               } else {
+                       ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
+                       zend_execute_ex(call);
+               }
+       } else {
+               zval retval;
+
+               ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
+
+               EG(scope) = object ? NULL : fbc->common.scope;
+               EG(current_execute_data) = call;
+
+               if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
+                       uint32_t i;
+                       uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
+                       zval *p = ZEND_CALL_ARG(call, 1);
+
+                       EG(current_execute_data) = call;
+
+                       for (i = 0; i < num_args; ++i) {
+                               zend_verify_internal_arg_type(fbc, i + 1, p);
+                               if (UNEXPECTED(EG(exception) != NULL)) {
+                                       EG(current_execute_data) = call->prev_execute_data;
+                                       zend_vm_stack_free_args(call);
+                                       zend_vm_stack_free_call_frame(call);
+                                       if (ret) {
+                                               ZVAL_UNDEF(ret);
+                                       }
+                                       goto call_trampoline_end;
+                               }
+                               p++;
+                       }
+               }
+
+               if (ret == NULL) {
+                       ZVAL_NULL(&retval);
+                       ret = &retval;
+               }
+               Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0;
+
+               if (!zend_execute_internal) {
+                       /* saves one function call if zend_execute_internal is not used */
+                       fbc->internal_function.handler(call, ret);
+               } else {
+                       zend_execute_internal(call, ret);
+               }
+
+#if ZEND_DEBUG
+               ZEND_ASSERT(
+                       !call->func ||
+                       !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
+                       zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var)));
+#endif
+
+               EG(current_execute_data) = call->prev_execute_data;
+
+               zend_vm_stack_free_args(call);
+               zend_vm_stack_free_call_frame(call);
+
+               if (ret == &retval) {
+                       zval_ptr_dtor(ret);
+               }
+       }
+
+call_trampoline_end:
+       execute_data = EG(current_execute_data);
+
+       if (!EX(func) || !ZEND_USER_CODE(EX(func)->type) || (call_kind & ZEND_CALL_TOP)) {
+               ZEND_VM_RETURN();
+       }
+
+       LOAD_OPLINE();
+
+       if (object) {
+               OBJ_RELEASE(object);
+       }
+       EG(scope) = EX(func)->op_array.scope;
+
+       if (UNEXPECTED(EG(exception) != NULL)) {
+               zend_throw_exception_internal(NULL);
+               if (RETURN_VALUE_USED(opline)) {
+                       zval_ptr_dtor(EX_VAR(opline->result.var));
+               }
+               HANDLE_EXCEPTION_LEAVE();
+       }
+
+       ZEND_VM_INC_OPCODE();
+       ZEND_VM_LEAVE();
+}
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
@@ -5057,7 +5196,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C
                }
                if (IS_CONST == IS_CONST &&
                    EXPECTED(fbc->type <= ZEND_USER_FUNCTION) &&
-                   EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) {
+                   EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
                        if (IS_CONST == IS_CONST) {
                                CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc);
                        } else {
@@ -7006,7 +7145,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C
                }
                if (IS_UNUSED == IS_CONST &&
                    EXPECTED(fbc->type <= ZEND_USER_FUNCTION) &&
-                   EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) {
+                   EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
                        if (IS_CONST == IS_CONST) {
                                CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc);
                        } else {
@@ -8514,7 +8653,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C
                }
                if (IS_CV == IS_CONST &&
                    EXPECTED(fbc->type <= ZEND_USER_FUNCTION) &&
-                   EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) {
+                   EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
                        if (IS_CONST == IS_CONST) {
                                CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc);
                        } else {
@@ -10103,7 +10242,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C
                }
                if ((IS_TMP_VAR|IS_VAR) == IS_CONST &&
                    EXPECTED(fbc->type <= ZEND_USER_FUNCTION) &&
-                   EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) {
+                   EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
                        if (IS_CONST == IS_CONST) {
                                CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc);
                        } else {
@@ -14013,7 +14152,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_VAR_HANDLER(ZEN
                Z_ADDREF_P(arg);
        } else {
                if (Z_ISREF_P(arg) &&
-                   (EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) {
+                   !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
                        /* don't separate references for __call */
                        arg = Z_REFVAL_P(arg);
                }
@@ -16161,7 +16300,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V
                }
                if (IS_CONST == IS_CONST &&
                    EXPECTED(fbc->type <= ZEND_USER_FUNCTION) &&
-                   EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) {
+                   EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
                        if (IS_VAR == IS_CONST) {
                                CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc);
                        } else {
@@ -17756,7 +17895,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V
                }
                if (IS_UNUSED == IS_CONST &&
                    EXPECTED(fbc->type <= ZEND_USER_FUNCTION) &&
-                   EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) {
+                   EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
                        if (IS_VAR == IS_CONST) {
                                CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc);
                        } else {
@@ -19443,7 +19582,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V
                }
                if (IS_CV == IS_CONST &&
                    EXPECTED(fbc->type <= ZEND_USER_FUNCTION) &&
-                   EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) {
+                   EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
                        if (IS_VAR == IS_CONST) {
                                CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc);
                        } else {
@@ -21085,7 +21224,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V
                }
                if ((IS_TMP_VAR|IS_VAR) == IS_CONST &&
                    EXPECTED(fbc->type <= ZEND_USER_FUNCTION) &&
-                   EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) {
+                   EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
                        if (IS_VAR == IS_CONST) {
                                CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc);
                        } else {
@@ -22542,7 +22681,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_C
                }
                if (IS_CONST == IS_CONST &&
                    EXPECTED(fbc->type <= ZEND_USER_FUNCTION) &&
-                   EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) &&
+                   EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
                    EXPECTED(obj == orig_obj)) {
                        CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc);
                }
@@ -24935,7 +25074,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_C
                }
                if (IS_CV == IS_CONST &&
                    EXPECTED(fbc->type <= ZEND_USER_FUNCTION) &&
-                   EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) &&
+                   EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
                    EXPECTED(obj == orig_obj)) {
                        CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc);
                }
@@ -26444,7 +26583,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_T
                }
                if ((IS_TMP_VAR|IS_VAR) == IS_CONST &&
                    EXPECTED(fbc->type <= ZEND_USER_FUNCTION) &&
-                   EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) &&
+                   EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
                    EXPECTED(obj == orig_obj)) {
                        CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc);
                }
@@ -27583,7 +27722,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_CV_HANDLER(ZEND
                Z_ADDREF_P(arg);
        } else {
                if (Z_ISREF_P(arg) &&
-                   (EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) {
+                   !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
                        /* don't separate references for __call */
                        arg = Z_REFVAL_P(arg);
                }
@@ -30526,7 +30665,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST
                }
                if (IS_CONST == IS_CONST &&
                    EXPECTED(fbc->type <= ZEND_USER_FUNCTION) &&
-                   EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) &&
+                   EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
                    EXPECTED(obj == orig_obj)) {
                        CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc);
                }
@@ -35485,7 +35624,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HA
                }
                if (IS_CV == IS_CONST &&
                    EXPECTED(fbc->type <= ZEND_USER_FUNCTION) &&
-                   EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) &&
+                   EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
                    EXPECTED(obj == orig_obj)) {
                        CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc);
                }
@@ -38015,7 +38154,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMPVA
                }
                if ((IS_TMP_VAR|IS_VAR) == IS_CONST &&
                    EXPECTED(fbc->type <= ZEND_USER_FUNCTION) &&
-                   EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) &&
+                   EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
                    EXPECTED(obj == orig_obj)) {
                        CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc);
                }
@@ -40089,7 +40228,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_C
                }
                if (IS_CONST == IS_CONST &&
                    EXPECTED(fbc->type <= ZEND_USER_FUNCTION) &&
-                   EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) &&
+                   EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
                    EXPECTED(obj == orig_obj)) {
                        CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc);
                }
@@ -42096,7 +42235,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_C
                }
                if (IS_CV == IS_CONST &&
                    EXPECTED(fbc->type <= ZEND_USER_FUNCTION) &&
-                   EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) &&
+                   EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
                    EXPECTED(obj == orig_obj)) {
                        CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc);
                }
@@ -43114,7 +43253,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_T
                }
                if ((IS_TMP_VAR|IS_VAR) == IS_CONST &&
                    EXPECTED(fbc->type <= ZEND_USER_FUNCTION) &&
-                   EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) &&
+                   EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
                    EXPECTED(obj == orig_obj)) {
                        CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc);
                }
@@ -47346,31 +47485,31 @@ void zend_init_opcodes_handlers(void)
        ZEND_FETCH_CLASS_NAME_SPEC_HANDLER,
        ZEND_FETCH_CLASS_NAME_SPEC_HANDLER,
        ZEND_FETCH_CLASS_NAME_SPEC_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
+       ZEND_CALL_TRAMPOLINE_SPEC_HANDLER,
        ZEND_DISCARD_EXCEPTION_SPEC_HANDLER,
        ZEND_DISCARD_EXCEPTION_SPEC_HANDLER,
        ZEND_DISCARD_EXCEPTION_SPEC_HANDLER,
index b234c2f33e12ff62fc3dbef2ca7504cf41dd3dc2..2214cd9dc44783b2cb67f31259e29901c27b9884 100644 (file)
@@ -180,7 +180,7 @@ const char *zend_vm_opcodes_map[171] = {
        "ZEND_BIND_TRAITS",
        "ZEND_SEPARATE",
        "ZEND_FETCH_CLASS_NAME",
-       NULL,
+       "ZEND_CALL_TRAMPOLINE",
        "ZEND_DISCARD_EXCEPTION",
        "ZEND_YIELD",
        "ZEND_GENERATOR_RETURN",
index 84b7cd98828b118630249d896d20a396c86049f0..8b9321a99177c0e99fa76f8ba453ba2c63fe95cc 100644 (file)
@@ -188,6 +188,7 @@ END_EXTERN_C()
 #define ZEND_BIND_TRAITS                     155
 #define ZEND_SEPARATE                        156
 #define ZEND_FETCH_CLASS_NAME                157
+#define ZEND_CALL_TRAMPOLINE                 158
 #define ZEND_DISCARD_EXCEPTION               159
 #define ZEND_YIELD                           160
 #define ZEND_GENERATOR_RETURN                161
index da208f6c4b5fabb3afbf4e5147eaa26b9514ff95..47cf107b19afab0fb167552e45e64085c0a2bb7a 100644 (file)
@@ -265,8 +265,7 @@ static void _default_lookup_entry(zval *object, char *name, int name_len, zval *
 static zend_function *_copy_function(zend_function *fptr) /* {{{ */
 {
        if (fptr
-               && fptr->type == ZEND_INTERNAL_FUNCTION
-               && (fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0)
+               && (fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
        {
                zend_function *copy_fptr;
                copy_fptr = emalloc(sizeof(zend_function));
@@ -283,11 +282,10 @@ static zend_function *_copy_function(zend_function *fptr) /* {{{ */
 static void _free_function(zend_function *fptr) /* {{{ */
 {
        if (fptr
-               && fptr->type == ZEND_INTERNAL_FUNCTION
-               && (fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0)
+               && (fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
        {
                zend_string_release(fptr->internal_function.function_name);
-               efree(fptr);
+               zend_free_trampoline(fptr);
        }
 }
 /* }}} */
@@ -2238,11 +2236,11 @@ ZEND_METHOD(reflection_parameter, __construct)
        if (Z_TYPE_P(parameter) == IS_LONG) {
                position= (int)Z_LVAL_P(parameter);
                if (position < 0 || (uint32_t)position >= num_args) {
-                       if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) {
+                       if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
                                if (fptr->type != ZEND_OVERLOADED_FUNCTION) {
                                        zend_string_release(fptr->common.function_name);
                                }
-                               efree(fptr);
+                               zend_free_trampoline(fptr);
                        }
                        if (is_closure) {
                                zval_ptr_dtor(reference);
@@ -2276,11 +2274,11 @@ ZEND_METHOD(reflection_parameter, __construct)
                        }
                }
                if (position == -1) {
-                       if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) {
+                       if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
                                if (fptr->type != ZEND_OVERLOADED_FUNCTION) {
                                        zend_string_release(fptr->common.function_name);
                                }
-                               efree(fptr);
+                               zend_free_trampoline(fptr);
                        }
                        if (is_closure) {
                                zval_ptr_dtor(reference);
@@ -2841,8 +2839,8 @@ ZEND_METHOD(reflection_method, getClosure)
                }
 
                /* This is an original closure object and __invoke is to be called. */
-               if (Z_OBJCE_P(obj) == zend_ce_closure && mptr->type == ZEND_INTERNAL_FUNCTION &&
-                       (mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0)
+               if (Z_OBJCE_P(obj) == zend_ce_closure &&
+                       (mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
                {
                        RETURN_ZVAL(obj, 1, 0);
                } else {
@@ -3043,8 +3041,7 @@ ZEND_METHOD(reflection_method, invokeArgs)
        /*
         * Copy the zend_function when calling via handler (e.g. Closure::__invoke())
         */
-       if (mptr->type == ZEND_INTERNAL_FUNCTION &&
-               (mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0) {
+       if ((mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
                fcc.function_handler = _copy_function(mptr);
        }