Skip to content

Commit 7103d43

Browse files
fishythefishCommit Queue
authored andcommitted
[dart2js] Add powerset bits for interceptor domain.
Change-Id: Id9509c6b6eb8143263763e508512c0703d4aa493 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/404500 Reviewed-by: Stephen Adams <[email protected]> Commit-Queue: Mayank Patke <[email protected]>
1 parent 76606ca commit 7103d43

File tree

165 files changed

+4584
-4311
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

165 files changed

+4584
-4311
lines changed

pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart

Lines changed: 96 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class FlatTypeMask extends TypeMask {
3737
_getPowerset(_Flags(a.bitset.union(b.bitset)));
3838

3939
static Bitset _powersetOfFlagsIntersection(_Flags a, _Flags b) =>
40-
_getPowerset(_Flags(a.bitset.intersection(b.bitset)));
40+
_getPowerset(_Flags(_intersectPowersets(a.bitset, b.bitset)));
4141

4242
static FlatTypeMaskKind _getKind(_Flags flags) =>
4343
FlatTypeMaskKind.values[flags.bitset.bits >> _powersetDomains.bitWidth];
@@ -92,6 +92,15 @@ class FlatTypeMask extends TypeMask {
9292
domain,
9393
);
9494

95+
factory FlatTypeMask._emptyOrSpecial(CommonMasks domain, Bitset powerset) {
96+
assert(_isEmptyOrSpecialPowerset(powerset));
97+
return FlatTypeMask._cached(
98+
null,
99+
_computeFlags(FlatTypeMaskKind.empty, powerset),
100+
domain,
101+
);
102+
}
103+
95104
factory FlatTypeMask.nonNullEmpty(
96105
CommonMasks domain, {
97106
bool hasLateSentinel = false,
@@ -100,11 +109,8 @@ class FlatTypeMask extends TypeMask {
100109
hasLateSentinel
101110
? _specialValueDomain.fromValue(TypeMaskSpecialValue.lateSentinel)
102111
: Bitset.empty();
103-
return FlatTypeMask._cached(
104-
null,
105-
_computeFlags(FlatTypeMaskKind.empty, powerset),
106-
domain,
107-
);
112+
113+
return FlatTypeMask._emptyOrSpecial(domain, powerset);
108114
}
109115

110116
factory FlatTypeMask.empty(
@@ -115,13 +121,9 @@ class FlatTypeMask extends TypeMask {
115121
hasLateSentinel
116122
? _specialValueDomain.allValues
117123
: _specialValueDomain.fromValue(TypeMaskSpecialValue.null_);
118-
return FlatTypeMask._cached(
119-
null,
120-
_computeFlags(FlatTypeMaskKind.empty, powerset),
121-
domain,
122-
);
123-
}
124124

125+
return FlatTypeMask._emptyOrSpecial(domain, powerset);
126+
}
125127
factory FlatTypeMask.nonNullExact(
126128
ClassEntity base,
127129
CommonMasks domain, {
@@ -175,7 +177,16 @@ class FlatTypeMask extends TypeMask {
175177
),
176178
);
177179
}
178-
var powerset = _specialValueDomain.fromEnumSet(specialValues);
180+
181+
final probe = domain._powersetCache[base];
182+
final powerset = switch (kind) {
183+
FlatTypeMaskKind.empty =>
184+
throw StateError('Unexpected empty kind with base $base'),
185+
FlatTypeMaskKind.exact => probe.exact,
186+
FlatTypeMaskKind.subclass => probe.subclass,
187+
FlatTypeMaskKind.subtype => probe.subtype,
188+
}.union(_specialValueDomain.fromEnumSet(specialValues));
189+
179190
return FlatTypeMask._cached(base, _computeFlags(kind, powerset), domain);
180191
}
181192

@@ -196,11 +207,13 @@ class FlatTypeMask extends TypeMask {
196207
/// Ensures that the generated mask is normalized, i.e., a call to
197208
/// [TypeMask.assertIsNormalized] with the factory's result returns `true`.
198209
factory FlatTypeMask.normalized(
199-
ClassEntity? base,
210+
ClassEntity base,
200211
FlatTypeMaskKind kind,
201212
Bitset powerset,
202213
CommonMasks domain,
203214
) {
215+
assert(kind != FlatTypeMaskKind.empty);
216+
assert(!_isEmptyOrSpecialPowerset(powerset));
204217
if (base == domain.commonElements.nullClass) {
205218
return FlatTypeMask.empty(
206219
domain,
@@ -210,16 +223,16 @@ class FlatTypeMask extends TypeMask {
210223
),
211224
);
212225
}
213-
if (kind == FlatTypeMaskKind.empty || kind == FlatTypeMaskKind.exact) {
226+
if (kind == FlatTypeMaskKind.exact) {
214227
return FlatTypeMask._cached(base, _computeFlags(kind, powerset), domain);
215228
}
216229
if (kind == FlatTypeMaskKind.subtype) {
217-
if (!domain.closedWorld.classHierarchy.hasAnyStrictSubtype(base!) ||
230+
if (!domain.closedWorld.classHierarchy.hasAnyStrictSubtype(base) ||
218231
domain.closedWorld.classHierarchy.hasOnlySubclasses(base)) {
219232
kind = FlatTypeMaskKind.subclass;
220233
}
221234
} else if (kind == FlatTypeMaskKind.subclass &&
222-
!domain.closedWorld.classHierarchy.hasAnyStrictSubclass(base!)) {
235+
!domain.closedWorld.classHierarchy.hasAnyStrictSubclass(base)) {
223236
kind = FlatTypeMaskKind.exact;
224237
}
225238
final flags = _computeFlags(kind, powerset);
@@ -518,7 +531,7 @@ class FlatTypeMask extends TypeMask {
518531
// If we weaken the constraint on this type, we have to make sure that
519532
// the result is normalized.
520533
return FlatTypeMask.normalized(
521-
base,
534+
base!,
522535
combinedKind,
523536
combinedPowerset,
524537
domain,
@@ -537,11 +550,16 @@ class FlatTypeMask extends TypeMask {
537550
? this
538551
// If we weaken the constraint on this type, we have to make sure that
539552
// the result is normalized.
540-
: FlatTypeMask.normalized(base, combinedKind, combinedPowerset, domain);
553+
: FlatTypeMask.normalized(
554+
base!,
555+
combinedKind,
556+
combinedPowerset,
557+
domain,
558+
);
541559
}
542560

543561
@override
544-
TypeMask intersection(TypeMask other, CommonMasks domain) {
562+
TypeMask _nonEmptyIntersection(TypeMask other, CommonMasks domain) {
545563
return (domain._intersectionCache[this] ??= {})[other] ??= _intersection(
546564
other,
547565
domain,
@@ -551,8 +569,10 @@ class FlatTypeMask extends TypeMask {
551569
TypeMask _intersection(TypeMask other, CommonMasks domain) {
552570
if (other is! FlatTypeMask) return other.intersection(this, domain);
553571

554-
final otherBase = other.base;
555572
final powerset = _powersetOfFlagsIntersection(_flags, other._flags);
573+
assert(!isEmptyOrSpecial);
574+
assert(!other.isEmptyOrSpecial);
575+
556576
final includeNull = _specialValueDomain.contains(
557577
powerset,
558578
TypeMaskSpecialValue.null_,
@@ -562,16 +582,10 @@ class FlatTypeMask extends TypeMask {
562582
TypeMaskSpecialValue.lateSentinel,
563583
);
564584

565-
if (isEmptyOrSpecial) {
566-
return withPowerset(powerset, domain);
567-
} else if (other.isEmptyOrSpecial) {
568-
return other.withPowerset(powerset, domain);
569-
}
570-
571585
SubclassResult result = domain.closedWorld.classHierarchy.commonSubclasses(
572586
base!,
573587
_classQuery,
574-
otherBase!,
588+
other.base!,
575589
other._classQuery,
576590
);
577591

@@ -637,20 +651,18 @@ class FlatTypeMask extends TypeMask {
637651
}
638652

639653
@override
640-
bool isDisjoint(TypeMask other, JClosedWorld closedWorld) {
641-
if (other is! FlatTypeMask) return other.isDisjoint(this, closedWorld);
642-
FlatTypeMask flatOther = other;
643-
644-
if (isNullable && flatOther.isNullable) return false;
645-
if (hasLateSentinel && flatOther.hasLateSentinel) return false;
646-
if (isEmptyOrSpecial || flatOther.isEmptyOrSpecial) return true;
647-
if (base == flatOther.base) return false;
648-
if (isExact && flatOther.isExact) return true;
649-
650-
if (isExact) return !flatOther.contains(base!, closedWorld);
651-
if (flatOther.isExact) return !contains(flatOther.base!, closedWorld);
654+
bool _isNonTriviallyDisjoint(TypeMask other, JClosedWorld closedWorld) {
655+
if (other is! FlatTypeMask) {
656+
return other._isNonTriviallyDisjoint(this, closedWorld);
657+
}
658+
659+
if (base == other.base) return false;
660+
if (isExact && other.isExact) return true;
661+
662+
if (isExact) return !other.contains(base!, closedWorld);
663+
if (other.isExact) return !contains(other.base!, closedWorld);
652664
final thisBase = base!;
653-
final otherBase = flatOther.base!;
665+
final otherBase = other.base!;
654666

655667
// Normalization guarantees that isExact === !isSubclass && !isSubtype.
656668
// Both are subclass or subtype masks, so if there is a subclass
@@ -664,9 +676,9 @@ class FlatTypeMask extends TypeMask {
664676

665677
// Two different base classes have no common subclass unless one is a
666678
// subclass of the other (checked above).
667-
if (isSubclass && flatOther.isSubclass) return true;
679+
if (isSubclass && other.isSubclass) return true;
668680

669-
return _isDisjointHelper(this, flatOther, closedWorld);
681+
return _isDisjointHelper(this, other, closedWorld);
670682
}
671683

672684
static bool _isDisjointHelper(
@@ -692,59 +704,6 @@ class FlatTypeMask extends TypeMask {
692704
return true;
693705
}
694706

695-
TypeMask intersectionSame(FlatTypeMask other, CommonMasks domain) {
696-
assert(base == other.base);
697-
// The two masks share the base type, so we must chose the most
698-
// constraining kind (the lowest) of the two. The result will be normalized,
699-
// as the two inputs are normalized, too.
700-
final combined = _Flags(
701-
(_flags.bitset.bits < other._flags.bitset.bits)
702-
? _flags.bitset.intersection(
703-
other._flags.bitset.union(_powersetDomains.notMask),
704-
)
705-
: other._flags.bitset.intersection(
706-
_flags.bitset.union(_powersetDomains.notMask),
707-
),
708-
);
709-
710-
if (_flags == combined) {
711-
return this;
712-
} else if (other._flags == combined) {
713-
return other;
714-
} else {
715-
return FlatTypeMask._cached(base, combined, domain);
716-
}
717-
}
718-
719-
TypeMask intersectionStrictSubclass(FlatTypeMask other, CommonMasks domain) {
720-
assert(base != other.base);
721-
assert(domain.closedWorld.classHierarchy.isSubclassOf(other.base!, base!));
722-
// If this mask isn't at least a subclass mask, then the
723-
// intersection with the other mask is empty.
724-
if (isExact) return intersectionEmpty(other, domain);
725-
// Only the other mask puts constraints on the intersection mask,
726-
// so base the combined flags on the other mask. The result is guaranteed to
727-
// be normalized, as the other type was normalized.
728-
final combined = _Flags(
729-
other._flags.bitset.intersection(
730-
_flags.bitset.union(_powersetDomains.notMask),
731-
),
732-
);
733-
if (other._flags == combined) {
734-
return other;
735-
} else {
736-
return FlatTypeMask._cached(other.base, combined, domain);
737-
}
738-
}
739-
740-
TypeMask intersectionEmpty(FlatTypeMask other, CommonMasks domain) {
741-
bool isNullable = this.isNullable && other.isNullable;
742-
bool hasLateSentinel = this.hasLateSentinel && other.hasLateSentinel;
743-
return isNullable
744-
? TypeMask.empty(domain, hasLateSentinel: hasLateSentinel)
745-
: TypeMask.nonNullEmpty(domain, hasLateSentinel: hasLateSentinel);
746-
}
747-
748707
@override
749708
bool canHit(MemberEntity element, Name name, CommonMasks domain) {
750709
final closedWorld = domain.closedWorld;
@@ -913,3 +872,44 @@ class FlatTypeMask extends TypeMask {
913872
return buffer.toString();
914873
}
915874
}
875+
876+
typedef _CachedPowersets = ({Bitset exact, Bitset subclass, Bitset subtype});
877+
878+
class _PowersetCache {
879+
final ClassHierarchy _classHierarchy;
880+
final Set<ClassEntity> _interceptorCone;
881+
final Map<ClassEntity, _CachedPowersets> _cache = {};
882+
883+
_PowersetCache(JClosedWorld closedWorld)
884+
: _classHierarchy = closedWorld.classHierarchy,
885+
_interceptorCone =
886+
closedWorld.classHierarchy
887+
.subclassesOf(closedWorld.commonElements.jsInterceptorClass)
888+
.toSet();
889+
890+
_CachedPowersets operator [](ClassEntity cls) => _cache.putIfAbsent(cls, () {
891+
var exactPowerset = Bitset.empty();
892+
exactPowerset = _interceptorDomain.add(
893+
exactPowerset,
894+
_interceptorCone.contains(cls)
895+
? TypeMaskInterceptorProperty.interceptor
896+
: TypeMaskInterceptorProperty.notInterceptor,
897+
);
898+
899+
var subclassPowerset = exactPowerset;
900+
for (final subclass in _classHierarchy.strictSubclassesOf(cls)) {
901+
subclassPowerset = subclassPowerset.union(this[subclass].subclass);
902+
}
903+
904+
var subtypePowerset = exactPowerset;
905+
for (final subtype in _classHierarchy.strictSubtypesOf(cls)) {
906+
subtypePowerset = subtypePowerset.union(this[subtype].subtype);
907+
}
908+
909+
return (
910+
exact: exactPowerset,
911+
subclass: subclassPowerset,
912+
subtype: subtypePowerset,
913+
);
914+
});
915+
}

pkg/compiler/lib/src/inferrer/typemasks/forwarding_type_mask.dart

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,16 @@ abstract class ForwardingTypeMask extends TypeMask {
102102
) => null;
103103

104104
@override
105-
bool isDisjoint(TypeMask other, JClosedWorld closedWorld) {
106-
return forwardTo.isDisjoint(other, closedWorld);
105+
bool _isNonTriviallyDisjoint(TypeMask other, JClosedWorld closedWorld) {
106+
return forwardTo._isNonTriviallyDisjoint(other, closedWorld);
107107
}
108108

109109
@override
110-
TypeMask intersection(TypeMask other, CommonMasks domain) {
111-
TypeMask forwardIntersection = forwardTo.intersection(other, domain);
110+
TypeMask _nonEmptyIntersection(TypeMask other, CommonMasks domain) {
111+
TypeMask forwardIntersection = forwardTo._nonEmptyIntersection(
112+
other,
113+
domain,
114+
);
112115
if (forwardIntersection.isEmptyOrSpecial) return forwardIntersection;
113116
return withPowerset(forwardIntersection.powerset, domain);
114117
}

pkg/compiler/lib/src/inferrer/typemasks/masks.dart

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ class CommonMasks with AbstractValueDomain {
4747
// TODO(sigmund): once we split out the backend common elements, depend
4848
// directly on those instead.
4949
final JClosedWorld closedWorld;
50+
final _PowersetCache _powersetCache;
5051

51-
CommonMasks(this.closedWorld);
52+
CommonMasks(this.closedWorld) : _powersetCache = _PowersetCache(closedWorld);
5253

5354
ClassHierarchy get classHierarchy => closedWorld.classHierarchy;
5455
CommonElements get commonElements => closedWorld.commonElements;
@@ -907,28 +908,22 @@ class CommonMasks with AbstractValueDomain {
907908

908909
@override
909910
AbstractBool isInterceptor(TypeMask value) {
910-
// TODO(39874): Remove cache when [TypeMask.isDisjoint] is faster.
911-
var result = _isInterceptorCache[value];
912-
if (result == null) {
913-
result = _isInterceptorCacheSecondChance[value] ?? _isInterceptor(value);
914-
if (_isInterceptorCache.length >= _kIsInterceptorCacheLimit) {
915-
_isInterceptorCacheSecondChance = _isInterceptorCache;
916-
_isInterceptorCache = {};
917-
}
918-
_isInterceptorCache[value] = result;
911+
if (!_interceptorDomain.contains(
912+
value.powerset,
913+
TypeMaskInterceptorProperty.interceptor,
914+
)) {
915+
return AbstractBool.false_;
919916
}
920-
return result;
921-
}
922917

923-
AbstractBool _isInterceptor(TypeMask value) {
924-
return AbstractBool.maybeOrFalse(
925-
!interceptorType.isDisjoint(value, closedWorld),
926-
);
927-
}
918+
if (!_interceptorDomain.contains(
919+
value.powerset,
920+
TypeMaskInterceptorProperty.notInterceptor,
921+
)) {
922+
return AbstractBool.true_;
923+
}
928924

929-
static const _kIsInterceptorCacheLimit = 500;
930-
Map<TypeMask, AbstractBool> _isInterceptorCache = {};
931-
Map<TypeMask, AbstractBool> _isInterceptorCacheSecondChance = {};
925+
return AbstractBool.maybe;
926+
}
932927

933928
@override
934929
bool isMap(TypeMask value) => value is MapTypeMask;

0 commit comments

Comments
 (0)