Skip to content

Commit b931cfa

Browse files
committed
Improve the optimizer's check if a function is a prototype or not
Currently, a function is considered a prototype if the function is not marked as final. However, a class marked as final or an anonymous class also make it impossible for a function to be overridden. Therefore, we know in these 2 cases 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.
1 parent d5ce616 commit b931cfa

File tree

2 files changed

+51
-5
lines changed

2 files changed

+51
-5
lines changed

Zend/Optimizer/zend_optimizer.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -891,16 +891,20 @@ 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+
bool can_be_overridden = (fbc->common.fn_flags & ZEND_ACC_FINAL) == 0 &&
904+
(fbc->common.scope->ce_flags & ZEND_ACC_FINAL) == 0;
905+
if (can_be_overridden) {
906+
*is_prototype = true;
907+
}
904908
return fbc;
905909
}
906910
}
Lines changed: 42 additions & 0 deletions
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)