[ddc] Compile SDK as a bundle of libraries Cleanup temporary code paths in the stable version of compiler.dart. Change-Id: I4b60d90345bf8653060772789f55e16fb5db60d7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/385185 Reviewed-by: Mark Zhou <markzipan@google.com> Commit-Queue: Nicholas Shahan <nshahan@google.com> Reviewed-by: Nate Biggs <natebiggs@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 26dae95..564199f 100644 --- a/pkg/dev_compiler/lib/js/ddc/ddc_module_loader.js +++ b/pkg/dev_compiler/lib/js/ddc/ddc_module_loader.js
@@ -754,7 +754,7 @@ } if (!!configuration.jsInteropNonNullAsserts) { runtimeLibrary.jsInteropNonNullAsserts( - configuration.jsInteropNonNullAsserts); + configuration.jsInteropNonNullAsserts); } if (!!configuration.dynamicModuleLoader) { let loader = configuration.dynamicModuleLoader; @@ -1393,6 +1393,7 @@ // The name of the entrypoint module. Set when the application starts for // the first time and used during a hot restart. savedEntryPointLibraryName = null; + savedDartSdkRuntimeOptions = null; createEmptyLibrary() { return Object.create(null); @@ -1425,13 +1426,11 @@ if (currentLibrary == null) { currentLibrary = this.createEmptyLibrary(); // Run the initialization logic. - // TODO(nshahan): Refactor so the init function does not return a value, - // it should modify the library object passed in. let initializer = this.libraryInitializers[libraryName]; if (initializer == null) { throw 'Library not defined: ' + libraryName + '. Failed to initialize.'; } - currentLibrary = initializer(currentLibrary); + initializer(currentLibrary); // We make the library available in the map before linking to break out // of cycles in library dependencies. // Invariant: during linking a library dependency can be read in a state @@ -1478,13 +1477,34 @@ }); } + /** + * Forces the SDK libraries with side effects on the JavaScript side to be + * initialized and linked. + * + * These side effects could be required for correct Dart semantics + * (ex: dart:_interceptors) or observable from a carefully crafted user + * program (ex: dart:html). In either case, the dependencies on the side + * effects are not expressed through a Dart import so the libraries need + * to be loaded manually before the user program starts running. + */ + triggerSDKLibrariesSideEffects() { + this.initializeAndLinkLibrary('dart:_runtime'); + this.initializeAndLinkLibrary('dart:_interceptors'); + this.initializeAndLinkLibrary('dart:_native_typed_data'); + this.initializeAndLinkLibrary('dart:html'); + this.initializeAndLinkLibrary('dart:svg'); + this.initializeAndLinkLibrary('dart:web_audio'); + this.initializeAndLinkLibrary('dart:web_gl'); + } + // See docs on `DartDevEmbedder.runMain`. runMain(entryPointLibraryName, dartSdkRuntimeOptions) { + this.triggerSDKLibrariesSideEffects(); this.setDartSDKRuntimeOptions(dartSdkRuntimeOptions); - console.log('Starting application from main method in: ' + entryPointLibraryName + '.'); let entryPointLibrary = this.initializeAndLinkLibrary(entryPointLibraryName); this.savedEntryPointLibraryName = entryPointLibraryName; + this.savedDartSdkRuntimeOptions = dartSdkRuntimeOptions; entryPointLibrary.main(); } @@ -1582,15 +1602,22 @@ if (!this.savedEntryPointLibraryName) { throw "Error: Hot restart requested before application started."; } - console.log('Hot restarting...'); - // TODO(nshahan): Stop calling hotRestart in the SDK when the libraries - // have real initialization functions. + // TODO(nshahan): Stop calling hotRestart in the SDK when scheduled + // futures no longer keep lazy initialized values from the previous + // generation alive. let dart = this.importLibrary('dart:_runtime'); dart.hotRestart(); // Clear all libraries. this.libraries = Object.create(null); + this.triggerSDKLibrariesSideEffects(); + this.setDartSDKRuntimeOptions(this.savedDartSdkRuntimeOptions); let entryPointLibrary = this.initializeAndLinkLibrary(this.savedEntryPointLibraryName); + // TODO(nshahan): Start sharing a single source of truth for the restart + // generation between the dart:_runtime and this module system. this.hotRestartGeneration += 1; + console.log('Hot restarting application from main method in: ' + + this.savedEntryPointLibraryName + ' (generation: ' + + this.hotRestartGeneration + ').'); entryPointLibrary.main(); } } @@ -1657,7 +1684,7 @@ /** * DDC's entrypoint for triggering a hot reload. - * + * * Previous generations may continue to run until all specified files * have been loaded and initialized. *
diff --git a/pkg/dev_compiler/lib/src/compiler/module_builder.dart b/pkg/dev_compiler/lib/src/compiler/module_builder.dart index aaf8101..ae4d825 100644 --- a/pkg/dev_compiler/lib/src/compiler/module_builder.dart +++ b/pkg/dev_compiler/lib/src/compiler/module_builder.dart
@@ -494,80 +494,44 @@ return items; } - /// Build statements for [exports]. - // TODO(nshahan): Delete and build the SDK libraries/module like any other. - static List<Statement> temporaryBuildSdkExports( - List<ExportDeclaration> exports) { - var items = <Statement>[]; - if (exports.isNotEmpty) { - for (var export in exports) { - // Dart SDK module must export the libraries via a definition until it - // can be separated into individual libraries. - 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; - } - Program build(Program module) { - if (module is LibraryBundle) { - var body = <ModuleItem>[]; - // Collect imports/exports/statements. - for (var library in module.libraries) { - // Handle each library separately. - imports.clear(); - statements.clear(); + if (module is! LibraryBundle) { + // TODO(nshahan): Delete and update the argument type when this is the + // only supported module format. + throw ArgumentError.value( + module, + '`DdcLibraryBundleBuilder` requires `LibraryBundle`s as input to ' + '`.build()`.'); + } + var body = <ModuleItem>[]; + // Collect imports/exports/statements. + for (var library in module.libraries) { + // Handle each library separately. + imports.clear(); + statements.clear(); - visitProgram(library); - var moduleImports = _collectModuleImports(imports); - var importStatements = <Statement>[]; - for (var p in moduleImports) { - var moduleVar = p.key; - var import = p.value; - importStatements.addAll(buildImports(moduleVar, import)); - } - // Prepend import statements. - statements.insertAll(0, importStatements); - // Package the library into an initialization function. - var initFunction = NamedFunction( - loadFunctionIdentifier(library.name!), - js.fun("function(#) { 'use strict'; #; return #; }", - [library.librarySelfVar!, statements, library.librarySelfVar!]), - true); - var resultModule = js.statement('dartDevEmbedder.defineLibrary(#, #)', - [js.string(library.name!), initFunction]); - body.add(resultModule); - } - // Append all library definitions into a single file. - return Program([...module.header, ...body]); - } else { - // TODO(nshahan): Migrate the SDK to the LibraryBundle format. - // Collect imports/exports/statements. - visitProgram(module); - var importNames = <Expression>[]; + visitProgram(library); var moduleImports = _collectModuleImports(imports); var importStatements = <Statement>[]; for (var p in moduleImports) { var moduleVar = p.key; var import = p.value; - importNames.add(import.from); importStatements.addAll(buildImports(moduleVar, import)); } // Prepend import statements. statements.insertAll(0, importStatements); - // Append export statements. - statements.addAll(temporaryBuildSdkExports(exports)); - // Wrap the SDK statements into a self invoking function. - var moduleName = module.name!; - var resultModule = NamedFunction(loadFunctionIdentifier(moduleName), - js.fun("function() { 'use strict'; #; }", [statements]), true); - var moduleDef = js.statement('#()', [resultModule]); - return Program(<ModuleItem>[...module.header, moduleDef]); + // Package the library into an initialization function. + var initFunction = NamedFunction( + loadFunctionIdentifier(library.name!), + js.fun("function(#) { 'use strict'; #; return #; }", + [library.librarySelfVar!, statements, library.librarySelfVar!]), + true); + var resultModule = js.statement('dartDevEmbedder.defineLibrary(#, #)', + [js.string(library.name!), initFunction]); + body.add(resultModule); } + // Append all library definitions into a single file. + return Program([...module.header, ...body]); } }
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart index 6bce825..6cd1a2c 100644 --- a/pkg/dev_compiler/lib/src/kernel/command.dart +++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -591,9 +591,11 @@ var hierarchy = ClassHierarchy(component, coreTypes); var options = SharedCompilerOptions.fromSdkRequiredArguments(argResults); - var compiler = ProgramCompiler( - component, hierarchy, options, const {}, const {}, - coreTypes: coreTypes); + var compiler = options.emitLibraryBundle + ? LibraryBundleCompiler(component, hierarchy, options, const {}, const {}, + coreTypes: coreTypes) + : ProgramCompiler(component, hierarchy, options, const {}, const {}, + coreTypes: coreTypes); var jsModule = compiler.emitModule(component); var outFiles = <Future>[];
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart index ea955fe..a23f4e0 100644 --- a/pkg/dev_compiler/lib/src/kernel/compiler.dart +++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -542,6 +542,7 @@ /// only in incremental mode, for expression compilation only. @override js_ast.Program emitModule(Component component) { + assert(!_options.emitLibraryBundle); if (_moduleEmitted) { throw StateError('Can only call emitModule once.'); } @@ -922,33 +923,10 @@ _emitLibraryProcedures(library); _emitTopLevelFields(library.fields); } - if (_options.emitLibraryBundle) { - // TODO(nshahan): Remove when the Dart SDK can be compiled with the - // `LibraryBundleCompiler`. - _moduleItems.add(_emitEmptyLinkMethod( - _jsLibraryName(library), _emitLibraryName(library))); - } _staticTypeContext.leaveLibrary(_currentLibrary!); _currentLibrary = null; } - /// Returns an empty placeholder link method for the libraries in the SDK. - /// - /// This is a temporary solution to allow the Dart SDK to act like it was - /// compiled as a bundle of individual libraries. - // TODO(nshahan): Remove when the Dart SDK can be compiled with the - // `LibraryBundleCompiler`. - js_ast.Statement _emitEmptyLinkMethod( - String libraryName, js_ast.Identifier libraryId) { - assert(_options.emitLibraryBundle && _isBuildingSdk); - var functionName = _emitTemporaryId('link__$libraryName'); - return js.statement('# = #', [ - js_ast.PropertyAccess.field(libraryId, 'link'), - js_ast.NamedFunction( - functionName, js_ast.Fun(const [], js_ast.Block(const []))) - ]); - } - void _emitExports(Library library) { assert(_currentLibrary == null); _currentLibrary = library; @@ -7974,71 +7952,38 @@ items.add(js.statement('#.library = #', [_runtimeModule, libraryProto])); exports.add(js_ast.NameSpecifier(_runtimeModule)); } - 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])); + for (var library in libraries) { + if (_isBuildingSdk && _isSdkInternalRuntime(library)) { + _libraries[library] = _runtimeModule; + continue; } - // 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)); + 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)); - } - - // 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))); + // 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))); + if (_isBuildingSdk) { // Initialize the private name function. // To bootstrap the SDK, this needs to be emitted before other code. @@ -8299,15 +8244,6 @@ /// field of the result. js_ast.Program _finishModule(List<js_ast.ModuleItem> items, String moduleName, {List<js_ast.Comment> header = const []}) { - if (_options.emitLibraryBundle) { - assert(_isBuildingSdk); - // Manually add a link method for the runtime "dartx" library. It is - // synthetically created by DDC and doesn't have an associated kernel - // library node. - // TODO(nshahan): Remove when the Dart SDK can be compiled with the - // `LibraryBundleCompiler`. - _moduleItems.add(_emitEmptyLinkMethod('dartx', _extensionSymbolsModule)); - } // TODO(jmesserly): there's probably further consolidation we can do // between DDC's two backends, by moving more code into this method, as the // code between `startModule` and `finishModule` is very similar in both.
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler_new.dart b/pkg/dev_compiler/lib/src/kernel/compiler_new.dart index 9e70a5f..3e52d8f 100644 --- a/pkg/dev_compiler/lib/src/kernel/compiler_new.dart +++ b/pkg/dev_compiler/lib/src/kernel/compiler_new.dart
@@ -121,6 +121,7 @@ @override js_ast.Program emitModule(Component component) { + assert(_options.emitLibraryBundle); _ticker?.logMs('Emitting library bundle'); var compiledLibraries = <js_ast.Program>[]; for (var library in component.libraries) { @@ -889,14 +890,6 @@ [_emitLibraryName(_rtiLibrary)]).toStatement()); }); } - // Visit directives (for exports) - _emitExports(library); - _ticker?.logMs('Emitted exports'); - - // Declare imports and extension symbols - _emitImportsAndExtensionSymbols(items, - forceExtensionSymbols: allowedNativeTest(library.importUri)); - _ticker?.logMs('Emitted imports and extension symbols'); // Insert a check that runs when loading this module to verify that the null // safety mode it was compiled in matches the mode used when compiling the @@ -926,6 +919,15 @@ _moduleItems.add(_emitLibraryLinkMethod(_currentLibrary!)); _ticker?.logMs('Emitted library link method'); + // Visit directives (for exports) + _emitExports(library); + _ticker?.logMs('Emitted exports'); + + // Declare imports and extension symbols + _emitImportsAndExtensionSymbols(items, + forceExtensionSymbols: allowedNativeTest(library.importUri)); + _ticker?.logMs('Emitted imports and extension symbols'); + // Emit the hoisted type table cache variables items.addAll(_typeTable.dischargeBoundTypes()); _ticker?.logMs('Emitted type table'); @@ -8023,12 +8025,8 @@ for (var import in _imports.keys) { modules.putIfAbsent(_libraryToModule(import), () => []).add(import); } - - String? coreModuleName; - if (!_libraries.containsKey(_coreLibrary)) { - coreModuleName = _libraryToModule(_coreLibrary); - } - + // TODO(nshahan): Update this code and the representation of + // `ImportDeclaration`s when other module formats are no longer supported. modules.forEach((module, libraries) { if (!_incrementalMode || _incrementalModules.containsKey(module)) { var usedLibraries = _incrementalModules[module]; @@ -8060,24 +8058,11 @@ } } } - if (module == coreModuleName) { - if (!_incrementalMode || - usedLibraries!.contains(_runtimeLibraryId.name)) { - items.add(js_ast.ImportDeclaration( - from: js.string('dart:_runtime'), - namedImports: [js_ast.NameSpecifier(_runtimeLibraryId)])); - } - if (!_incrementalMode || - usedLibraries!.contains(_extensionSymbolsLibraryId.name)) { - items.add(js_ast.ImportDeclaration( - from: js.string(_extensionSymbolHolderName), - namedImports: [ - js_ast.NameSpecifier(_extensionSymbolsLibraryId) - ])); - } - } } }); + items.add(js_ast.ImportDeclaration( + from: js.string(_extensionSymbolHolderName), + namedImports: [js_ast.NameSpecifier(_extensionSymbolsLibraryId)])); } /// Emits extension methods into [items].