]> granicus.if.org Git - php/commitdiff
Trampoline cleanup
authorDmitry Stogov <dmitry@zend.com>
Mon, 16 Nov 2020 09:05:45 +0000 (12:05 +0300)
committerDmitry Stogov <dmitry@zend.com>
Mon, 16 Nov 2020 09:05:45 +0000 (12:05 +0300)
ext/opcache/jit/zend_jit_internal.h
ext/opcache/jit/zend_jit_trace.c
ext/opcache/jit/zend_jit_vm_helpers.c
ext/opcache/jit/zend_jit_x86.dasc
ext/opcache/tests/jit/trampoline_001.phpt [new file with mode: 0644]

index 22a5aa4100b257cb2289c69cb388102e9be70b31..74b3b8a7e80cf015ca35b7d948f1b8a1e147cf04 100644 (file)
@@ -211,7 +211,8 @@ typedef enum _zend_jit_trace_stop {
 #define ZEND_JIT_EXIT_FREE_OP1      (1<<5)
 #define ZEND_JIT_EXIT_FREE_OP2      (1<<6)
 #define ZEND_JIT_EXIT_PACKED_GUARD  (1<<7)
-#define ZEND_JIT_EXIT_DYNAMIC_CALL  (1<<8) /* exit because of polymorphic INTI_DYNAMIC_CALL call */
+#define ZEND_JIT_EXIT_CLOSURE_CALL  (1<<8) /* exit because of polymorphic INIT_DYNAMIC_CALL call */
+#define ZEND_JIT_EXIT_METHOD_CALL   (1<<9) /* exit because of polymorphic INIT_METHOD_CALL call */
 
 typedef union _zend_op_trace_info {
        zend_op dummy; /* the size of this structure must be the same as zend_op */
index e15dde5354e18f6a7e90ef59fcfabec373bb8963..31ab4fab068c89acbb3b37fe9725854fe55dda3c 100644 (file)
@@ -6640,7 +6640,7 @@ static void zend_jit_dump_exit_info(zend_jit_trace_info *t)
                if (t->exit_info[i].flags & ZEND_JIT_EXIT_RESTORE_CALL) {
                        fprintf(stderr, "/CALL");
                }
-               if (t->exit_info[i].flags & (ZEND_JIT_EXIT_POLYMORPHISM|ZEND_JIT_EXIT_DYNAMIC_CALL)) {
+               if (t->exit_info[i].flags & (ZEND_JIT_EXIT_POLYMORPHISM|ZEND_JIT_EXIT_METHOD_CALL|ZEND_JIT_EXIT_CLOSURE_CALL)) {
                        fprintf(stderr, "/POLY");
                }
                if (t->exit_info[i].flags & ZEND_JIT_EXIT_FREE_OP1) {
@@ -7043,12 +7043,12 @@ int ZEND_FASTCALL zend_jit_trace_hot_side(zend_execute_data *execute_data, uint3
        }
 
        if (JIT_G(max_polymorphic_calls) > 0) {
-               if ((zend_jit_traces[parent_num].exit_info[exit_num].flags & ZEND_JIT_EXIT_DYNAMIC_CALL)
+               if ((zend_jit_traces[parent_num].exit_info[exit_num].flags & (ZEND_JIT_EXIT_METHOD_CALL|ZEND_JIT_EXIT_CLOSURE_CALL))
                 || ((zend_jit_traces[parent_num].exit_info[exit_num].flags & ZEND_JIT_EXIT_POLYMORPHISM)
                  && EX(call))) {
                        if (zend_jit_traces[parent_num].polymorphism >= JIT_G(max_polymorphic_calls) - 1) {
                                is_megamorphic = zend_jit_traces[parent_num].exit_info[exit_num].flags &
-                                       (ZEND_JIT_EXIT_DYNAMIC_CALL | ZEND_JIT_EXIT_POLYMORPHISM);
+                                       (ZEND_JIT_EXIT_METHOD_CALL | ZEND_JIT_EXIT_CLOSURE_CALL | ZEND_JIT_EXIT_POLYMORPHISM);
                        } else if (!zend_jit_traces[parent_num].polymorphism) {
                                polymorphism = 1;
                        } else if (exit_num == 0) {
@@ -7249,6 +7249,16 @@ int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf
                                return 1;
                        }
                }
+               if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_METHOD_CALL) {
+                       zend_function *func = (zend_function*)regs->r[0];
+
+                       if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
+                               zend_string_release_ex(func->common.function_name, 0);
+                               zend_free_trampoline(func);
+                               EX(opline) = opline;
+                               return 1;
+                       }
+               }
 
                /* Set VM opline to continue interpretation */
                EX(opline) = opline;
index 6573200430543ae86d8ddffcd2ce5bc27a649e42..6952f7532ec441d9623dacd0fe793b35e5e19057 100644 (file)
@@ -928,7 +928,8 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
                                if (JIT_G(max_polymorphic_calls) == 0
                                 && zend_jit_may_be_polymorphic_call(opline - 1)) {
                                        func = NULL;
-                               } else if (is_megamorphic == ZEND_JIT_EXIT_DYNAMIC_CALL
+                               } else if ((is_megamorphic == ZEND_JIT_EXIT_METHOD_CALL
+                                                || is_megamorphic == ZEND_JIT_EXIT_CLOSURE_CALL)
                                                && trace_buffer[1].opline == opline - 1) {
                                        func = NULL;
                                }
index 7306ee2a3cb56cfcb78a8c3936d1c28d8882cb84..42b0e1940c0c36371266a5669756d9f10915b3aa 100644 (file)
@@ -9348,7 +9348,7 @@ static int zend_jit_init_method_call(dasm_State          **Dst,
                int32_t exit_point;
                const void *exit_addr;
 
-               exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_DYNAMIC_CALL);
+               exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_METHOD_CALL);
                exit_addr = zend_jit_trace_get_exit_addr(exit_point);
                if (!exit_addr) {
                        return 0;
@@ -9500,7 +9500,7 @@ static int zend_jit_init_closure_call(dasm_State          **Dst,
 
                func = (zend_function*)trace->func;
                opcodes = func->op_array.opcodes;
-               exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_DYNAMIC_CALL);
+               exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_CLOSURE_CALL);
                exit_addr = zend_jit_trace_get_exit_addr(exit_point);
                if (!exit_addr) {
                        return 0;
diff --git a/ext/opcache/tests/jit/trampoline_001.phpt b/ext/opcache/tests/jit/trampoline_001.phpt
new file mode 100644 (file)
index 0000000..21b8b20
--- /dev/null
@@ -0,0 +1,34 @@
+--TEST--
+JIT: trampoline cleanup
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.jit=tracing
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+class A {
+}
+class B extends A {
+       function foo() {
+               echo "B";
+       }
+}
+class C extends A {
+       function __call($name, $argd) {
+               echo "C";
+       }
+}
+$b = new B;
+$c = new C;
+$a = [$b, $b, $b, $c, $c, $c];
+foreach ($a as $x) {
+       $x->foo();
+}
+echo "\n";
+?>
+--EXPECT--
+BBBCCC