Skip to content

Commit 2e78c08

Browse files
authored
Improve the optimizer's check if a function is a prototype or not (#10467)
Currently, a function is considered a prototype if the function is not marked as final. However, a class marked as final also make it impossible for a function to be overridden. Therefore, we know in this case too that the function is not a prototype. This allows the type inference algorithm to determine some types more precisely, and can allow for more optimizations of the instructions. Additionally, place some computation of the flags in their respective blocks as a micro-optimization. Note: anonymous classes *can* be extended (see test Zend/tests/anon/011.phpt). Therefore we don't optimize this case.
1 parent b578f69 commit 2e78c08

File tree

2 files changed

+50
-5
lines changed

2 files changed

+50
-5
lines changed

Zend/Optimizer/zend_optimizer.c

+8-5
Original file line numberDiff line numberDiff line change
@@ -891,16 +891,19 @@ zend_function *zend_optimizer_get_called_func(
891891
&op_array->scope->function_table, method_name);
892892
if (fbc) {
893893
bool is_private = (fbc->common.fn_flags & ZEND_ACC_PRIVATE) != 0;
894-
bool is_final = (fbc->common.fn_flags & ZEND_ACC_FINAL) != 0;
895-
bool same_scope = fbc->common.scope == op_array->scope;
896894
if (is_private) {
897895
/* Only use private method if in the same scope. We can't even use it
898896
* as a prototype, as it may be overridden with changed signature. */
897+
bool same_scope = fbc->common.scope == op_array->scope;
899898
return same_scope ? fbc : NULL;
900899
}
901-
/* If the method is non-final, it may be overridden,
902-
* but only with a compatible method signature. */
903-
*is_prototype = !is_final;
900+
/* Prototype methods are potentially overridden. fbc still contains useful type information.
901+
* Some optimizations may not be applied, like inlining or inferring the send-mode of superfluous args.
902+
* A method cannot be overridden if the class or method is final. */
903+
if ((fbc->common.fn_flags & ZEND_ACC_FINAL) == 0 &&
904+
(fbc->common.scope->ce_flags & ZEND_ACC_FINAL) == 0) {
905+
*is_prototype = true;
906+
}
904907
return fbc;
905908
}
906909
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
--TEST--
2+
Type inference test with final class
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.optimization_level=-1
7+
opcache.opt_debug_level=0x20000
8+
opcache.preload=
9+
--EXTENSIONS--
10+
opcache
11+
--FILE--
12+
<?php
13+
14+
final class Test {
15+
public function getInt(): int {
16+
return 42;
17+
}
18+
public function getInt2(): int {
19+
return $this->getInt();
20+
}
21+
}
22+
23+
?>
24+
--EXPECTF--
25+
$_main:
26+
; (lines=1, args=0, vars=0, tmps=0)
27+
; (after optimizer)
28+
; %s
29+
0000 RETURN int(1)
30+
31+
Test::getInt:
32+
; (lines=1, args=0, vars=0, tmps=0)
33+
; (after optimizer)
34+
; %s
35+
0000 RETURN int(42)
36+
37+
Test::getInt2:
38+
; (lines=2, args=0, vars=0, tmps=1)
39+
; (after optimizer)
40+
; %s
41+
0000 V0 = QM_ASSIGN int(42)
42+
0001 RETURN V0

0 commit comments

Comments
 (0)