[dart2js] Choose between while- and for- loops
Change-Id: I6b564775e42649a974b72331528e02803a41616e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/447880
Reviewed-by: Mayank Patke <fishythefish@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
diff --git a/pkg/compiler/lib/src/js/rewrite_async.dart b/pkg/compiler/lib/src/js/rewrite_async.dart
index 9c05884..065b576 100644
--- a/pkg/compiler/lib/src/js/rewrite_async.dart
+++ b/pkg/compiler/lib/src/js/rewrite_async.dart
@@ -776,7 +776,7 @@
rewrittenBody = js.LabeledStatement(outerLabelName, rewrittenBody);
}
rewrittenBody = js.js
- .statement('while (true) #', rewrittenBody)
+ .statement('for (;;) #', rewrittenBody)
.withSourceInformation(bodySourceInformation);
List<js.VariableInitialization> variables = [];
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 519cacf..394f212 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -1109,11 +1109,11 @@
currentContainer = body;
visitBodyIgnoreLabels(info);
currentContainer = oldContainer;
- loop = js.For(
- jsInitialization,
- jsCondition,
- jsUpdates,
- unwrapStatement(body),
+ loop = newLoop(
+ init: jsInitialization,
+ condition: jsCondition,
+ update: jsUpdates,
+ body: unwrapStatement(body),
sourceInformation: info.sourceInformation,
);
} else {
@@ -1129,7 +1129,6 @@
jsCondition = generateExpression(condition);
currentContainer = body;
} else {
- jsCondition = newLiteralBool(true, info.sourceInformation);
currentContainer = body;
generateStatements(condition);
use(condition.conditionExpression!);
@@ -1151,9 +1150,9 @@
visitBodyIgnoreLabels(info);
}
currentContainer = oldContainer;
- loop = js.While(
- jsCondition!,
- unwrapStatement(body),
+ loop = newLoop(
+ condition: jsCondition,
+ body: unwrapStatement(body),
sourceInformation: info.sourceInformation,
);
}
@@ -1206,9 +1205,8 @@
// If the condition is dead code, we turn the do-while into
// a simpler while because we will never reach the condition
// at the end of the loop anyway.
- loop = js.While(
- newLiteralBool(true, info.sourceInformation),
- unwrapStatement(body),
+ loop = newLoop(
+ body: unwrapStatement(body),
sourceInformation: info.sourceInformation,
);
} else {
@@ -2836,6 +2834,45 @@
}
}
+ /// Returns a 'for' loop or 'while' loop depending on which parts of a 'for'
+ /// loop are present. In effect, choose the loop kind by applying these
+ /// reductions:
+ ///
+ /// for(init;true;update) --> for(init;;update)
+ /// for(;cond;) --> while(cond)
+ /// while(true) --> for(;;)
+ js.Loop newLoop({
+ js.Expression? init,
+ js.Expression? condition, // `null` means indefinite, i.e. `true`.
+ js.Expression? update,
+ required js.Statement body,
+ SourceInformation? sourceInformation,
+ }) {
+ // `condition` with `true` replaced with `null`:
+ final conditionOrNull = switch (condition) {
+ js.LiteralBool(value: true) => null,
+ js.LiteralNumber(value: '1') => null,
+ // Minified `true` is `!0`:
+ js.Prefix(op: '!', argument: js.LiteralNumber(value: '0')) => null,
+ _ => condition,
+ };
+
+ if (init == null && update == null && conditionOrNull != null) {
+ return js.While(
+ conditionOrNull,
+ body,
+ sourceInformation: sourceInformation,
+ );
+ }
+ return js.For(
+ init,
+ conditionOrNull,
+ update,
+ body,
+ sourceInformation: sourceInformation,
+ );
+ }
+
void generateConstant(
ConstantValue constant,
SourceInformation? sourceInformation,
diff --git a/pkg/compiler/test/async_await/async_await_js_transform_test.dart b/pkg/compiler/test/async_await/async_await_js_transform_test.dart
index e349294..35fd080e 100644
--- a/pkg/compiler/test/async_await/async_await_js_transform_test.dart
+++ b/pkg/compiler/test/async_await/async_await_js_transform_test.dart
@@ -78,7 +78,7 @@
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
- while (true)
+ for (;;)
switch (__goto) {
case 0:
// Function start
@@ -116,7 +116,7 @@
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
- while (true)
+ for (;;)
switch (__goto) {
case 0:
// Function start
@@ -168,7 +168,7 @@
__errorStack.push(__result);
__goto = __handler;
}
- while (true)
+ for (;;)
__outer1:
switch (__goto) {
case 0:
@@ -281,7 +281,7 @@
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
- while (true)
+ for (;;)
switch (__goto) {
case 0:
// Function start
@@ -338,7 +338,7 @@
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
- while (true)
+ for (;;)
switch (__goto) {
case 0:
// Function start
@@ -474,7 +474,7 @@
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
- while (true)
+ for (;;)
switch (__goto) {
case 0:
// Function start
@@ -563,7 +563,7 @@
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
- while (true)
+ for (;;)
switch (__goto) {
case 0:
// Function start
@@ -628,7 +628,7 @@
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
- while (true)
+ for (;;)
switch (__goto) {
case 0:
// Function start
@@ -713,7 +713,7 @@
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
- while (true)
+ for (;;)
switch (__goto) {
case 0:
// Function start
@@ -799,7 +799,7 @@
__errorStack.push(__result);
__goto = __handler;
}
- while (true)
+ for (;;)
switch (__goto) {
case 0:
// Function start
@@ -912,7 +912,7 @@
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
- while (true)
+ for (;;)
switch (__goto) {
case 0:
// Function start
@@ -995,7 +995,7 @@
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
- while (true)
+ for (;;)
switch (__goto) {
case 0:
// Function start
@@ -1122,7 +1122,7 @@
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
- while (true)
+ for (;;)
switch (__goto) {
case 0:
// Function start
@@ -1196,7 +1196,7 @@
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
- while (true)
+ for (;;)
switch (__goto) {
case 0:
// Function start
@@ -1275,7 +1275,7 @@
__errorStack.push(__result);
__goto = __handler;
}
- while (true)
+ for (;;)
switch (__goto) {
case 0:
// Function start
@@ -1348,7 +1348,7 @@
__errorStack.push(__result);
__goto = __handler;
}
- while (true)
+ for (;;)
switch (__goto) {
case 0:
// Function start
diff --git a/pkg/compiler/test/codegen/licm_test.dart b/pkg/compiler/test/codegen/licm_test.dart
index f194de4..2b6e5fb 100644
--- a/pkg/compiler/test/codegen/licm_test.dart
+++ b/pkg/compiler/test/codegen/licm_test.dart
@@ -28,7 +28,7 @@
await compileAndMatch(
TEST,
'main',
- RegExp('if \\(typeof count !== "number"\\)(.|\\n)*while'),
+ RegExp('if \\(typeof count !== "number"\\)(.|\\n)*(while|for)'),
);
}
diff --git a/pkg/compiler/test/dump_info/data/deferred_future/main.dart b/pkg/compiler/test/dump_info/data/deferred_future/main.dart
index 5f3d7fb..3c4e219 100644
--- a/pkg/compiler/test/dump_info/data/deferred_future/main.dart
+++ b/pkg/compiler/test/dump_info/data/deferred_future/main.dart
@@ -102,7 +102,7 @@
"id": "library/memory:sdk/tests/web/native/main.dart::",
"kind": "library",
"name": "<unnamed>",
- "size": 861,
+ "size": 857,
"children": [
"function/memory:sdk/tests/web/native/main.dart::main"
],
@@ -137,7 +137,7 @@
"id": "function/memory:sdk/tests/web/native/main.dart::main",
"kind": "function",
"name": "main",
- "size": 861,
+ "size": 857,
"outputUnit": "outputUnit/main",
"parent": "library/memory:sdk/tests/web/native/main.dart::",
"children": [],
@@ -152,7 +152,7 @@
"parameters": [],
"sideEffects": "SideEffects(reads nothing; writes nothing)",
"inlinedCount": 0,
- "code": "main() {\n var $async$goto = 0,\n $async$completer = A._makeAsyncAwaitCompleter(type$.dynamic);\n var $async$main = A._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {\n if ($async$errorCode === 1)\n return A._asyncRethrow($async$result, $async$completer);\n while (true)\n switch ($async$goto) {\n case 0:\n // Function start\n $async$goto = 2;\n return A._asyncAwait(A.loadDeferredLibrary(\"lib1\", \"\"), $async$main);\n case 2:\n // returning from await.\n A.checkDeferredIsLoaded(\"lib1\");\n A.checkDeferredIsLoaded(\"lib1\");\n // implicit return\n return A._asyncReturn(null, $async$completer);\n }\n });\n return A._asyncStartSync($async$main, $async$completer);\n }",
+ "code": "main() {\n var $async$goto = 0,\n $async$completer = A._makeAsyncAwaitCompleter(type$.dynamic);\n var $async$main = A._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {\n if ($async$errorCode === 1)\n return A._asyncRethrow($async$result, $async$completer);\n for (;;)\n switch ($async$goto) {\n case 0:\n // Function start\n $async$goto = 2;\n return A._asyncAwait(A.loadDeferredLibrary(\"lib1\", \"\"), $async$main);\n case 2:\n // returning from await.\n A.checkDeferredIsLoaded(\"lib1\");\n A.checkDeferredIsLoaded(\"lib1\");\n // implicit return\n return A._asyncReturn(null, $async$completer);\n }\n });\n return A._asyncStartSync($async$main, $async$completer);\n }",
"type": "dynamic Function()",
"functionKind": 0
}],