[dart2js] Avoid adding empty type rules.

The fragment emitter already tries to skip the call to `addRules` if the
ruleset is empty, but this occurs too early. The ruleset encoder strips
tautologies like `T <: T` and `InterfaceType <: Object`, but this occurs
after the empty check.

This CL removes the preprocessing from the encoder and instead performs
checks when entries are added to the ruleset, fixing the issue.

Change-Id: I62f937e0ff6abac12973f82b2c89d8ea6f3162b4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/258040
Reviewed-by: Joshua Litt <joshualitt@google.com>
Commit-Queue: Mayank Patke <fishythefish@google.com>
This commit is contained in:
Mayank Patke 2022-09-08 19:25:43 +00:00 committed by Commit Bot
parent 3584073fbc
commit 581db69c7a
6 changed files with 49 additions and 54 deletions

View file

@ -460,15 +460,22 @@ class _RulesetEntry {
}
class Ruleset {
Map<ClassEntity, ClassEntity> _redirections;
Map<InterfaceType, _RulesetEntry> _entries;
final DartTypes _dartTypes;
final Map<ClassEntity, ClassEntity> _redirections = {};
final Map<InterfaceType, _RulesetEntry> _entries = {};
Ruleset(this._redirections, this._entries);
Ruleset.empty() : this({}, {});
Ruleset.empty(this._dartTypes);
CommonElements get _commonElements => _dartTypes.commonElements;
ClassEntity get _objectClass => _commonElements.objectClass;
bool get isEmpty => _redirections.isEmpty && _entries.isEmpty;
bool get isNotEmpty => _redirections.isNotEmpty || _entries.isNotEmpty;
bool _isObject(InterfaceType type) => identical(type.element, _objectClass);
bool _isSyntheticClosure(InterfaceType type) => type.element.isClosure;
void addRedirection(ClassEntity redirectee, ClassEntity target) {
assert(redirectee != target);
_redirections[redirectee] = target;
@ -476,20 +483,21 @@ class Ruleset {
void addEntry(InterfaceType targetType, Iterable<InterfaceType> supertypes,
Map<TypeVariableType, DartType> typeVariables) {
if (_isObject(targetType) || _isSyntheticClosure(targetType)) return;
supertypes = supertypes.where((supertype) =>
!_isObject(supertype) &&
!identical(targetType.element, supertype.element));
if (supertypes.isEmpty && typeVariables.isEmpty) return;
_RulesetEntry entry = _entries[targetType] ??= _RulesetEntry();
entry.addAll(supertypes, typeVariables);
}
}
class RulesetEncoder {
final DartTypes _dartTypes;
final ModularEmitter _emitter;
final RecipeEncoder _recipeEncoder;
RulesetEncoder(this._dartTypes, this._emitter, this._recipeEncoder);
CommonElements get _commonElements => _dartTypes.commonElements;
ClassEntity get _objectClass => _commonElements.objectClass;
RulesetEncoder(this._emitter, this._recipeEncoder);
final _leftBrace = js.string('{');
final _rightBrace = js.string('}');
@ -499,32 +507,10 @@ class RulesetEncoder {
final _comma = js.string(',');
final _doubleQuote = js.string('"');
bool _isObject(InterfaceType type) => identical(type.element, _objectClass);
bool _isSyntheticClosure(InterfaceType type) => type.element.isClosure;
void _preprocessEntry(InterfaceType targetType, _RulesetEntry entry) {
entry._supertypes.removeWhere((InterfaceType supertype) =>
_isObject(supertype) ||
identical(targetType.element, supertype.element));
}
void _preprocessRuleset(Ruleset ruleset) {
ruleset._entries.removeWhere((InterfaceType targetType, _) =>
_isObject(targetType) || _isSyntheticClosure(targetType));
ruleset._entries.forEach(_preprocessEntry);
ruleset._entries.removeWhere((_, _RulesetEntry entry) => entry.isEmpty);
}
// TODO(fishythefish): Common substring elimination.
/// Produces a string readable by `JSON.parse()`.
jsAst.StringConcatenation encodeRuleset(Ruleset ruleset) {
_preprocessRuleset(ruleset);
return _encodeRuleset(ruleset);
}
jsAst.StringConcatenation _encodeRuleset(Ruleset ruleset) =>
jsAst.StringConcatenation encodeRuleset(Ruleset ruleset) =>
js.concatenateStrings([
_leftBrace,
...js.joinLiterals([

View file

@ -628,8 +628,7 @@ class FragmentEmitter {
: RuntimeTypesImpl(_closedWorld),
_closedWorld.nativeData,
_closedWorld.commonElements);
_rulesetEncoder =
RulesetEncoder(_closedWorld.dartTypes, _emitter, _recipeEncoder);
_rulesetEncoder = RulesetEncoder(_emitter, _recipeEncoder);
}
js.Expression generateEmbeddedGlobalAccess(String global) =>
@ -1912,7 +1911,7 @@ class FragmentEmitter {
Map<ClassTypeData, List<ClassTypeData>> nativeRedirections =
_nativeEmitter.typeRedirections;
Ruleset ruleset = Ruleset.empty();
Ruleset ruleset = Ruleset.empty(_dartTypes);
Map<ClassEntity, int> erasedTypes = {};
Iterable<ClassTypeData> classTypeData =
fragment.libraries.expand((Library library) => library.classTypeData);

View file

@ -23,9 +23,9 @@
/*two-frag.library:
a_pre_fragments=[
p1: {units: [4{libB}, 1{libA}], usedBy: [p2, p3], needs: []},
p2: {units: [3{libA, libC}, 6{libC}], usedBy: [p3], needs: [p1]},
p3: {units: [2{libA, libB, libC}, 5{libB, libC}], usedBy: [], needs: [p2, p1]}],
p1: {units: [4{libB}, 1{libA}], usedBy: [p3], needs: []},
p2: {units: [6{libC}], usedBy: [p3], needs: []},
p3: {units: [2{libA, libB, libC}, 5{libB, libC}, 3{libA, libC}], usedBy: [], needs: [p2, p1]}],
b_finalized_fragments=[
f1: [4{libB}, 1{libA}],
f2: [6{libC}],

View file

@ -80,30 +80,28 @@
/*three-frag.library:
a_pre_fragments=[
p1: {units: [26{b3, b4}, 21{b2, b5}, 19{b2, b4}, 18{b2, b3}, 10{b1, b5}, 6{b1, b4}, 4{b1, b3}, 3{b1, b2}, 31{b5}, 29{b4}, 25{b3}, 17{b2}, 1{b1}], usedBy: [p2], needs: []},
p2: {units: [9{b1, b2, b3, b4}, 28{b3, b4, b5}, 23{b2, b4, b5}, 22{b2, b3, b5}, 20{b2, b3, b4}, 14{b1, b4, b5}, 12{b1, b3, b5}, 8{b1, b3, b4}, 11{b1, b2, b5}, 7{b1, b2, b4}, 5{b1, b2, b3}, 30{b4, b5}, 27{b3, b5}], usedBy: [p4, p3], needs: [p1]},
p3: {units: [24{b2, b3, b4, b5}, 16{b1, b3, b4, b5}, 15{b1, b2, b4, b5}, 13{b1, b2, b3, b5}], usedBy: [p4], needs: [p2]},
p4: {units: [2{b1, b2, b3, b4, b5}], usedBy: [], needs: [p2, p3]}],
p2: {units: [9{b1, b2, b3, b4}, 28{b3, b4, b5}, 23{b2, b4, b5}, 22{b2, b3, b5}, 20{b2, b3, b4}, 14{b1, b4, b5}, 12{b1, b3, b5}, 8{b1, b3, b4}, 11{b1, b2, b5}, 7{b1, b2, b4}, 5{b1, b2, b3}, 30{b4, b5}, 27{b3, b5}], usedBy: [p3], needs: [p1]},
p3: {units: [2{b1, b2, b3, b4, b5}, 24{b2, b3, b4, b5}, 16{b1, b3, b4, b5}, 15{b1, b2, b4, b5}, 13{b1, b2, b3, b5}], usedBy: [], needs: [p2]}],
b_finalized_fragments=[
f1: [26{b3, b4}, 21{b2, b5}, 19{b2, b4}, 18{b2, b3}, 10{b1, b5}, 6{b1, b4}, 4{b1, b3}, 3{b1, b2}, 31{b5}, 29{b4}, 25{b3}, 17{b2}, 1{b1}],
f2: [9{b1, b2, b3, b4}, 28{b3, b4, b5}, 23{b2, b4, b5}, 22{b2, b3, b5}, 20{b2, b3, b4}, 14{b1, b4, b5}, 12{b1, b3, b5}, 8{b1, b3, b4}, 11{b1, b2, b5}, 7{b1, b2, b4}, 5{b1, b2, b3}, 30{b4, b5}, 27{b3, b5}],
f3: [24{b2, b3, b4, b5}, 16{b1, b3, b4, b5}, 15{b1, b2, b4, b5}, 13{b1, b2, b3, b5}],
f4: [2{b1, b2, b3, b4, b5}]],
f3: [2{b1, b2, b3, b4, b5}, 24{b2, b3, b4, b5}, 16{b1, b3, b4, b5}, 15{b1, b2, b4, b5}, 13{b1, b2, b3, b5}]],
c_steps=[
b1=(f4, f3, f2, f1),
b2=(f4, f3, f2, f1),
b3=(f4, f3, f2, f1),
b4=(f4, f3, f2, f1),
b5=(f4, f3, f2, f1)]
b1=(f3, f2, f1),
b2=(f3, f2, f1),
b3=(f3, f2, f1),
b4=(f3, f2, f1),
b5=(f3, f2, f1)]
*/
/*two-frag.library:
a_pre_fragments=[
p1: {units: [12{b1, b3, b5}, 8{b1, b3, b4}, 11{b1, b2, b5}, 7{b1, b2, b4}, 5{b1, b2, b3}, 30{b4, b5}, 27{b3, b5}, 26{b3, b4}, 21{b2, b5}, 19{b2, b4}, 18{b2, b3}, 10{b1, b5}, 6{b1, b4}, 4{b1, b3}, 3{b1, b2}, 31{b5}, 29{b4}, 25{b3}, 17{b2}, 1{b1}], usedBy: [p2], needs: []},
p2: {units: [24{b2, b3, b4, b5}, 16{b1, b3, b4, b5}, 15{b1, b2, b4, b5}, 13{b1, b2, b3, b5}, 9{b1, b2, b3, b4}, 28{b3, b4, b5}, 23{b2, b4, b5}, 22{b2, b3, b5}, 20{b2, b3, b4}, 14{b1, b4, b5}], usedBy: [p3], needs: [p1]},
p1: {units: [8{b1, b3, b4}, 11{b1, b2, b5}, 7{b1, b2, b4}, 5{b1, b2, b3}, 30{b4, b5}, 27{b3, b5}, 26{b3, b4}, 21{b2, b5}, 19{b2, b4}, 18{b2, b3}, 10{b1, b5}, 6{b1, b4}, 4{b1, b3}, 3{b1, b2}, 31{b5}, 29{b4}, 25{b3}, 17{b2}, 1{b1}], usedBy: [p2], needs: []},
p2: {units: [24{b2, b3, b4, b5}, 16{b1, b3, b4, b5}, 15{b1, b2, b4, b5}, 13{b1, b2, b3, b5}, 9{b1, b2, b3, b4}, 28{b3, b4, b5}, 23{b2, b4, b5}, 22{b2, b3, b5}, 20{b2, b3, b4}, 14{b1, b4, b5}, 12{b1, b3, b5}], usedBy: [p3], needs: [p1]},
p3: {units: [2{b1, b2, b3, b4, b5}], usedBy: [], needs: [p2]}],
b_finalized_fragments=[
f1: [12{b1, b3, b5}, 8{b1, b3, b4}, 11{b1, b2, b5}, 7{b1, b2, b4}, 5{b1, b2, b3}, 30{b4, b5}, 27{b3, b5}, 26{b3, b4}, 21{b2, b5}, 19{b2, b4}, 18{b2, b3}, 10{b1, b5}, 6{b1, b4}, 4{b1, b3}, 3{b1, b2}, 31{b5}, 29{b4}, 25{b3}, 17{b2}, 1{b1}],
f2: [24{b2, b3, b4, b5}, 16{b1, b3, b4, b5}, 15{b1, b2, b4, b5}, 13{b1, b2, b3, b5}, 9{b1, b2, b3, b4}, 28{b3, b4, b5}, 23{b2, b4, b5}, 22{b2, b3, b5}, 20{b2, b3, b4}, 14{b1, b4, b5}],
f1: [8{b1, b3, b4}, 11{b1, b2, b5}, 7{b1, b2, b4}, 5{b1, b2, b3}, 30{b4, b5}, 27{b3, b5}, 26{b3, b4}, 21{b2, b5}, 19{b2, b4}, 18{b2, b3}, 10{b1, b5}, 6{b1, b4}, 4{b1, b3}, 3{b1, b2}, 31{b5}, 29{b4}, 25{b3}, 17{b2}, 1{b1}],
f2: [24{b2, b3, b4, b5}, 16{b1, b3, b4, b5}, 15{b1, b2, b4, b5}, 13{b1, b2, b3, b5}, 9{b1, b2, b3, b4}, 28{b3, b4, b5}, 23{b2, b4, b5}, 22{b2, b3, b5}, 20{b2, b3, b4}, 14{b1, b4, b5}, 12{b1, b3, b5}],
f3: [2{b1, b2, b3, b4, b5}]],
c_steps=[
b1=(f3, f2, f1),

View file

@ -15,7 +15,19 @@
lib3=(f2)]
*/
/*two-frag|three-frag.library:
/*two-frag.library:
a_pre_fragments=[
p1: {units: [1{lib1}], usedBy: [p2], needs: []},
p2: {units: [2{lib1, lib3}, 3{lib3}], usedBy: [], needs: [p1]}],
b_finalized_fragments=[
f1: [1{lib1}],
f2: [3{lib3}]],
c_steps=[
lib1=(f1),
lib3=(f2)]
*/
/*three-frag.library:
a_pre_fragments=[
p1: {units: [1{lib1}], usedBy: [p3], needs: []},
p2: {units: [3{lib3}], usedBy: [p3], needs: []},

View file

@ -110,7 +110,7 @@
"id": "outputUnit/1",
"kind": "outputUnit",
"name": "1",
"size": 895,
"size": 834,
"filename": "out_1.part.js",
"imports": [
"lib1"