Skip to content

Commit 65ce9ed

Browse files
srujzsCommit Queue
authored andcommitted
Add debugger runtime APIs and add/modify tests
- Exposes a minimum set of APIs that are needed by DWDS a single class Debugger. - Renames some APIs and modifies the signature to better align with what's happening and what DWDS actually uses. Similarly, modifies the internal APIs to handle the new format. - Modifies expression evaluation test suite to handle the new module format correctly. - Modifies LibraryBundleCompiler to emit the right export name. - Adds/adapts existing tests for the runtime debugger APIs. With this, all tests within pkg/dev_compiler/test/expression_compiler pass with the new module format with the exception of two tests within expression_compiler_e2e_ddc_null_safe_test, which will be fixed in a future CL. Change-Id: I296496441ea421ecb57bed3b2e90b92365fef510 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/391308 Reviewed-by: Nicholas Shahan <[email protected]> Commit-Queue: Srujan Gaddam <[email protected]>
1 parent 98c6d50 commit 65ce9ed

File tree

10 files changed

+522
-110
lines changed

10 files changed

+522
-110
lines changed

pkg/dev_compiler/lib/js/ddc/ddc_module_loader.js

Lines changed: 298 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1622,8 +1622,297 @@ if (!self.deferred_loader) {
16221622
}
16231623
}
16241624

1625+
// This is closed-upon to avoid exposing it through the `dartDevEmbedder`.
16251626
const libraryManager = new LibraryManager();
16261627

1628+
function dartDebuggerLibrary() {
1629+
return libraryManager.initializeAndLinkLibrary('dart:_debugger');
1630+
}
1631+
1632+
function dartDeveloperLibrary() {
1633+
return libraryManager.initializeAndLinkLibrary('dart:developer')
1634+
}
1635+
1636+
function dartRuntimeLibrary() {
1637+
return libraryManager.initializeAndLinkLibrary('dart:_runtime');
1638+
}
1639+
1640+
/**
1641+
* Common debugging APIs that may be useful for metadata, invocations,
1642+
* developer extensions, bootstrapping, and more.
1643+
*/
1644+
// TODO(56966): A number of APIs in this class consume and return Dart
1645+
// objects, nested or otherwise. We should replace them with some kind of
1646+
// metadata instead so users don't accidentally rely on the object's
1647+
// representation. For now, we warn users to not do so in the APIs below.
1648+
class Debugger {
1649+
/**
1650+
* Returns a JavaScript array of all class names in a Dart library.
1651+
*
1652+
* @param {string} libraryUri URI of the Dart library.
1653+
* @returns {Array<string>} Array containing the class names in the library.
1654+
*/
1655+
getClassesInLibrary(libraryUri) {
1656+
return dartRuntimeLibrary().getLibraryMetadata(libraryUri, libraryManager.libraries);
1657+
}
1658+
1659+
/**
1660+
* Returns a JavaScript object containing metadata of a class in a given
1661+
* Dart library.
1662+
*
1663+
* The object will be formatted as such:
1664+
* ```
1665+
* {
1666+
* 'className': <dart class name>,
1667+
* 'superClassName': <super class name, if any>
1668+
* 'superClassLibraryId': <super class library ID, if any>
1669+
* 'fields': {
1670+
* <name>: {
1671+
* 'isConst': <true if the member is const>,
1672+
* 'isFinal': <true if the member is final>,
1673+
* 'isStatic': <true if the member is final>,
1674+
* 'className': <class name for a field type>,
1675+
* 'classLibraryId': <library id for a field type>,
1676+
* }
1677+
* },
1678+
* 'methods': {
1679+
* <name>: {
1680+
* 'isConst': <true if the member is const>,
1681+
* 'isStatic': <true if the member is static>,
1682+
* 'isSetter" <true if the member is a setter>,
1683+
* 'isGetter" <true if the member is a getter>,
1684+
* }
1685+
* },
1686+
* }
1687+
* ```
1688+
*
1689+
* @param {string} libraryUri URI of the Dart library that the class is in.
1690+
* @param {string} name Name of the Dart class.
1691+
* @param {any} objectInstance Optional instance of the Dart class that's
1692+
* needed to determine the type of any generic members.
1693+
* @returns {Object<String, any>} Object containing the metadata in the
1694+
* above format.
1695+
*/
1696+
getClassMetadata(libraryUri, name, objectInstance) {
1697+
return dartRuntimeLibrary().getClassMetadata(libraryUri, name, objectInstance, libraryManager.libraries);
1698+
}
1699+
1700+
/**
1701+
* Returns a JavaScript object containing metadata about a Dart value.
1702+
*
1703+
* The object will be formatted as such:
1704+
* ```
1705+
* {
1706+
* 'className': <dart class name>,
1707+
* 'libraryId': <library URI for the object type>,
1708+
* 'runtimeKind': <kind of the object for display purposes>,
1709+
* 'length': <length of the object if applicable>,
1710+
* 'typeName': <name of the type represented if object is a Type>,
1711+
* }
1712+
* ```
1713+
*
1714+
* @param {Object} value Dart value for which metadata is computed.
1715+
* @returns {Object<String, any>} Object containing the metadata in the
1716+
* above format.
1717+
*/
1718+
getObjectMetadata(value) {
1719+
return dartRuntimeLibrary().getObjectMetadata(value);
1720+
}
1721+
1722+
/**
1723+
* Returns the name of the given function. If it's bound to an object of
1724+
* class `C`, returns `C.<name>` instead.
1725+
*
1726+
* @param {Object} fun Dart function for which the name is returned.
1727+
* @returns {string} Name of the given function in the above format.
1728+
*/
1729+
getFunctionName(fun) {
1730+
return dartRuntimeLibrary().getFunctionMetadata(fun);
1731+
}
1732+
1733+
/**
1734+
* Returns an array of all the field names in the Dart object.
1735+
*
1736+
* @param {Object} object Dart object whose field names are collected.
1737+
* @returns {Array<string>} Array of field names.
1738+
*/
1739+
getObjectFieldNames(object) {
1740+
return dartRuntimeLibrary().getObjectFieldNames(object);
1741+
}
1742+
1743+
/**
1744+
* If given a Dart `Set`, `List`, or `Map`, returns a sub-range array of at
1745+
* most the given number of elements starting at the given offset. If given
1746+
* any other Dart value, returns the original value. Any Dart values
1747+
* returned from this API should be treated as opaque pointers and should
1748+
* not be interacted with.
1749+
*
1750+
* @param {Object} object Dart object for which the sub-range is computed.
1751+
* @param {number} offset Integer index at which the sub-range should start.
1752+
* @param {number} count Integer number of values in the sub-range.
1753+
* @returns {any} Either the sub-range or the original object.
1754+
*/
1755+
getSubRange(object, offset, count) {
1756+
return dartRuntimeLibrary().getSubRange(object, offset, count);
1757+
}
1758+
1759+
/**
1760+
* Returns a JavaScript object containing the entries for a given Dart `Map`
1761+
* that will be formatted as:
1762+
*
1763+
* ```
1764+
* {
1765+
* 'keys': [ <key>, ...],
1766+
* 'values': [ <value>, ...],
1767+
* }
1768+
* ```
1769+
*
1770+
* Any Dart values returned from this API should be treated as opaque
1771+
* pointers and should not be interacted with.
1772+
*
1773+
* @param {Object} map Dart `Map` whose entries will be copied.
1774+
* @returns {Object<String, Array>} Object containing the entries in
1775+
* the above format.
1776+
*/
1777+
getMapElements(map) {
1778+
return dartRuntimeLibrary().getMapElements(map);
1779+
}
1780+
1781+
/**
1782+
* Returns a JavaScript object containing the entries for a given Dart `Set`
1783+
* that will be formatted as:
1784+
*
1785+
* ```
1786+
* {
1787+
* 'entries': [ <entry>, ...],
1788+
* }
1789+
* ```
1790+
*
1791+
* Any Dart values returned from this API should be treated as opaque
1792+
* pointers and should not be interacted with.
1793+
*
1794+
* @param {Object} set Dart `Set` whose entries will be copied.
1795+
* @returns {Object<String, Array} Object containing the entries in the
1796+
* above format.
1797+
*/
1798+
getSetElements(set) {
1799+
return dartRuntimeLibrary().getSetElements(set);
1800+
}
1801+
1802+
/**
1803+
* Returns a JavaScript object containing metadata for a given Dart `Record`
1804+
* that will be formatted as:
1805+
*
1806+
* ```
1807+
* {
1808+
* 'positionalCount': <number of positional elements>,
1809+
* 'named': [ <name>, ...],
1810+
* 'values': [ <positional value>, ..., <named value>, ... ],
1811+
* }
1812+
* ```
1813+
*
1814+
* Any Dart values returned from this API should be treated as opaque
1815+
* pointers and should not be interacted with.
1816+
*
1817+
* @param {Object} record Dart `Record` whose metadata will be computed.
1818+
* @returns {Object<String, any>} Object containing the metadata in the
1819+
* above format.
1820+
*/
1821+
getRecordFields(record) {
1822+
return dartRuntimeLibrary().getRecordFields(record);
1823+
}
1824+
1825+
/**
1826+
* Returns a JavaScript object containing metadata for a given Dart
1827+
* `Record`'s runtime type that will be formatted as:
1828+
*
1829+
* ```
1830+
* {
1831+
* 'positionalCount': <number of positional types>,
1832+
* 'named': [ <name>, ...],
1833+
* 'types': [ <positional type>, ..., <named type>, ... ],
1834+
* }
1835+
* ```
1836+
*
1837+
* Any Dart values returned from this API should be treated as opaque
1838+
* pointers and should not be interacted with.
1839+
*
1840+
* @param {Object} recordType Dart `Type` of a `Record` whose metadata will
1841+
* be computed.
1842+
* @returns {Object<String, any>} Object containing the metadata in the
1843+
* above format.
1844+
*/
1845+
getRecordTypeFields(recordType) {
1846+
return dartRuntimeLibrary().getRecordTypeFields(recordType);
1847+
}
1848+
1849+
/**
1850+
* Given a Dart instance, calls the method with the given name in that
1851+
* instance and returns the result.
1852+
*
1853+
* Any Dart values returned from this API should be treated as opaque
1854+
* pointers and should not be interacted with.
1855+
*
1856+
* @param {Object} instance Dart instance whose method will be called.
1857+
* @param {string} name Name of the method.
1858+
* @param {Array} args Array of arguments passed to the method.
1859+
* @returns {any} Result of calling the method.
1860+
*/
1861+
callInstanceMethod(instance, name, args) {
1862+
return dartRuntimeLibrary().dsendRepl(instance, name, args);
1863+
}
1864+
1865+
/**
1866+
* Given a Dart library URI, calls the method with the given name in that
1867+
* library and returns the result.
1868+
*
1869+
* Any Dart values returned from this API should be treated as opaque
1870+
* pointers and should not be interacted with.
1871+
*
1872+
* @param {any} libraryUri Dart library URI in which the method exists.
1873+
* @param {string} name Name of the method.
1874+
* @param {Array} args Array of arguments passed to the method.
1875+
* @returns {any} Result of calling the method.
1876+
*/
1877+
callLibraryMethod(libraryUri, name, args) {
1878+
let library = libraryManager.initializeAndLinkLibrary(libraryUri);
1879+
return library[name].apply(library, args);
1880+
}
1881+
1882+
/**
1883+
* Register the DDC Chrome DevTools custom formatter into the global
1884+
* `devtoolsFormatters` property.
1885+
*/
1886+
registerDevtoolsFormatter() {
1887+
dartDebuggerLibrary().registerDevtoolsFormatter();
1888+
}
1889+
1890+
/**
1891+
* Invoke a registered extension with the given name and encoded map.
1892+
*
1893+
* @param {String} methodName The name of the registered extension.
1894+
* @param {String} encodedJson The encoded string map that will be passed as
1895+
* a parameter to the invoked method.
1896+
* @returns {Promise} Promise that will await the invocation of the
1897+
* extension.
1898+
*/
1899+
invokeExtension(methodName, encodedJson) {
1900+
return dartDeveloperLibrary().invokeExtension(methodName, encodedJson);
1901+
}
1902+
1903+
/**
1904+
* Returns a JavaScript array containing the names of the extensions
1905+
* registered in `dart:developer`.
1906+
*
1907+
* @returns {Array<string>} Array containing the extension names.
1908+
*/
1909+
get extensionNames() {
1910+
return dartDeveloperLibrary()._extensions.keys().toList();
1911+
}
1912+
}
1913+
1914+
const debugger_ = new Debugger();
1915+
16271916
/** The API for embedding a Dart application in the page at development time
16281917
* that supports stateful hot reloading.
16291918
*/
@@ -1710,7 +1999,7 @@ if (!self.deferred_loader) {
17101999

17112000
/**
17122001
* @return {Number} The current hot reload generation of the running
1713-
* application.
2002+
* application.
17142003
*/
17152004
get hotReloadGeneration() {
17162005
return libraryManager.hotReloadGeneration;
@@ -1723,6 +2012,14 @@ if (!self.deferred_loader) {
17232012
get hotRestartGeneration() {
17242013
return libraryManager.hotRestartGeneration;
17252014
}
2015+
2016+
/**
2017+
* @return {Debugger} Common debugging APIs that may be useful for metadata,
2018+
* invocations, developer extensions, bootstrapping, and more.
2019+
*/
2020+
get debugger() {
2021+
return debugger_;
2022+
}
17262023
}
17272024

17282025
self.dartDevEmbedder = new DartDevEmbedder();

pkg/dev_compiler/lib/src/compiler/module_builder.dart

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,6 @@ Program transformModuleFormat(ModuleFormat format, Program module) {
100100

101101
/// Transforms an ES6 [function] into a given module [format].
102102
///
103-
/// If the format is [ModuleFormat.es6] this will return [function] unchanged.
104-
///
105103
/// Because JS ASTs are immutable the resulting function will share as much
106104
/// structure as possible with the original. The transformation is a shallow one
107105
/// that affects the [ImportDeclaration]s from [items].
@@ -115,6 +113,9 @@ Fun transformFunctionModuleFormat(
115113
return DdcModuleBuilder().buildFunctionWithImports(items, function);
116114
case ModuleFormat.amd:
117115
return AmdModuleBuilder().buildFunctionWithImports(items, function);
116+
case ModuleFormat.ddcLibraryBundle:
117+
return DdcLibraryBundleBuilder()
118+
.buildFunctionWithImports(items, function);
118119
default:
119120
throw UnsupportedError(
120121
'Incremental build does not support $format module format');
@@ -494,6 +495,33 @@ class DdcLibraryBundleBuilder extends _ModuleBuilder {
494495
return items;
495496
}
496497

498+
/// Build function body with all necessary imports included.
499+
///
500+
/// Used for the top level synthetic function generated during expression
501+
/// compilation, in order to include all the context needed for evaluation
502+
/// inside it.
503+
///
504+
/// Returns a new function that combines all statements from transformed
505+
/// imports from [items] and the body of the [function].
506+
Fun buildFunctionWithImports(List<ModuleItem> items, Fun function) {
507+
clear();
508+
visitModuleItems(items);
509+
510+
var moduleImports = _collectModuleImports(imports);
511+
var importStatements = <Statement>[];
512+
513+
for (var p in moduleImports) {
514+
var moduleVar = p.key;
515+
var import = p.value;
516+
importStatements.addAll(buildImports(moduleVar, import));
517+
}
518+
519+
return Fun(
520+
function.params,
521+
Block([...importStatements, ...statements, ...function.body.statements]),
522+
);
523+
}
524+
497525
Program build(Program module) {
498526
if (module is! LibraryBundle) {
499527
// TODO(nshahan): Delete and update the argument type when this is the

pkg/dev_compiler/lib/src/kernel/compiler_new.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8228,7 +8228,8 @@ class LibraryCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
82288228
});
82298229

82308230
items.add(js_ast.ImportDeclaration(
8231-
namedImports: exports, from: js.string(module, "'")));
8231+
namedImports: exports,
8232+
from: js.string(current.importUri.toString(), "'")));
82328233
}
82338234
}
82348235

0 commit comments

Comments
 (0)