diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md index a934fd496..155a7fa3a 100644 --- a/dwds/CHANGELOG.md +++ b/dwds/CHANGELOG.md @@ -1,3 +1,15 @@ +## 12.0.0-dev + +- Add code for loading symbols generated by DDC, if + `enableDebugSymbols` is set to `true` in `dwds.start`. + To be used by variable inspection, not implemented yet. +- Require at least `build_web_compilers` version `3.1.0`. +- Update min sdk constraint to `>=2.14.0-216.0.dev`. + +**Breaking changes:** + - Add `enableDebugSymbols` parameter `Dwds.start`, false by default. + - Add `symbolsContents` method to `AssetReader`. + ## 11.1.2-dev - Return empty library from `ChromeProxyService.getObject` for diff --git a/dwds/lib/dwds.dart b/dwds/lib/dwds.dart index 5c385aae0..adf2c2a1c 100644 --- a/dwds/lib/dwds.dart +++ b/dwds/lib/dwds.dart @@ -27,6 +27,7 @@ import 'src/services/expression_compiler.dart'; export 'src/connections/app_connection.dart' show AppConnection; export 'src/connections/debug_connection.dart' show DebugConnection; +export 'src/debugging/metadata/module_metadata.dart' show ModuleInfo; export 'src/debugging/metadata/provider.dart' show MetadataProvider, AbsoluteImportUriException; export 'src/events.dart' show DwdsEvent; @@ -46,7 +47,7 @@ export 'src/readers/proxy_server_asset_reader.dart' show ProxyServerAssetReader; export 'src/servers/devtools.dart'; export 'src/services/chrome_proxy_service.dart' show ChromeDebugException; export 'src/services/expression_compiler.dart' - show ExpressionCompilationResult, ExpressionCompiler, ModuleInfo; + show ExpressionCompilationResult, ExpressionCompiler; export 'src/services/expression_compiler_service.dart' show ExpressionCompilerService; @@ -100,6 +101,7 @@ class Dwds { // TODO(annagrin): make expressionCompiler argument required // [issue 881](https://github.com/dart-lang/webdev/issues/881) ExpressionCompiler expressionCompiler, + bool enableDebugSymbols, bool enableDebugExtension, String hostname, bool useSseForDebugProxy, @@ -119,6 +121,7 @@ class Dwds { enableDevtoolsLaunch ??= true; spawnDds ??= true; globalLoadStrategy = loadStrategy; + enableDebugSymbols ??= false; DevTools devTools; String extensionUri; @@ -171,6 +174,7 @@ class Dwds { useSseForInjectedClient, serveDevTools, expressionCompiler, + enableDebugSymbols, injected, spawnDds, ); diff --git a/dwds/lib/src/debugging/metadata/module_metadata.dart b/dwds/lib/src/debugging/metadata/module_metadata.dart index 9dee52820..cb3a6d3a5 100644 --- a/dwds/lib/src/debugging/metadata/module_metadata.dart +++ b/dwds/lib/src/debugging/metadata/module_metadata.dart @@ -176,3 +176,14 @@ class ModuleMetadata { }; } } + +class ModuleInfo { + final String fullDillPath; + final String summaryPath; + final String symbolsPath; + + ModuleInfo(this.fullDillPath, this.summaryPath, this.symbolsPath); + + @override + String toString() => '{ $fullDillPath, $summaryPath, $symbolsPath }'; +} diff --git a/dwds/lib/src/debugging/metadata/module_symbols.dart b/dwds/lib/src/debugging/metadata/module_symbols.dart new file mode 100644 index 000000000..b6de8d4ee --- /dev/null +++ b/dwds/lib/src/debugging/metadata/module_symbols.dart @@ -0,0 +1,757 @@ +// Copyright (c) 2021, 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. + +// @dart = 2.9 + +// Dart debug symbol information stored by DDC. +// +// The data format below stores descriptions of dart code objects and their +// mapping to JS that is generated by DDC. Every field, except ids, describes +// dart. + +// Note that 'localId' and 'scopeId' combine into a unique id that is used for +// object lookup and mapping between JS and dart concepts. As a result, it +// needs to be either stored or easily computed for each corresponding JS object +// created by DDC, so the debugger is able to look up dart symbol from JS ones. +// +// For example, to detect all dart variables in the current scope and display +// their values, the debugger can do the following: +// +// - map current JS location to dart location using source maps +// - find all nested dart scopes that include the current dart location +// - collect all dart variables in scope +// - look up corresponding variables and their values in JS scope by their +// JS ids +// - display their values (non-expanded) +// +// To display a JS value of variable 'v' (non-expanded) +// +// - v: (jsvalue.toString()) +// +// Where is the dart type of the dart variable 'v' +// at runtime. +// +// TODO: describe displaying specific non-expanded JS instances in dart +// way, for example, lists, maps, types - is JS toString() enough? +// +// To display a value (expanded) +// +// - look up the JS runtime type of the value +// - find the dart value's runtime type by JS id value's runtime type id +// - collect all dart fields of that type, including the inherited fields +// - map dart fields to JS field ids and look up their values using object +// ids referenced by the original displayed value. +// - display their values (non-expanded) + +class SemanticVersion { + final int major; + final int minor; + final int patch; + + const SemanticVersion( + this.major, + this.minor, + this.patch, + ); + + static SemanticVersion parse(String version) { + var parts = version.split('.'); + if (parts.length != 3) { + throw FormatException('Version: $version ' + 'does not follow simple semantic versioning format'); + } + var major = int.parse(parts[0]); + var minor = int.parse(parts[1]); + var patch = int.parse(parts[2]); + + return SemanticVersion(major, minor, patch); + } + + /// Text version. + String get version => '$major.$minor.$patch'; + + /// True if this version is compatible with [version]. + /// + /// The minor and patch version changes never remove any fields that current + /// version supports, so the reader can create current metadata version from + /// any file created with a later reader, as long as the major version does + /// not change. + bool isCompatibleWith(String version) { + var other = parse(version); + return other.major == major && other.minor >= minor && other.patch >= patch; + } +} + +/// Base class for a symbol table element. +/// +/// Symbol tables and its elements are stored by the compiler using +/// [toJson] method, and are read from json using `fromJson` constructors. +abstract class SymbolTableElement { + Map toJson(); +} + +class ModuleSymbols implements SymbolTableElement { + /// Current symbol information version. + /// + /// Version follows simple semantic versioning format 'major.minor.patch' + /// See https://semver.org + static const SemanticVersion current = SemanticVersion(0, 0, 1); + + /// Semantic version of the format. + String version; + + /// Module name as used in the module metadata + String moduleName; + + /// All dart libraries included in the module. + /// + /// Note here and below that imported elements are not included in + /// the current module but can be referenced by their ids. + List libraries; + + /// All dart scripts included in the module. + List