[dart2js] Add priority to dartDeferredLibraryLoader hook.
Change-Id: Ib77b20fc56aa67b4f3318f9dcd8fa65b62c56509
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/275800
Commit-Queue: Nate Biggs <natebiggs@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/js_emitter/headers.dart b/pkg/compiler/lib/src/js_emitter/headers.dart
index 90e4098..494a398 100644
--- a/pkg/compiler/lib/src/js_emitter/headers.dart
+++ b/pkg/compiler/lib/src/js_emitter/headers.dart
@@ -27,12 +27,14 @@
// directly. Instead, a closure that will invoke [main], and its arguments
// [args] is passed to [dartMainRunner].
//
-// dartDeferredLibraryLoader(uri, successCallback, errorCallback, loadId):
+// dartDeferredLibraryLoader(uri, successCallback, errorCallback, loadId, loadPriority):
// if this function is defined, it will be called when a deferred library
// is loaded. It should load and eval the javascript of `uri`, and call
// successCallback. If it fails to do so, it should call errorCallback with
-// an error. The loadId argument is the deferred import that resulted in
-// this uri being loaded.
+// an error. The loadId argument is the deferred import that resulted in
+// this uri being loaded. The loadPriority argument is the priorty the
+// library should be loaded with as specified in the code via the
+// load-priority annotation (0: normal, 1: high).
//
// dartCallInstrumentation(id, qualifiedName):
// if this function is defined, it will be called at each entry of a
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index 0694ddb..8efc2bf 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -2961,8 +2961,8 @@
try {
// Share the loadId that hunk belongs to, this will allow for any
// additional loadId based bundling optimizations.
- JS('void', '#(#, #, #, #)', deferredLibraryLoader, uriAsString, jsSuccess,
- jsFailure, loadId);
+ JS('void', '#(#, #, #, #, #)', deferredLibraryLoader, uriAsString,
+ jsSuccess, jsFailure, loadId, priority);
} catch (error, stackTrace) {
failure(error, "invoking dartDeferredLibraryLoader hook", stackTrace);
}
diff --git a/tests/web/internal/deferred/load_with_priority_lib.dart b/tests/web/internal/deferred/load_with_priority_lib.dart
new file mode 100644
index 0000000..b0bcaba
--- /dev/null
+++ b/tests/web/internal/deferred/load_with_priority_lib.dart
@@ -0,0 +1,7 @@
+final int a = 1;
+final int b = 2;
+final int c = 3;
+final int d = 4;
+final int e = 5;
+final int f = 6;
+final int g = 7;
diff --git a/tests/web/internal/deferred/load_with_priority_test.dart b/tests/web/internal/deferred/load_with_priority_test.dart
new file mode 100644
index 0000000..813df1f
--- /dev/null
+++ b/tests/web/internal/deferred/load_with_priority_test.dart
@@ -0,0 +1,110 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:async_helper/async_helper.dart';
+import 'package:expect/expect.dart';
+import 'dart:async';
+
+import 'dart:_foreign_helper' show JS;
+
+@pragma('dart2js:load-priority:high')
+import 'load_with_priority_lib.dart' deferred as highLib;
+@pragma('dart2js:load-priority:normal')
+import 'load_with_priority_lib.dart' deferred as normalExplicitLib;
+import 'load_with_priority_lib.dart' deferred as normalImplicitLib;
+import 'load_with_priority_lib.dart' deferred as highLocalLib;
+import 'load_with_priority_lib.dart' deferred as normalLocalLib;
+import 'load_with_priority_lib.dart' deferred as highMemberLib;
+import 'load_with_priority_lib.dart' deferred as normalMemberLib;
+
+main() {
+ asyncStart();
+ runTest().then((_) => asyncEnd());
+}
+
+@pragma('dart2js:load-priority:normal')
+Future<void> testNormalLoad() async {
+ await normalMemberLib.loadLibrary();
+ Expect.equals(6, normalMemberLib.f);
+}
+
+@pragma('dart2js:load-priority:high')
+Future<void> testHighLoad() async {
+ await highMemberLib.loadLibrary();
+ Expect.equals(7, highMemberLib.g);
+}
+
+runTest() async {
+ setup();
+ await highLib.loadLibrary();
+ Expect.equals(1, highLib.a);
+
+ await normalExplicitLib.loadLibrary();
+ Expect.equals(2, normalExplicitLib.b);
+
+ await normalImplicitLib.loadLibrary();
+ Expect.equals(3, normalImplicitLib.c);
+
+ @pragma('dart2js:load-priority:high')
+ final unused1 = await highLocalLib.loadLibrary();
+ Expect.equals(4, highLocalLib.d);
+
+ @pragma('dart2js:load-priority:normal')
+ final unused2 = await normalLocalLib.loadLibrary();
+ Expect.equals(5, normalLocalLib.e);
+
+ await testNormalLoad();
+ await testHighLoad();
+ tearDown();
+}
+
+void tearDown() {
+ // `wasCalled` will be false for DDC since there is no deferred load hook.
+ if (JS('bool', 'self.wasCalled')) {
+ Expect.equals(7, JS('', 'self.index'));
+ }
+}
+
+void setup() {
+ JS('', r"""
+(function() {
+// In d8 we don't have any way to load the content of the file via XHR, but we
+// can use the "load" instruction. A hook is already defined in d8 for this
+// reason.
+self.isD8 = !!self.dartDeferredLibraryLoader;
+self.index = 0;
+self.wasCalled = false;
+self.expectedPriorities = [1, 0, 0, 1, 0, 0, 1];
+
+// Download uri via an XHR
+self.download = function(uri, success) {
+ var req = new XMLHttpRequest();
+ req.addEventListener("load", function() {
+ eval(this.responseText);
+ success();
+ });
+ req.open("GET", uri);
+ req.send();
+};
+
+self.checkPriority = function(priority) {
+ if (priority !== self.expectedPriorities[self.index]) {
+ throw 'Unexpected priority from load index ' + self.index;
+ }
+ self.index++;
+};
+
+self.dartDeferredLibraryLoader = function(uri, success, error, loadId, priority) {
+ self.checkPriority(priority);
+ self.wasCalled = true;
+ if (self.isD8) {
+ load(uri);
+ success();
+ } else {
+ self.download(uri, success);
+ }
+};
+})()
+""");
+}