[ddc] Use import URI to name a library

Import URIs are normalized by the CFE and should be globally unique in
the program. They serve as a good identifier to name a library in the
new "ddc" module format.

Change-Id: I9e255221bcffba52ad80138a4672d0490b7cbacd
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/381781
Reviewed-by: Nate Biggs <natebiggs@google.com>
Reviewed-by: Mark Zhou <markzipan@google.com>
diff --git a/pkg/dev_compiler/lib/js/ddc/ddc_module_loader.js b/pkg/dev_compiler/lib/js/ddc/ddc_module_loader.js
index 98a14b4..0b297c5 100644
--- a/pkg/dev_compiler/lib/js/ddc/ddc_module_loader.js
+++ b/pkg/dev_compiler/lib/js/ddc/ddc_module_loader.js
@@ -1367,7 +1367,7 @@
     // See docs on `DartDevEmbedder.runMain`.
     runMain(entryPointLibraryName, dartSdkRuntimeOptions) {
       console.log('Setting Dart SDK runtime options.');
-      let dartRuntimeLibrary = this.initializeAndLinkLibrary('dart');
+      let dartRuntimeLibrary = this.initializeAndLinkLibrary('dart:_runtime');
 
       // TODO(nshahan) Use a single method in the Dart SDK to set all options.
       dartRuntimeLibrary.weakNullSafetyErrors(dartSdkRuntimeOptions.weakNullSafetyErrors);
diff --git a/pkg/dev_compiler/lib/src/compiler/module_builder.dart b/pkg/dev_compiler/lib/src/compiler/module_builder.dart
index 8961e8f..aaf8101 100644
--- a/pkg/dev_compiler/lib/src/compiler/module_builder.dart
+++ b/pkg/dev_compiler/lib/src/compiler/module_builder.dart
@@ -474,21 +474,21 @@
       Identifier? moduleVar, ImportDeclaration import) {
     var items = <Statement>[];
 
+    var fromName = import.from;
     for (var importName in import.namedImports!) {
       // import * is not emitted by the compiler, so we don't handle it here.
       assert(!importName.isStar);
 
-      var fromName = importName.name!.name;
       var asName = importName.asName ?? importName.name;
       if (import.from.valueWithoutQuotes != dartSdkModule) {
         // Load non-SDK modules on demand (i.e., deferred).
         items.add(js.statement(
             'let # = dartDevEmbedder.importLibrary(#, function (lib) { '
             '# = lib; });',
-            [asName, js.string(fromName), asName]));
+            [asName, fromName, asName]));
       } else {
-        items.add(js.statement('const # = dartDevEmbedder.importLibrary(#)',
-            [asName, js.string(fromName)]));
+        items.add(js.statement(
+            'const # = dartDevEmbedder.importLibrary(#)', [asName, fromName]));
       }
     }
     return items;
@@ -503,13 +503,11 @@
       for (var export in exports) {
         // Dart SDK module must export the libraries via a definition until it
         // can be separated into individual libraries.
-        var names = export.exportedNames!;
-        for (var name in names) {
-          var alias = name.asName ?? name.name!;
-          items.add(js.statement(
-              'dartDevEmbedder.defineLibrary(#, function(_) { return #; })',
-              [js.string(name.name!.name), alias]));
-        }
+        var name = export.exportedNames!.single;
+        var alias = name.asName ?? name.name!;
+        items.add(js.statement(
+            'dartDevEmbedder.defineLibrary(#, function(_) { return #; })',
+            [(export.exported as ExportClause).from, alias]));
       }
     }
     return items;
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 06377fd..d3a4462 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -7934,39 +7934,71 @@
       items.add(js.statement('#.library = #', [_runtimeModule, libraryProto]));
       exports.add(js_ast.NameSpecifier(_runtimeModule));
     }
-
-    for (var library in libraries) {
-      if (_isBuildingSdk && _isSdkInternalRuntime(library)) {
-        _libraries[library] = _runtimeModule;
-        continue;
+    if (_options.emitLibraryBundle) {
+      assert(_isBuildingSdk);
+      for (var library in libraries) {
+        js_ast.Identifier libraryId;
+        if (_isSdkInternalRuntime(library)) {
+          libraryId = _runtimeModule;
+        } else if (_isDartLibrary(library, '_rti')) {
+          libraryId = _rtiLibraryId;
+        } else {
+          libraryId = js_ast.TemporaryId(_jsLibraryName(library));
+        }
+        _libraries[library] = libraryId;
+        var alias = _jsLibraryAlias(library);
+        var aliasId = alias == null ? null : js_ast.TemporaryId(alias);
+        items.add(js_ast.ExportDeclaration(js_ast.ExportClause(
+            [js_ast.NameSpecifier(libraryId, asName: aliasId)],
+            from: js.string('${library.importUri}'))));
+        // The initialization object for the runtime library is created above so
+        // it is skipped here.
+        if (_isSdkInternalRuntime(library)) continue;
+        items.add(js.statement(
+            'const # = Object.create(#.library)', [libraryId, _runtimeModule]));
       }
-      var libraryId = _isBuildingSdk && _isDartLibrary(library, '_rti')
-          ? _rtiLibraryId
-          : js_ast.TemporaryId(_jsLibraryName(library));
+      // dart:_runtime has a magic library that holds extension method symbols.
+      // TODO(nshahan): Could this be created with a kernel transform or just
+      // become a member in dart:_runtime?
+      items.add(js.statement('const # = Object.create(#.library)',
+          [_extensionSymbolsModule, _runtimeModule]));
+      items.add(js_ast.ExportDeclaration(js_ast.ExportClause(
+          [js_ast.NameSpecifier(_extensionSymbolsModule)],
+          from: js.string('dartx'))));
+    } else {
+      for (var library in libraries) {
+        if (_isBuildingSdk && _isSdkInternalRuntime(library)) {
+          _libraries[library] = _runtimeModule;
+          continue;
+        }
+        var libraryId = _isBuildingSdk && _isDartLibrary(library, '_rti')
+            ? _rtiLibraryId
+            : js_ast.TemporaryId(_jsLibraryName(library));
 
-      _libraries[library] = libraryId;
-      var alias = _jsLibraryAlias(library);
-      var aliasId = alias == null ? null : js_ast.TemporaryId(alias);
+        _libraries[library] = libraryId;
+        var alias = _jsLibraryAlias(library);
+        var aliasId = alias == null ? null : js_ast.TemporaryId(alias);
 
-      // TODO(vsm): Change back to `const`.
-      // See https://github.com/dart-lang/sdk/issues/40380.
-      items.add(js.statement(
-          'var # = Object.create(#.library)', [libraryId, _runtimeModule]));
-      exports.add(js_ast.NameSpecifier(libraryId, asName: aliasId));
+        // TODO(vsm): Change back to `const`.
+        // See https://github.com/dart-lang/sdk/issues/40380.
+        items.add(js.statement(
+            'var # = Object.create(#.library)', [libraryId, _runtimeModule]));
+        exports.add(js_ast.NameSpecifier(libraryId, asName: aliasId));
+      }
+
+      // dart:_runtime has a magic module that holds extension method symbols.
+      // TODO(jmesserly): find a cleaner design for this.
+      if (_isBuildingSdk) {
+        var id = _extensionSymbolsModule;
+        // TODO(vsm): Change back to `const`.
+        // See https://github.com/dart-lang/sdk/issues/40380.
+        items.add(js.statement(
+            'var # = Object.create(#.library)', [id, _runtimeModule]));
+        exports.add(js_ast.NameSpecifier(id));
+      }
+      items.add(js_ast.ExportDeclaration(js_ast.ExportClause(exports)));
     }
 
-    // dart:_runtime has a magic module that holds extension method symbols.
-    // TODO(jmesserly): find a cleaner design for this.
-    if (_isBuildingSdk) {
-      var id = _extensionSymbolsModule;
-      // TODO(vsm): Change back to `const`.
-      // See https://github.com/dart-lang/sdk/issues/40380.
-      items.add(js
-          .statement('var # = Object.create(#.library)', [id, _runtimeModule]));
-      exports.add(js_ast.NameSpecifier(id));
-    }
-    items.add(js_ast.ExportDeclaration(js_ast.ExportClause(exports)));
-
     if (_isBuildingSdk) {
       // Initialize the private name function.
       // To bootstrap the SDK, this needs to be emitted before other code.
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler_new.dart b/pkg/dev_compiler/lib/src/kernel/compiler_new.dart
index daee98b..22bf41c 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler_new.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler_new.dart
@@ -867,15 +867,14 @@
     // Emit the hoisted instantiated generic class table cache variables
     items.addAll(_genericClassTable.dischargeBoundTypes());
     _ticker?.logMs('Emitted instantiated generic class table');
-
-    var module = _finishLibrary(
-        items, _jsLibraryName(library), _emitLibraryName(library));
+    var compiledLibrary = _finishLibrary(
+        items, '${library.importUri}', _emitLibraryName(library));
     _ticker?.logMs('Finished emitting module');
 
     // Mark as finished for incremental mode, so it is safe to
     // switch to the incremental mode for expression compilation.
     _moduleEmitted = true;
-    return module;
+    return compiledLibrary;
   }
 
   /// Choose a canonical name from the [library] element.
@@ -8023,36 +8022,38 @@
         //     import {foo} from 'foo';         // if no rename needed
         //     import {foo as foo$} from 'foo'; // if rename was needed
         //
-        var imports = <js_ast.NameSpecifier>[];
         for (var library in libraries) {
           if (!_incrementalMode ||
               usedLibraries!.contains(_jsLibraryName(library))) {
             var alias = _jsLibraryAlias(library);
             if (alias != null) {
               var aliasId = js_ast.TemporaryId(alias);
-              imports.add(
-                  js_ast.NameSpecifier(aliasId, asName: _imports[library]));
+              items.add(js_ast.ImportDeclaration(
+                  from: js.string('${library.importUri}'),
+                  namedImports: [
+                    js_ast.NameSpecifier(aliasId, asName: _imports[library])
+                  ]));
             } else {
-              imports.add(js_ast.NameSpecifier(_imports[library]));
+              items.add(js_ast.ImportDeclaration(
+                  from: js.string('${library.importUri}'),
+                  namedImports: [js_ast.NameSpecifier(_imports[library])]));
             }
           }
         }
-
         if (module == coreModuleName) {
           if (!_incrementalMode ||
               usedLibraries!.contains(_runtimeModule.name)) {
-            imports.add(js_ast.NameSpecifier(_runtimeModule));
+            items.add(js_ast.ImportDeclaration(
+                from: js.string('dart:_runtime'),
+                namedImports: [js_ast.NameSpecifier(_runtimeModule)]));
           }
           if (!_incrementalMode ||
               usedLibraries!.contains(_extensionSymbolsModule.name)) {
-            imports.add(js_ast.NameSpecifier(_extensionSymbolsModule));
+            items.add(js_ast.ImportDeclaration(
+                from: js.string('dartx'),
+                namedImports: [js_ast.NameSpecifier(_extensionSymbolsModule)]));
           }
         }
-
-        if (!_incrementalMode || imports.isNotEmpty) {
-          items.add(js_ast.ImportDeclaration(
-              namedImports: imports, from: js.string(module, "'")));
-        }
       }
     });
   }
diff --git a/pkg/dev_compiler/tool/ddb b/pkg/dev_compiler/tool/ddb
index ff953fa..4f7eedc 100755
--- a/pkg/dev_compiler/tool/ddb
+++ b/pkg/dev_compiler/tool/ddb
@@ -25,8 +25,8 @@
     print('Usage: ddb [options] <dart-script-file>\n');
     print('Compiles <dart-script-file> with the dev_compiler and runs it on a '
         'JS platform.\n'
-        'Optionally, mulitple Dart source files can be passed as arguments and '
-        'they will be compiled into seperate modules in the order provided. '
+        'Optionally, multiple Dart source files can be passed as arguments and '
+        'they will be compiled into separate modules in the order provided. '
         'The order will be treated as an import DAG with the last file as the '
         'application entrypoint. The .dill file outputs from each compile will '
         'be collected and passed as dependency summaries for the next compile '
@@ -281,6 +281,10 @@
       if (options['packages'] != null) '--packages=${options['packages']}',
       if (emitDebugSymbols) '--emit-debug-symbols',
       if (canaryFeatures) '--canary',
+      // Provide predictable library URIs for all libraries when using the
+      // new ddc module format.
+      if (canaryFeatures) '--multi-root-scheme=ddb',
+      if (canaryFeatures) '--multi-root=/',
     ];
     var summaryFiles = [];
     for (var sourceFile in sourceFiles) {
@@ -289,27 +293,28 @@
         for (var summary in summaryFiles) '--summary=$summary',
         '-o',
         out,
-        sourceFile,
+        if (canaryFeatures) 'ddb:$sourceFile' else sourceFile,
       ];
       await runDdc([...ddcArgs, ...requestArgs]);
       outputs.add(out);
       var summaryFile = p.setExtension(out, '.dill');
-      var libname =
-          js_names.pathToJSIdentifier(p.basenameWithoutExtension(sourceFile));
+      var libname = canaryFeatures
+          ? 'ddb:$sourceFile'
+          : js_names.pathToJSIdentifier(p.basenameWithoutExtension(sourceFile));
       summaryFiles.add('$summaryFile=$libname');
     }
   }
 
   if (run) {
-    var ddcModuleSdkOptions = canaryFeatures ?
-'''let sdkOptions = {
-weakNullSafetyWarnings: !($weakNullSafetyErrors || $soundNullSafety),
+    var ddcModuleSdkOptions = canaryFeatures
+        ? '''let sdkOptions = {
+  weakNullSafetyWarnings: !($weakNullSafetyErrors || $soundNullSafety),
   weakNullSafetyErrors: $weakNullSafetyErrors,
   nonNullAsserts: $nonNullAsserts,
   nativeNonNullAsserts: $nativeNonNullAsserts,
   jsInteropNonNullAsserts: $jsInteropNonNullAsserts,
-};''' :
-'''
+};'''
+        : '''
 let sdk = dart_library.import("dart_sdk", "$appname");
 sdk.dart.weakNullSafetyWarnings(!($weakNullSafetyErrors || $soundNullSafety));
 sdk.dart.weakNullSafetyErrors($weakNullSafetyErrors);
@@ -318,9 +323,9 @@
 sdk.dart.jsInteropNonNullAsserts($jsInteropNonNullAsserts);
 ''';
     var ddcModuleRunMain = canaryFeatures
-          ? 'dartDevEmbedder.runMain("$libname", sdkOptions);'
-          : 'dart_library.start('
-              '"$appname", "$uuid", "$basename", "$libname", false);';
+        ? 'dartDevEmbedder.runMain("ddb:$entryPoint", sdkOptions);'
+        : 'dart_library.start('
+            '"$appname", "$uuid", "$basename", "$libname", false);';
     if (chrome) {
       String chromeBinary;
       if (binary != null) {
@@ -437,11 +442,11 @@
     } else if (d8) {
       var ddcModuleScriptTags =
           [for (var output in outputs) 'load("$output");'].join('\n');
-      var ddcModuleAssignGlobalSelf = canaryFeatures ?
-      '''
-let dart = dartDevEmbedder.importLibrary("dart");
-dart.global.self = dart.global;''':
-      'sdk.dart.global.self = sdk.dart.global;';
+      var ddcModuleAssignGlobalSelf = canaryFeatures
+          ? '''
+let dart = dartDevEmbedder.importLibrary("dart:_runtime");
+dart.global.self = dart.global;'''
+          : 'sdk.dart.global.self = sdk.dart.global;';
       var runjs = '''
 load("$ddcPath/lib/js/ddc/ddc_module_loader.js");
 load("$sdkJsPath/dart_sdk.js");