[dart2wasm] Stub out deferred loading.

Change-Id: If5ad3a783beb91bd11068b755974aa078530ac6e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/275743
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Commit-Queue: Joshua Litt <joshualitt@google.com>
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index 56d2a5e..efb27a4 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -627,10 +627,7 @@
 
   /// Helper function to throw a Wasm ref downcast error.
   void throwWasmRefError(String expected) {
-    wrap(
-        StringLiteral(expected),
-        translator
-            .translateType(translator.coreTypes.stringNonNullableRawType));
+    _emitString(expected);
     call(translator.stackTraceCurrent.reference);
     call(translator.throwWasmRefError.reference);
     b.unreachable();
@@ -2736,6 +2733,23 @@
     return operand.type;
   }
 
+  @override
+  w.ValueType visitLoadLibrary(LoadLibrary node, w.ValueType expectedType) {
+    LibraryDependency import = node.import;
+    _emitString(import.enclosingLibrary.importUri.toString());
+    _emitString(import.name!);
+    return call(translator.loadLibrary.reference);
+  }
+
+  @override
+  w.ValueType visitCheckLibraryIsLoaded(
+      CheckLibraryIsLoaded node, w.ValueType expectedType) {
+    LibraryDependency import = node.import;
+    _emitString(import.enclosingLibrary.importUri.toString());
+    _emitString(import.name!);
+    return call(translator.checkLibraryIsLoaded.reference);
+  }
+
   /// Pushes the `_Type` object for a function or class type parameter to the
   /// stack and returns the value type of the object.
   w.ValueType instantiateTypeParameter(TypeParameter parameter) {
@@ -3031,15 +3045,15 @@
     // Type check failed
     b.local_get(argLocal);
     b.local_get(argExpectedTypeLocal);
-    wrap(
-        StringLiteral(argName),
-        translator
-            .translateType(translator.coreTypes.stringNonNullableRawType));
+    _emitString(argName);
     call(translator.stackTraceCurrent.reference);
     call(translator.throwArgumentTypeCheckError.reference);
     b.unreachable();
     b.end();
   }
+
+  void _emitString(String str) => wrap(StringLiteral(str),
+      translator.translateType(translator.coreTypes.stringNonNullableRawType));
 }
 
 class TryBlockFinalizer {
diff --git a/pkg/dart2wasm/lib/kernel_nodes.dart b/pkg/dart2wasm/lib/kernel_nodes.dart
index 99d240a..53bfb19 100644
--- a/pkg/dart2wasm/lib/kernel_nodes.dart
+++ b/pkg/dart2wasm/lib/kernel_nodes.dart
@@ -11,15 +11,18 @@
   Component get component;
 
   late final LibraryIndex index = LibraryIndex(component, [
+    "dart:_internal",
     "dart:async",
     "dart:collection",
     "dart:core",
     "dart:ffi",
-    "dart:_internal",
     "dart:typed_data",
     "dart:wasm"
   ]);
 
+  // dart:_internal classes
+  late final Class symbolClass = index.getClass("dart:_internal", "Symbol");
+
   // dart:collection classes
   late final Class hashFieldBaseClass =
       index.getClass("dart:collection", "_HashFieldBase");
@@ -89,9 +92,6 @@
   late final Class unmodifiableByteDataViewClass =
       index.getClass("dart:typed_data", "_UnmodifiableByteDataView");
 
-  // dart:_internal classes
-  late final Class symbolClass = index.getClass("dart:_internal", "Symbol");
-
   // dart:wasm classes
   late final Class wasmTypesBaseClass =
       index.getClass("dart:wasm", "_WasmBase");
@@ -115,6 +115,12 @@
       index.getClass("dart:wasm", "WasmFunction");
   late final Class wasmTableClass = index.getClass("dart:wasm", "WasmTable");
 
+  // dart:_internal procedures
+  late final Procedure loadLibrary =
+      index.getTopLevelProcedure("dart:_internal", "loadLibrary");
+  late final Procedure checkLibraryIsLoaded =
+      index.getTopLevelProcedure("dart:_internal", "checkLibraryIsLoaded");
+
   // dart:async procedures
   late final Procedure asyncHelper =
       index.getTopLevelProcedure("dart:async", "_asyncHelper");
diff --git a/sdk/lib/_internal/wasm/lib/deferred.dart b/sdk/lib/_internal/wasm/lib/deferred.dart
new file mode 100644
index 0000000..099c245
--- /dev/null
+++ b/sdk/lib/_internal/wasm/lib/deferred.dart
@@ -0,0 +1,36 @@
+// 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.
+
+// TODO(joshualitt): This is just a stub so apps can run. We should replace it
+// with an actual implementation of deferred loading.
+
+part of "internal_patch.dart";
+
+Map<String, Set<String>> _loadedLibraries = {};
+
+class DeferredNotLoadedError extends Error implements NoSuchMethodError {
+  final String libraryName;
+  final String prefix;
+
+  DeferredNotLoadedError(this.libraryName, this.prefix);
+
+  String toString() {
+    return 'Deferred library $libraryName has not loaded $prefix.';
+  }
+}
+
+@pragma("wasm:entry-point")
+Future<void> loadLibrary(String enclosingLibrary, String importPrefix) {
+  (_loadedLibraries[enclosingLibrary] ??= {}).add(importPrefix);
+  return Future<void>.value();
+}
+
+@pragma("wasm:entry-point")
+Object checkLibraryIsLoaded(String enclosingLibrary, String importPrefix) {
+  bool? isLoaded = _loadedLibraries[enclosingLibrary]?.contains(importPrefix);
+  if (isLoaded == null || isLoaded == false) {
+    throw DeferredNotLoadedError(enclosingLibrary, importPrefix);
+  }
+  return true;
+}
diff --git a/sdk/lib/_internal/wasm/lib/internal_patch.dart b/sdk/lib/_internal/wasm/lib/internal_patch.dart
index 257f5b5..0eeb254 100644
--- a/sdk/lib/_internal/wasm/lib/internal_patch.dart
+++ b/sdk/lib/_internal/wasm/lib/internal_patch.dart
@@ -5,6 +5,7 @@
 import "dart:typed_data" show Uint8List;
 
 part "class_id.dart";
+part "deferred.dart";
 part "print_patch.dart";
 part "symbol_patch.dart";