summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2020-11-16 12:05:45 +0300
committerDmitry Stogov <dmitry@zend.com>2020-11-16 12:05:45 +0300
commit64dc79f90649f2ca3522ae8d658da4d5707dba29 (patch)
treead89529b5fd04af857a9534140035abc460b5044
parent7bbed1808613aed5ac30c5c0edc2ce938489a072 (diff)
downloadphp-git-64dc79f90649f2ca3522ae8d658da4d5707dba29.tar.gz
Trampoline cleanup
-rw-r--r--ext/opcache/jit/zend_jit_internal.h3
-rw-r--r--ext/opcache/jit/zend_jit_trace.c16
-rw-r--r--ext/opcache/jit/zend_jit_vm_helpers.c3
-rw-r--r--ext/opcache/jit/zend_jit_x86.dasc4
-rw-r--r--ext/opcache/tests/jit/trampoline_001.phpt34
5 files changed, 53 insertions, 7 deletions
diff --git a/ext/opcache/jit/zend_jit_internal.h b/ext/opcache/jit/zend_jit_internal.h
index 22a5aa4100..74b3b8a7e8 100644
--- a/ext/opcache/jit/zend_jit_internal.h
+++ b/ext/opcache/jit/zend_jit_internal.h
@@ -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 */
diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c
index e15dde5354..31ab4fab06 100644
--- a/ext/opcache/jit/zend_jit_trace.c
+++ b/ext/opcache/jit/zend_jit_trace.c
@@ -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;
diff --git a/ext/opcache/jit/zend_jit_vm_helpers.c b/ext/opcache/jit/zend_jit_vm_helpers.c
index 6573200430..6952f7532e 100644
--- a/ext/opcache/jit/zend_jit_vm_helpers.c
+++ b/ext/opcache/jit/zend_jit_vm_helpers.c
@@ -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;
}
diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc
index 7306ee2a3c..42b0e1940c 100644
--- a/ext/opcache/jit/zend_jit_x86.dasc
+++ b/ext/opcache/jit/zend_jit_x86.dasc
@@ -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
index 0000000000..21b8b20ee0
--- /dev/null
+++ b/ext/opcache/tests/jit/trampoline_001.phpt
@@ -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