Skip to content

Commit 7e53b08

Browse files
committed
Merge branch 'PHP-8.0' into PHP-8.1
* PHP-8.0: JIT: Fixed megamorphic call detection
2 parents fb5cff1 + 95c0dfc commit 7e53b08

File tree

4 files changed

+66
-33
lines changed

4 files changed

+66
-33
lines changed

Zend/zend_compile.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,7 @@ struct _zend_execute_data {
551551
#define ZEND_CALL_OBSERVED (1 << 28) /* "fcall_begin" observer handler may set this flag */
552552
/* to prevent optimization in RETURN handler and */
553553
/* keep all local variables for "fcall_end" handler */
554+
#define ZEND_CALL_JIT_RESERVED (1 << 29) /* reserved for tracing JIT */
554555
#define ZEND_CALL_SEND_ARG_BY_REF (1u << 31)
555556

556557
#define ZEND_CALL_NESTED_FUNCTION (ZEND_CALL_FUNCTION | ZEND_CALL_NESTED)

ext/opcache/jit/zend_jit_vm_helpers.c

Lines changed: 12 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,9 @@ static uint8_t zend_jit_trace_bad_stop_event(const zend_op *opline, int count)
449449
return 0;
450450
}
451451

452-
static int zend_jit_trace_record_fake_init_call_ex(zend_execute_data *call, zend_jit_trace_rec *trace_buffer, int idx, uint32_t is_megamorphic, uint32_t *megamorphic, uint32_t level, uint32_t init_level, uint32_t *call_level)
452+
#define ZEND_CALL_MEGAMORPHIC ZEND_CALL_JIT_RESERVED
453+
454+
static int zend_jit_trace_record_fake_init_call_ex(zend_execute_data *call, zend_jit_trace_rec *trace_buffer, int idx, uint32_t is_megamorphic, uint32_t init_level)
453455
{
454456
zend_jit_trace_stop stop ZEND_ATTRIBUTE_UNUSED = ZEND_JIT_TRACE_STOP_ERROR;
455457

@@ -458,7 +460,7 @@ static int zend_jit_trace_record_fake_init_call_ex(zend_execute_data *call, zend
458460
zend_jit_op_array_trace_extension *jit_extension;
459461

460462
if (call->prev_execute_data) {
461-
idx = zend_jit_trace_record_fake_init_call_ex(call->prev_execute_data, trace_buffer, idx, is_megamorphic, megamorphic, level, init_level + 1, call_level);
463+
idx = zend_jit_trace_record_fake_init_call_ex(call->prev_execute_data, trace_buffer, idx, is_megamorphic, init_level + 1);
462464
if (idx < 0) {
463465
return idx;
464466
}
@@ -489,32 +491,16 @@ static int zend_jit_trace_record_fake_init_call_ex(zend_execute_data *call, zend
489491
&& ((ZEND_CALL_INFO(call) & ZEND_CALL_DYNAMIC)
490492
|| func->common.scope)) {
491493
func = NULL;
492-
*megamorphic |= (1 << (level + *call_level));
493-
} else {
494-
*megamorphic &= ~(1 << (level + *call_level));
494+
ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_MEGAMORPHIC);
495495
}
496-
(*call_level)++;
497496
TRACE_RECORD(ZEND_JIT_TRACE_INIT_CALL, ZEND_JIT_TRACE_FAKE_INFO(init_level), func);
498497
} while (0);
499498
return idx;
500499
}
501500

502-
static int zend_jit_trace_record_fake_init_call(zend_execute_data *call, zend_jit_trace_rec *trace_buffer, int idx, uint32_t is_megamorphic, uint32_t *megamorphic, uint32_t level)
501+
static int zend_jit_trace_record_fake_init_call(zend_execute_data *call, zend_jit_trace_rec *trace_buffer, int idx, uint32_t is_megamorphic)
503502
{
504-
uint32_t call_level = 0;
505-
506-
return zend_jit_trace_record_fake_init_call_ex(call, trace_buffer, idx, is_megamorphic, megamorphic, level, 0, &call_level);
507-
}
508-
509-
static int zend_jit_trace_call_level(const zend_execute_data *call)
510-
{
511-
int call_level = 0;
512-
513-
while (call->prev_execute_data) {
514-
call_level++;
515-
call = call->prev_execute_data;
516-
}
517-
return call_level;
503+
return zend_jit_trace_record_fake_init_call_ex(call, trace_buffer, idx, is_megamorphic, 0);
518504
}
519505

520506
static int zend_jit_trace_subtrace(zend_jit_trace_rec *trace_buffer, int start, int end, uint8_t event, const zend_op_array *op_array, const zend_op *opline)
@@ -568,7 +554,6 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
568554
zend_jit_trace_stop halt = 0;
569555
int level = 0;
570556
int ret_level = 0;
571-
int call_level;
572557
zend_vm_opcode_handler_t handler;
573558
const zend_op_array *op_array;
574559
zend_jit_op_array_trace_extension *jit_extension;
@@ -585,7 +570,6 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
585570
int last_loop = -1;
586571
int last_loop_level = -1;
587572
const zend_op *last_loop_opline = NULL;
588-
uint32_t megamorphic = 0;
589573
const zend_op_array *unrolled_calls[ZEND_JIT_TRACE_MAX_CALL_DEPTH + ZEND_JIT_TRACE_MAX_RET_DEPTH];
590574
#ifdef HAVE_GCC_GLOBAL_REGS
591575
zend_execute_data *prev_execute_data = ex;
@@ -623,7 +607,7 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
623607
}
624608

625609
if (prev_call) {
626-
int ret = zend_jit_trace_record_fake_init_call(prev_call, trace_buffer, idx, is_megamorphic, &megamorphic, ret_level + level);
610+
int ret = zend_jit_trace_record_fake_init_call(prev_call, trace_buffer, idx, is_megamorphic);
627611
if (ret < 0) {
628612
TRACE_END(ZEND_JIT_TRACE_END, ZEND_JIT_TRACE_STOP_BAD_FUNC, opline);
629613
#ifdef HAVE_GCC_GLOBAL_REGS
@@ -831,8 +815,7 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
831815
|| opline->opcode == ZEND_DO_ICALL
832816
|| opline->opcode == ZEND_DO_UCALL
833817
|| opline->opcode == ZEND_DO_FCALL_BY_NAME) {
834-
call_level = zend_jit_trace_call_level(EX(call));
835-
if (megamorphic & (1 << (ret_level + level + call_level))) {
818+
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_MEGAMORPHIC) {
836819
stop = ZEND_JIT_TRACE_STOP_INTERPRETER;
837820
break;
838821
}
@@ -962,7 +945,7 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
962945
last_loop_opline = NULL;
963946

964947
if (prev_call) {
965-
int ret = zend_jit_trace_record_fake_init_call(prev_call, trace_buffer, idx, 0, &megamorphic, ret_level + level);
948+
int ret = zend_jit_trace_record_fake_init_call(prev_call, trace_buffer, idx, 0);
966949
if (ret < 0) {
967950
stop = ZEND_JIT_TRACE_STOP_BAD_FUNC;
968951
break;
@@ -1045,12 +1028,8 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
10451028
&& trace_buffer[1].opline == opline - 1) {
10461029
func = NULL;
10471030
}
1048-
call_level = zend_jit_trace_call_level(EX(call));
1049-
ZEND_ASSERT(ret_level + level + call_level < 32);
1050-
if (func) {
1051-
megamorphic &= ~(1 << (ret_level + level + call_level));
1052-
} else {
1053-
megamorphic |= (1 << (ret_level + level + call_level));
1031+
if (!func) {
1032+
ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_MEGAMORPHIC);
10541033
}
10551034
TRACE_RECORD(ZEND_JIT_TRACE_INIT_CALL, 0, func);
10561035
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
JIT INIT_FCALL: 001 too deep nesting level
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.file_update_protection=0
7+
opcache.jit_buffer_size=1M
8+
--FILE--
9+
<?php
10+
ini_set(ini_set(ini_set(ini_set(ini_set(ini_set(ini_set(ini_set(ini_set(
11+
ini_set(ini_set(ini_set(ini_set(ini_set(ini_set(ini_set(ini_set(ini_set(
12+
ini_set(ini_set(ini_set(ini_set(ini_set(ini_set(ini_set(ini_set(ini_set(
13+
ini_set(ini_set(ini_set(ini_set(ini_set(ini_set(
14+
)))))))))))))))))))))))))))))))));
15+
?>
16+
--EXPECTF--
17+
Fatal error: Uncaught ArgumentCountError: ini_set() expects exactly 2 arguments, 0 given in %sinit_fcall_001.php:5
18+
Stack trace:
19+
#0 %sinit_fcall_001.php(5): ini_set()
20+
#1 {main}
21+
thrown in %sinit_fcall_001.php on line 5
22+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
--TEST--
2+
JIT INIT_FCALL: 002 incorrect megamorphic call detection
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.file_update_protection=0
7+
opcache.jit_buffer_size=1M
8+
opcache.jit=tracing
9+
opcache.jit_max_polymorphic_calls=0
10+
--FILE--
11+
<?php
12+
class C {
13+
function foo($x) {
14+
return $x;
15+
}
16+
}
17+
function foo($x) {
18+
return $x;
19+
}
20+
function test2($x) {
21+
return foo(foo($x));
22+
}
23+
function test1() {
24+
$x = new C;
25+
foo(foo($x->foo(foo(test2($x)))));
26+
}
27+
test1();
28+
?>
29+
DONE
30+
--EXPECT--
31+
DONE

0 commit comments

Comments
 (0)