Skip to content

Commit 553ac95

Browse files
fishythefishCommit Queue
authored andcommitted
[dart2js] Add indexable bits to powerset.
Change-Id: I5d4c0b4d15a05cfc30d87003785ca841c46b1a0f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/426583 Reviewed-by: Stephen Adams <[email protected]>
1 parent b941f6f commit 553ac95

File tree

159 files changed

+3718
-3556
lines changed

Some content is hidden

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

159 files changed

+3718
-3556
lines changed

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,12 +877,22 @@ typedef _CachedPowersets = ({Bitset exact, Bitset subclass, Bitset subtype});
877877
class _PowersetCache {
878878
final JClosedWorld _closedWorld;
879879
final Set<ClassEntity> _interceptorCone;
880+
final Set<ClassEntity> _indexableCone;
881+
final Set<ClassEntity> _mutableIndexableCone;
880882
final Map<ClassEntity, _CachedPowersets> _cache = {};
881883

882884
_PowersetCache(this._closedWorld)
883885
: _interceptorCone =
884886
_closedWorld.classHierarchy
885887
.subclassesOf(_closedWorld.commonElements.jsInterceptorClass)
888+
.toSet(),
889+
_indexableCone =
890+
_closedWorld.classHierarchy
891+
.subtypesOf(_closedWorld.commonElements.jsIndexableClass)
892+
.toSet(),
893+
_mutableIndexableCone =
894+
_closedWorld.classHierarchy
895+
.subtypesOf(_closedWorld.commonElements.jsMutableIndexableClass)
886896
.toSet();
887897

888898
Bitset _computeExactPowerset(ClassEntity cls) {
@@ -915,6 +925,25 @@ class _PowersetCache {
915925
powerset = _arrayDomain.add(powerset, TypeMaskArrayProperty.other);
916926
}
917927

928+
// The order of these checks is important since `JSMutableIndexable` is a
929+
// subclass of `JSIndexable`.
930+
if (_mutableIndexableCone.contains(cls)) {
931+
powerset = _indexableDomain.add(
932+
powerset,
933+
TypeMaskIndexableProperty.mutableIndexable,
934+
);
935+
} else if (_indexableCone.contains(cls)) {
936+
powerset = _indexableDomain.add(
937+
powerset,
938+
TypeMaskIndexableProperty.indexable,
939+
);
940+
} else {
941+
powerset = _indexableDomain.add(
942+
powerset,
943+
TypeMaskIndexableProperty.notIndexable,
944+
);
945+
}
946+
918947
return powerset;
919948
}
920949

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

Lines changed: 67 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -233,11 +233,6 @@ class CommonMasks with AbstractValueDomain {
233233
@override
234234
TypeMask get emptyType => TypeMask.nonNullEmpty(this);
235235

236-
late final TypeMask indexablePrimitiveType = TypeMask.nonNullSubtype(
237-
commonElements.jsIndexableClass,
238-
this,
239-
);
240-
241236
late final TypeMask readableArrayType = TypeMask.nonNullSubclass(
242237
commonElements.jsArrayClass,
243238
this,
@@ -568,55 +563,69 @@ class CommonMasks with AbstractValueDomain {
568563

569564
@override
570565
AbstractBool isIndexablePrimitive(TypeMask value) =>
571-
AbstractBool.trueOrMaybe(_isIndexablePrimitive(value));
572-
573-
bool _isIndexablePrimitive(TypeMask value) {
574-
return value.containsOnlyString(closedWorld) ||
575-
_isInstanceOfOrNull(value, commonElements.jsIndexableClass);
576-
}
566+
AbstractBool.trueOrMaybe(value.containsOnlyString(closedWorld)) |
567+
isJsIndexable(value);
577568

578569
@override
579570
AbstractBool isMutableIndexable(TypeMask value) {
580-
return AbstractBool.trueOrMaybe(
581-
_isInstanceOfOrNull(value, commonElements.jsMutableIndexableClass),
582-
);
571+
final powerset = value.powerset;
572+
573+
if (_indexableDomain.containsSingle(
574+
powerset,
575+
TypeMaskIndexableProperty.mutableIndexable,
576+
)) {
577+
return AbstractBool.true_;
578+
}
579+
580+
if (!_indexableDomain.contains(
581+
powerset,
582+
TypeMaskIndexableProperty.mutableIndexable,
583+
)) {
584+
return AbstractBool.false_;
585+
}
586+
587+
return AbstractBool.maybe;
583588
}
584589

585590
@override
586591
AbstractBool isModifiableArray(TypeMask value) {
587592
final powerset = value.powerset;
588593

589-
if (_arrayDomain.contains(powerset, TypeMaskArrayProperty.other)) {
590-
return AbstractBool.maybe;
594+
if (_arrayDomain.containsOnly(
595+
powerset,
596+
TypeMaskArrayProperty._modifiableEnumSet,
597+
)) {
598+
return AbstractBool.true_;
591599
}
592600

593-
if (!powerset.intersects(TypeMaskArrayProperty._modifiableMask)) {
601+
if (_arrayDomain.containsOnly(
602+
powerset,
603+
TypeMaskArrayProperty._unmodifiableEnumSet,
604+
)) {
594605
return AbstractBool.false_;
595606
}
596607

597-
if (!powerset.intersects(TypeMaskArrayProperty._unmodifiableMask)) {
598-
return AbstractBool.true_;
599-
}
600-
601608
return AbstractBool.maybe;
602609
}
603610

604611
@override
605612
AbstractBool isGrowableArray(TypeMask value) {
606613
final powerset = value.powerset;
607614

608-
if (_arrayDomain.contains(powerset, TypeMaskArrayProperty.other)) {
609-
return AbstractBool.maybe;
615+
if (_arrayDomain.containsOnly(
616+
powerset,
617+
TypeMaskArrayProperty._growableEnumSet,
618+
)) {
619+
return AbstractBool.true_;
610620
}
611621

612-
if (!powerset.intersects(TypeMaskArrayProperty._growableMask)) {
622+
if (_arrayDomain.containsOnly(
623+
powerset,
624+
TypeMaskArrayProperty._fixedLengthEnumSet,
625+
)) {
613626
return AbstractBool.false_;
614627
}
615628

616-
if (!powerset.intersects(TypeMaskArrayProperty._fixedLengthMask)) {
617-
return AbstractBool.true_;
618-
}
619-
620629
return AbstractBool.maybe;
621630
}
622631

@@ -747,12 +756,20 @@ class CommonMasks with AbstractValueDomain {
747756
AbstractBool isPrimitiveOrNull(TypeMask value) =>
748757
AbstractBool.trueOrMaybe(_isPrimitiveOrNull(value));
749758

750-
bool _isPrimitiveOrNull(TypeMask value) {
751-
return _isIndexablePrimitive(value) ||
752-
_isNumberOrNull(value) ||
753-
_isBooleanOrNull(value) ||
754-
value.isNull;
755-
}
759+
bool _isIndexable(TypeMask value) =>
760+
!_indexableDomain.contains(
761+
value.powerset,
762+
TypeMaskIndexableProperty.notIndexable,
763+
);
764+
765+
bool _isIndexablePrimitive(TypeMask value) =>
766+
value.containsOnlyString(closedWorld) || _isIndexable(value);
767+
768+
bool _isPrimitiveOrNull(TypeMask value) =>
769+
_isIndexablePrimitive(value) ||
770+
_isNumberOrNull(value) ||
771+
_isBooleanOrNull(value) ||
772+
value.isNull;
756773

757774
@override
758775
TypeMask union(TypeMask a, TypeMask b) => a.union(b, this);
@@ -883,18 +900,24 @@ class CommonMasks with AbstractValueDomain {
883900

884901
@override
885902
AbstractBool isJsIndexable(TypeMask mask) {
886-
return AbstractBool.trueOrMaybe(
887-
mask.satisfies(closedWorld.commonElements.jsIndexableClass, closedWorld),
888-
);
903+
final powerset = mask.powerset;
904+
905+
if (_isIndexable(mask)) return AbstractBool.true_;
906+
907+
if (_indexableDomain.containsSingle(
908+
powerset,
909+
TypeMaskIndexableProperty.notIndexable,
910+
)) {
911+
return AbstractBool.false_;
912+
}
913+
914+
return AbstractBool.maybe;
889915
}
890916

891917
@override
892918
AbstractBool isJsIndexableAndIterable(covariant TypeMask mask) {
893919
return AbstractBool.trueOrMaybe(
894-
mask.satisfies(
895-
closedWorld.commonElements.jsIndexableClass,
896-
closedWorld,
897-
) &&
920+
_isIndexable(mask) &&
898921
// String is indexable but not iterable.
899922
!mask.satisfies(
900923
closedWorld.commonElements.jsStringClass,
@@ -910,9 +933,9 @@ class CommonMasks with AbstractValueDomain {
910933
return AbstractBool.true_;
911934
}
912935
// TODO(sra): Recognize any combination of fixed length indexables.
913-
if (mask.containsOnly(closedWorld.commonElements.jsFixedArrayClass) ||
914-
mask.containsOnly(
915-
closedWorld.commonElements.jsUnmodifiableArrayClass,
936+
if (_arrayDomain.containsOnly(
937+
mask.powerset,
938+
TypeMaskArrayProperty._fixedLengthEnumSet,
916939
) ||
917940
mask.containsOnlyString(closedWorld) ||
918941
isTypedArray(mask).isDefinitelyTrue) {

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ class RecordTypeMask extends TypeMask {
4141
TypeMaskInterceptorProperty.notInterceptor,
4242
);
4343
powerset = _arrayDomain.add(powerset, TypeMaskArrayProperty.other);
44+
powerset = _indexableDomain.add(
45+
powerset,
46+
TypeMaskIndexableProperty.notIndexable,
47+
);
4448
return createRecordWithPowerset(domain, types, shape, powerset);
4549
}
4650

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

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,10 +187,32 @@ enum TypeMaskArrayProperty {
187187
static const modifiableValues = [growable, fixedLength];
188188
static const unmodifiableValues = [unmodifiable];
189189

190-
static final _growableMask = _arrayDomain.fromValues(growableValues);
191-
static final _fixedLengthMask = _arrayDomain.fromValues(fixedLengthValues);
192-
static final _modifiableMask = _arrayDomain.fromValues(modifiableValues);
193-
static final _unmodifiableMask = _arrayDomain.fromValues(unmodifiableValues);
190+
static final _growableEnumSet = EnumSet.fromValues(growableValues);
191+
static final _fixedLengthEnumSet = EnumSet.fromValues(fixedLengthValues);
192+
static final _modifiableEnumSet = EnumSet.fromValues(modifiableValues);
193+
static final _unmodifiableEnumSet = EnumSet.fromValues(unmodifiableValues);
194+
}
195+
196+
/// This domain is similar to the [TypeMaskArrayProperty] domain. Since
197+
/// [JSMutableIndexable] is a subclass of [JSIndexable], every object that is
198+
/// mutable indexable (i.e. has `operator []=`) is also indexable (i.e. has
199+
/// `operator []`).
200+
///
201+
/// Therefore, the `mutableIndexable` bit corresponds to objects that have both
202+
/// operations, the `indexable` bit corresponds to objects that *only* have
203+
/// `operator []`, and the `notIndexable` bit corresponds to objects that have
204+
/// neither.
205+
enum TypeMaskIndexableProperty {
206+
indexable('I'),
207+
mutableIndexable('M'),
208+
notIndexable('N');
209+
210+
final String _mnemonic;
211+
212+
const TypeMaskIndexableProperty(this._mnemonic);
213+
214+
@override
215+
String toString() => _mnemonic;
194216
}
195217

196218
// This domain is unique in that it tracks specific values which are not
@@ -224,10 +246,16 @@ final _arrayDomain = EnumSetDomain<TypeMaskArrayProperty>(
224246
TypeMaskArrayProperty.values,
225247
);
226248

249+
final _indexableDomain = EnumSetDomain<TypeMaskIndexableProperty>(
250+
_arrayDomain.nextOffset,
251+
TypeMaskIndexableProperty.values,
252+
);
253+
227254
final _powersetDomains = ComposedEnumSetDomains([
228255
_specialValueDomain,
229256
_interceptorDomain,
230257
_arrayDomain,
258+
_indexableDomain,
231259
]);
232260

233261
Bitset _intersectPowersets(Bitset a, Bitset b) {

pkg/compiler/lib/src/util/enumset.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,14 @@ class EnumSetDomain<E extends Enum> {
215215
bool contains(Bitset bits, E enumValue) =>
216216
bits.intersects(fromValue(enumValue));
217217

218+
/// Returns `true` if [enumValue] is in [bits] and no other [E] is.
219+
bool containsSingle(Bitset bits, E enumValue) =>
220+
toEnumSet(bits) == enumValue.mask;
221+
222+
/// Returns `true` if the only [E] values in [bits] are in [enumValues].
223+
bool containsOnly(Bitset bits, EnumSet<E> enumValues) =>
224+
toEnumSet(bits).union(enumValues) == enumValues;
225+
218226
/// Returns `true` if [bits] contains any [E].
219227
bool isNotEmpty(Bitset bits) => bits.intersects(allValues);
220228

0 commit comments

Comments
 (0)