[dart2js] Use DeferredStatement in existing Finalizers.
Change-Id: Iadc4b2d6f1fa0bebb57ac25012571078b9bfcdb4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/195189
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Joshua Litt <joshualitt@google.com>
diff --git a/pkg/compiler/lib/src/js_backend/string_reference.dart b/pkg/compiler/lib/src/js_backend/string_reference.dart
index b8c41aa..05e1b8f 100644
--- a/pkg/compiler/lib/src/js_backend/string_reference.dart
+++ b/pkg/compiler/lib/src/js_backend/string_reference.dart
@@ -145,58 +145,55 @@
Iterable<js.Node> get containedNodes => isFinalized ? [_value] : const [];
}
-/// A [StringReferenceResource] is a deferred JavaScript expression determined
+/// A [StringReferenceResource] is a deferred JavaScript statement determined
/// by the finalization of string references. It is the injection point for data
/// or code to support string references. For example, if the
/// [StringReferenceFinalizer] decides that a string should be referred to via a
/// variable, the [StringReferenceResource] would be set to code that declares
/// and initializes the variable.
-class StringReferenceResource extends js.DeferredExpression
+class StringReferenceResource extends js.DeferredStatement
implements js.AstContainer {
- js.Expression _value;
+ js.Statement _statement;
@override
final js.JavaScriptNodeSourceInformation sourceInformation;
StringReferenceResource() : sourceInformation = null;
- StringReferenceResource._(this._value, this.sourceInformation);
+ StringReferenceResource._(this._statement, this.sourceInformation);
- set value(js.Expression value) {
- assert(!isFinalized && value != null);
- _value = value;
+ set statement(js.Statement statement) {
+ assert(!isFinalized && statement != null);
+ _statement = statement;
}
@override
- js.Expression get value {
+ js.Statement get statement {
assert(isFinalized, 'StringReferenceResource is unassigned');
- return _value;
+ return _statement;
}
@override
- int get precedenceLevel => value.precedenceLevel;
-
- @override
- bool get isFinalized => _value != null;
+ bool get isFinalized => _statement != null;
@override
StringReferenceResource withSourceInformation(
js.JavaScriptNodeSourceInformation newSourceInformation) {
if (newSourceInformation == sourceInformation) return this;
if (newSourceInformation == null) return this;
- return StringReferenceResource._(_value, newSourceInformation);
+ return StringReferenceResource._(_statement, newSourceInformation);
}
@override
- Iterable<js.Node> get containedNodes => isFinalized ? [_value] : const [];
+ Iterable<js.Node> get containedNodes => isFinalized ? [_statement] : const [];
@override
void visitChildren<T>(js.NodeVisitor<T> visitor) {
- _value?.accept<T>(visitor);
+ _statement?.accept<T>(visitor);
}
@override
void visitChildren1<R, A>(js.NodeVisitor1<R, A> visitor, A arg) {
- _value?.accept1<R, A>(visitor, arg);
+ _statement?.accept1<R, A>(visitor, arg);
}
}
@@ -287,14 +284,11 @@
}
if (properties.isEmpty) {
- // We don't have a deferred statement sequence. "0;" is the smallest we
- // can do with an expression statement.
- // TODO(sra): Add deferred expression statement sequences.
- _resource.value = js.js('0');
+ _resource.statement = js.Block.empty();
} else {
js.Expression initializer =
js.ObjectInitializer(properties, isOneLiner: false);
- _resource.value = js.js(
+ _resource.statement = js.js.statement(
r'var # = #', [js.VariableDeclaration(holderLocalName), initializer]);
}
}
@@ -432,7 +426,14 @@
void visitDeferredExpression(js.DeferredExpression node) {
if (node is StringReference) {
_finalizer.registerStringReference(node);
- } else if (node is StringReferenceResource) {
+ } else {
+ visitNode(node);
+ }
+ }
+
+ @override
+ void visitDeferredStatement(js.DeferredStatement node) {
+ if (node is StringReferenceResource) {
_finalizer.registerStringReferenceResource(node);
} else {
visitNode(node);
diff --git a/pkg/compiler/lib/src/js_backend/type_reference.dart b/pkg/compiler/lib/src/js_backend/type_reference.dart
index f33591d..4ec5745 100644
--- a/pkg/compiler/lib/src/js_backend/type_reference.dart
+++ b/pkg/compiler/lib/src/js_backend/type_reference.dart
@@ -162,58 +162,55 @@
Iterable<js.Node> get containedNodes => isFinalized ? [_value] : const [];
}
-/// A [TypeReferenceResource] is a deferred JavaScript expression determined by
+/// A [TypeReferenceResource] is a deferred JavaScript statement determined by
/// the finalization of type references. It is the injection point for data or
/// code to support type references. For example, if the
/// [TypeReferenceFinalizer] decides that type should be referred to via a
/// variable, the [TypeReferenceResource] would be set to code that declares and
/// initializes the variable.
-class TypeReferenceResource extends js.DeferredExpression
+class TypeReferenceResource extends js.DeferredStatement
implements js.AstContainer {
- js.Expression _value;
+ js.Statement _statement;
@override
final js.JavaScriptNodeSourceInformation sourceInformation;
TypeReferenceResource() : sourceInformation = null;
- TypeReferenceResource._(this._value, this.sourceInformation);
+ TypeReferenceResource._(this._statement, this.sourceInformation);
- set value(js.Expression value) {
- assert(!isFinalized && value != null);
- _value = value;
+ set statement(js.Statement statement) {
+ assert(!isFinalized && statement != null);
+ _statement = statement;
}
@override
- js.Expression get value {
+ js.Statement get statement {
assert(isFinalized, 'TypeReferenceResource is unassigned');
- return _value;
+ return _statement;
}
@override
- bool get isFinalized => _value != null;
-
- @override
- int get precedenceLevel => value.precedenceLevel;
+ bool get isFinalized => _statement != null;
@override
TypeReferenceResource withSourceInformation(
js.JavaScriptNodeSourceInformation newSourceInformation) {
if (newSourceInformation == sourceInformation) return this;
if (newSourceInformation == null) return this;
- return TypeReferenceResource._(_value, newSourceInformation);
+ return TypeReferenceResource._(_statement, newSourceInformation);
}
@override
- Iterable<js.Node> get containedNodes => isFinalized ? [_value] : const [];
+ Iterable<js.Node> get containedNodes => isFinalized ? [_statement] : const [];
@override
void visitChildren<T>(js.NodeVisitor<T> visitor) {
- _value?.accept<T>(visitor);
+ _statement?.accept<T>(visitor);
}
@override
void visitChildren1<R, A>(js.NodeVisitor1<R, A> visitor, A arg) {
- _value?.accept1<R, A>(visitor, arg);
+ _statement?.accept1<R, A>(visitor, arg);
}
}
@@ -322,10 +319,7 @@
}
if (properties.isEmpty) {
- // We don't have a deferred statement sequence. "0;" is the smallest we
- // can do with an expression statement.
- // TODO(sra): Add deferred expression statement sequences.
- _resource.value = js.js('0');
+ _resource.statement = js.Block.empty();
} else {
js.Expression initializer =
js.ObjectInitializer(properties, isOneLiner: false);
@@ -335,7 +329,7 @@
[js.VariableDeclaration(helperLocal), helperAccess, initializer]);
initializer = js.js('#()', js.Parentheses(function));
}
- _resource.value = js.js(r'var # = #',
+ _resource.statement = js.js.statement(r'var # = #',
[js.VariableDeclaration(typesHolderLocalName), initializer]);
}
}
@@ -551,7 +545,14 @@
void visitDeferredExpression(js.DeferredExpression node) {
if (node is TypeReference) {
_finalizer._registerTypeReference(node);
- } else if (node is TypeReferenceResource) {
+ } else {
+ visitNode(node);
+ }
+ }
+
+ @override
+ void visitDeferredStatement(js.DeferredStatement node) {
+ if (node is TypeReferenceResource) {
_finalizer._registerTypeReferenceResource(node);
} else {
visitNode(node);
diff --git a/pkg/compiler/test/codegen/string_reference_test.dart b/pkg/compiler/test/codegen/string_reference_test.dart
index f7e20d2..27d64d6 100644
--- a/pkg/compiler/test/codegen/string_reference_test.dart
+++ b/pkg/compiler/test/codegen/string_reference_test.dart
@@ -11,6 +11,7 @@
show StringReference, StringReferenceResource, StringReferenceFinalizerImpl;
import 'package:compiler/src/js/js.dart' show prettyPrint;
+import 'package:js_ast/js_ast.dart' as js;
void test(List<String> strings, String expected, {bool minified: false}) {
var finalizer =
@@ -24,7 +25,8 @@
finalizer.registerStringReferenceResource(resource);
finalizer.finalize();
- Expect.equals(expected.trim(), prettyPrint(resource).trim());
+ // Wrap the resource in a block, as they would print in actual code.
+ Expect.equals(expected.trim(), prettyPrint(js.Block([resource])).trim());
}
extension on List<String> {
@@ -37,20 +39,26 @@
void main() {
// No strings yields an empty pool.
- test([], '0');
+ test([], r'''
+{
+}''');
// Single occurrence strings are not pooled.
test(
['Yellow', 'Blue', 'Crimson'],
- '0',
+ r'''
+{
+}''',
);
// Repeated strings that are long enough are pooled.
test(
['Yellow', 'Blue', 'Blue', 'Crimson', 'Crimson'],
r'''
-var string$ = {
- Crimso: "Crimson"
+{
+ var string$ = {
+ Crimso: "Crimson"
+ };
}''',
);
@@ -65,11 +73,13 @@
test(
greets * 2,
r'''
-var string$ = {
- Great_: "Great work!",
- GreetiA: "Greetings Alice",
- GreetiBH: "Greetings Bob Henry",
- GreetiBS: "Greetings Bob Smith"
+{
+ var string$ = {
+ Great_: "Great work!",
+ GreetiA: "Greetings Alice",
+ GreetiBH: "Greetings Bob Henry",
+ GreetiBS: "Greetings Bob Smith"
+ };
}''',
);
@@ -77,9 +87,11 @@
test(
['xylograph', '!pingpong'] * 2,
r'''
-var string$ = {
- _pingp: "!pingpong",
- xylogr: "xylograph"
+{
+ var string$ = {
+ _pingp: "!pingpong",
+ xylogr: "xylograph"
+ };
}''',
);
@@ -94,20 +106,24 @@
test(
strings1,
r'''
-var string$ = {
- a_x21pin: "a !pingpong",
- a_x25per: "a %percent",
- a_x78ylo: "a xylograph"
+{
+ var string$ = {
+ a_x21pin: "a !pingpong",
+ a_x25per: "a %percent",
+ a_x78ylo: "a xylograph"
+ };
}''',
);
// Minified version keeps the strings in the same order as unminified, and
// tries to allocate the same minified name.
const minified1 = r'''
-var string$ = {
- l: "a !pingpong",
- o: "a %percent",
- n: "a xylograph"
+{
+ var string$ = {
+ l: "a !pingpong",
+ o: "a %percent",
+ n: "a xylograph"
+ };
}''';
final strings2 = [