Skip to content

Commit 1ee5ab4

Browse files
committed
zend_compile: Optimize arguments for ZEND_NEW
Apply the optimization for static method calls to `new` calls, since `new` is effectively a static method for all intents and purposes. For: <?php final class MyClass { private function __construct( private \Random\Engine $foo, private int $bar = 0, ) {} public static function new(int $bar): self { $engine = new \Random\Engine\Xoshiro256StarStar(seed: 123); return new self(foo: $engine, bar: $bar); } } for ($i = 0; $i < 3_000_000; $i++) { MyClass::new($i); } This is ~1.13 faster for a gcc 13.3 release build on a Intel(R) Core(TM) i7-1365U. Benchmark 1: /tmp/bench/php.old /tmp/bench/test6.php Time (mean ± σ): 409.5 ms ± 1.9 ms [User: 406.6 ms, System: 2.2 ms] Range (min … max): 407.4 ms … 414.0 ms 10 runs Benchmark 2: /tmp/bench/php.new /tmp/bench/test6.php Time (mean ± σ): 360.9 ms ± 1.7 ms [User: 358.5 ms, System: 2.2 ms] Range (min … max): 359.2 ms … 365.0 ms 10 runs Summary /tmp/bench/php.new /tmp/bench/test6.php ran 1.13 ± 0.01 times faster than /tmp/bench/php.old /tmp/bench/test6.php
1 parent 297a323 commit 1ee5ab4

File tree

3 files changed

+32
-5
lines changed

3 files changed

+32
-5
lines changed

Zend/zend_compile.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5497,7 +5497,34 @@ static void zend_compile_new(znode *result, zend_ast *ast) /* {{{ */
54975497
opline->op2.num = zend_alloc_cache_slot();
54985498
}
54995499

5500-
zend_compile_call_common(&ctor_result, args_ast, NULL, ast->lineno);
5500+
zend_class_entry *ce = NULL;
5501+
zend_function *fbc = NULL;
5502+
if (opline->op1_type == IS_CONST) {
5503+
zend_string *lcname = Z_STR_P(CT_CONSTANT(opline->op1) + 1);
5504+
ce = zend_hash_find_ptr(CG(class_table), lcname);
5505+
if (ce) {
5506+
if (zend_compile_ignore_class(ce, CG(active_op_array)->filename)) {
5507+
ce = NULL;
5508+
}
5509+
} else if (CG(active_class_entry)
5510+
&& zend_string_equals_ci(CG(active_class_entry)->name, lcname)) {
5511+
ce = CG(active_class_entry);
5512+
}
5513+
} else if (opline->op1_type == IS_UNUSED
5514+
&& (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF
5515+
&& zend_is_scope_known()) {
5516+
ce = CG(active_class_entry);
5517+
}
5518+
if (
5519+
ce
5520+
&& ce->default_object_handlers->get_constructor == zend_std_get_constructor
5521+
&& ce->constructor
5522+
&& is_func_accessible(ce->constructor)
5523+
) {
5524+
fbc = ce->constructor;
5525+
}
5526+
5527+
zend_compile_call_common(&ctor_result, args_ast, fbc, ast->lineno);
55015528
zend_do_free(&ctor_result);
55025529
}
55035530
/* }}} */

ext/opcache/tests/opt/gh18107_1.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ $_main:
3030
0000 T1 = ISSET_ISEMPTY_CV (isset) CV0($badvar)
3131
0001 JMPNZ T1 0006
3232
0002 V3 = NEW 1 string("Exception")
33-
0003 SEND_VAL_EX string("Should happen") 1
33+
0003 SEND_VAL%S string("Should happen") 1
3434
0004 DO_FCALL
3535
0005 THROW V3
3636
0006 JMP 0006
3737
0007 V6 = NEW 1 string("Exception")
38-
0008 SEND_VAL_EX string("Should not happen") 1
38+
0008 SEND_VAL%S string("Should not happen") 1
3939
0009 DO_FCALL
4040
0010 THROW V6
4141
0011 FAST_RET T5

ext/opcache/tests/opt/gh18107_2.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ $_main:
3333
0000 T2 = ISSET_ISEMPTY_CV (isset) CV0($badvar)
3434
0001 JMPNZ T2 0008
3535
0002 V4 = NEW 1 string("Exception")
36-
0003 SEND_VAL_EX string("Should happen") 1
36+
0003 SEND_VAL%S string("Should happen") 1
3737
0004 DO_FCALL
3838
0005 THROW V4
3939
0006 CV1($e) = CATCH string("Throwable")
4040
0007 ECHO string("foo")
4141
0008 T6 = FAST_CALL 0010
4242
0009 JMP 0015
4343
0010 V7 = NEW 1 string("Exception")
44-
0011 SEND_VAL_EX string("Should not happen") 1
44+
0011 SEND_VAL%S string("Should not happen") 1
4545
0012 DO_FCALL
4646
0013 THROW V7
4747
0014 FAST_RET T6

0 commit comments

Comments
 (0)