Skip to content

Commit a30fab5

Browse files
committed
Make can_elide_return_type_check() more robust
Rather than using def_info, check against the actual arg_info type. As it is stored as a type mask nowadays, this is not much harder, but more general and more robust as we don't need to deal with inaccurate cases.
1 parent 0d9269d commit a30fab5

File tree

2 files changed

+40
-19
lines changed

2 files changed

+40
-19
lines changed

Zend/Optimizer/dfa_pass.c

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -291,34 +291,41 @@ static bool safe_instanceof(zend_class_entry *ce1, zend_class_entry *ce2) {
291291
}
292292

293293
static inline bool can_elide_return_type_check(
294-
zend_op_array *op_array, zend_ssa *ssa, zend_ssa_op *ssa_op) {
295-
zend_arg_info *info = &op_array->arg_info[-1];
294+
const zend_script *script, zend_op_array *op_array, zend_ssa *ssa, zend_ssa_op *ssa_op) {
295+
zend_arg_info *arg_info = &op_array->arg_info[-1];
296296
zend_ssa_var_info *use_info = &ssa->var_info[ssa_op->op1_use];
297-
zend_ssa_var_info *def_info = &ssa->var_info[ssa_op->op1_def];
298-
299-
/* TODO: It would be better to rewrite this without using def_info,
300-
* which may not be an exact representation of the type. */
301-
if (use_info->type & MAY_BE_REF) {
297+
uint32_t use_type = use_info->type & (MAY_BE_ANY|MAY_BE_UNDEF);
298+
if (use_type & MAY_BE_REF) {
302299
return 0;
303300
}
304301

305-
/* A type is possible that is not in the allowed types */
306-
if ((use_info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) & ~(def_info->type & MAY_BE_ANY)) {
307-
return 0;
302+
if (use_type & MAY_BE_UNDEF) {
303+
use_type &= ~MAY_BE_UNDEF;
304+
use_type |= MAY_BE_NULL;
308305
}
309306

310-
/* These types are not represented exactly */
311-
if (ZEND_TYPE_FULL_MASK(info->type) & (MAY_BE_CALLABLE|MAY_BE_ITERABLE|MAY_BE_STATIC)) {
312-
return 0;
307+
uint32_t disallowed_types = use_type & ~ZEND_TYPE_PURE_MASK(arg_info->type);
308+
if (!disallowed_types) {
309+
/* Only contains allowed types. */
310+
return true;
313311
}
314312

315-
if (ZEND_TYPE_HAS_CLASS(info->type)) {
316-
if (!use_info->ce || !def_info->ce || !safe_instanceof(use_info->ce, def_info->ce)) {
317-
return 0;
318-
}
313+
if (disallowed_types == MAY_BE_OBJECT && use_info->ce && ZEND_TYPE_HAS_CLASS(arg_info->type)) {
314+
zend_type *single_type;
315+
ZEND_TYPE_FOREACH(arg_info->type, single_type) {
316+
if (ZEND_TYPE_HAS_NAME(*single_type)) {
317+
zend_string *lcname = zend_string_tolower(ZEND_TYPE_NAME(*single_type));
318+
zend_class_entry *ce = zend_optimizer_get_class_entry(script, lcname);
319+
zend_string_release(lcname);
320+
if (ce && safe_instanceof(use_info->ce, ce)) {
321+
/* One of the class union types matched. */
322+
return true;
323+
}
324+
}
325+
} ZEND_TYPE_FOREACH_END();
319326
}
320327

321-
return 1;
328+
return false;
322329
}
323330

324331
static bool opline_supports_assign_contraction(
@@ -1235,7 +1242,7 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
12351242
&& ssa->ops[op_1].op1_def == v
12361243
&& ssa->ops[op_1].op1_use >= 0
12371244
&& ssa->ops[op_1].op1_use_chain == -1
1238-
&& can_elide_return_type_check(op_array, ssa, &ssa->ops[op_1])) {
1245+
&& can_elide_return_type_check(ctx->script, op_array, ssa, &ssa->ops[op_1])) {
12391246

12401247
// op_1: VERIFY_RETURN_TYPE #orig_var.? [T] -> #v.? [T] => NOP
12411248

ext/opcache/tests/opt/verify_return_type.phpt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ class Test3 {
4747
}
4848
}
4949

50+
function getClassUnion(): stdClass|FooBar {
51+
return new stdClass;
52+
}
53+
5054
?>
5155
--EXPECTF--
5256
$_main:
@@ -55,6 +59,16 @@ $_main:
5559
; %s
5660
0000 RETURN int(1)
5761

62+
getClassUnion:
63+
; (lines=3, args=0, vars=0, tmps=1)
64+
; (after optimizer)
65+
; %s
66+
0000 V0 = NEW 0 string("stdClass")
67+
0001 DO_FCALL
68+
0002 RETURN V0
69+
LIVE RANGES:
70+
0: 0001 - 0002 (new)
71+
5872
Test1::getIntOrFloat:
5973
; (lines=2, args=1, vars=1, tmps=0)
6074
; (after optimizer)

0 commit comments

Comments
 (0)