[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);
+  }
+};
+})()
+""");
+}