[vm,dyn_modules] Fix single-target cid range dispatch for dynamically loaded classes

In AOT mode, when call site is transitioned from monomorphic state
(with receiver cid1) to polymorphic (with receiver cid2),
there is an optimization which checks if all _allocated_ classes
in the class id range cid1..cid2 have the same dispatch target.
If so, a specialized SingleTargetCall stub is used.

The problem is that 'allocated' bit is only set during precompilation,
and dynamically loaded classes were not considered as valid receiver
classes by this optimization.

As a result, the following situation could happen:
cid1 < cid3 < cid2,
cid1 dispatches to target1
cid2 dispatches to target1
cid3 should dispatch to target2, but it is still in range cid1..cid2 and
SingleTargetCall stub would incorrectly dispatch it to target1.

The fix is to treat all dynamically loaded classes as allocated when
checking for single target optimization.

TEST=pkg/dynamic_modules/test/data/single_target_cid_range_dispatch
Fixes b/493677699

Change-Id: I42e407385a5d9b0a4a1017f713b47587c3c6a818
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/488920
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
This commit is contained in:
Alexander Markov
2026-03-19 06:12:41 -07:00
committed by Commit Queue
parent aa3665ed78
commit efce7c1cb0
5 changed files with 83 additions and 1 deletions
+1 -1
View File
@@ -2559,7 +2559,7 @@ static bool IsSingleTarget(IsolateGroup* isolate_group,
if (!table->HasValidClassAt(cid)) continue;
cls = table->At(cid);
if (cls.is_abstract()) continue;
if (!cls.is_allocated()) continue;
if (!cls.is_allocated() && !cls.is_declared_in_bytecode()) continue;
other_target = Resolver::ResolveDynamicAnyArgs(zone, cls, name,
/*allow_add=*/false);
if (other_target.ptr() != target.ptr()) {