Skip to content

Commit

Permalink
Use DDC runtime debugger API (#2159)
Browse files Browse the repository at this point in the history
* Use DDC debugger API

* Fix analyzer warnings

* Cleanup

* Run instance tests with frontend server and build daemon

* Add canary option to webdev and expression compiler worker

* Update for latest sdk changes

* cleanup and add tests

* Updated issue reference

* Remove unused API

* Try making it work with current sdk changes

* Cleanup

* Cleanup

* Cleanup

* Cleanup

* Update SDK min consrraint to require new debugger runtime API

* Cleanup

* Temporarily only test on main

* More running on main

* More running on main

* More running on main

* Fix failing webdev test

* Remove unnecessary asyncs

* Run type system verification tests for non-canary mode as well

* Now run CI on dev
  • Loading branch information
Anna Gringauze authored Aug 3, 2023
1 parent 87bd77f commit db1f552
Show file tree
Hide file tree
Showing 52 changed files with 856 additions and 876 deletions.
200 changes: 100 additions & 100 deletions .github/workflows/dart.yml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dwds/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
- Require clients to specify the `basePath` on `AssetReader`. - [#2160](https://github.com/dart-lang/webdev/pull/2160)
- Update SDK constraint to `>=3.1.0-254.0.dev <4.0.0`. - [#2169](https://github.com/dart-lang/webdev/pull/2169)
- Require min `build_web_compilers` version `4.0.4` - [#2171](https://github.com/dart-lang/webdev/pull/2171)
- Switch to using new debugging API from DDC to support new type system. - [#2159](https://github.com/dart-lang/webdev/pull/2159)

## 19.0.2

Expand Down
2 changes: 1 addition & 1 deletion dwds/debug_extension/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: >-
A chrome extension for Dart debugging.
environment:
sdk: ">=3.1.0-254.0.dev <4.0.0"
sdk: ">=3.1.0-340.0.dev <4.0.0"

dependencies:
async: ^2.3.0
Expand Down
2 changes: 1 addition & 1 deletion dwds/debug_extension_mv3/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: >-
A Chrome extension for Dart debugging.
environment:
sdk: ">=3.1.0-254.0.dev <4.0.0"
sdk: ">=3.1.0-340.0.dev <4.0.0"

dependencies:
built_value: ^8.3.0
Expand Down
139 changes: 24 additions & 115 deletions dwds/lib/src/debugging/classes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -77,88 +77,12 @@ class ClassHelper extends Domain {

if (libraryUri == null || classId == null || className == null) return null;

final rawName = className.split('<').first;
final expression = '''
(function() {
${globalLoadStrategy.loadLibrarySnippet(libraryUri)}
var result = {};
var clazz = library["$rawName"];
var descriptor = {
'name': clazz.name,
'dartName': sdkUtils.typeName(clazz)
};
// TODO(grouma) - we display all inherited methods since we don't provide
// the superClass information. This is technically not correct.
var proto = clazz.prototype;
var methodNames = [];
for (; proto != null; proto = Object.getPrototypeOf(proto)) {
var methods = Object.getOwnPropertyNames(proto);
for (var i = 0; i < methods.length; i++) {
if (methodNames.indexOf(methods[i]) == -1
&& methods[i] != 'constructor') {
methodNames.push(methods[i]);
}
}
if (proto.constructor.name == 'Object') break;
}
descriptor['methods'] = {};
for (var name of methodNames) {
descriptor['methods'][name] = {
// TODO(jakemac): how can we get actual const info?
"isConst": false,
"isStatic": false,
}
}
var fields = sdkUtils.getFields(clazz);
var fieldNames = fields ? Object.keys(fields) : [];
descriptor['fields'] = {};
for (var name of fieldNames) {
var field = fields[name];
var libraryUri = Object.getOwnPropertySymbols(fields[name]["type"])
.find(x => x.description == "libraryUri");
descriptor['fields'][name] = {
// TODO(jakemac): how can we get actual const info?
"isConst": false,
"isFinal": field.isFinal,
"isStatic": false,
"classRefName": fields[name]["type"]["name"],
"classRefDartName": sdkUtils.typeName(fields[name]["type"]),
"classRefLibraryId" : field["type"][libraryUri],
}
}
// TODO(elliette): The following static member information is minimal and
// should be replaced once DDC provides full symbol information (see
// https://github.com/dart-lang/sdk/issues/40273):
descriptor['staticFields'] = {};
var staticFieldNames = sdkUtils.getStaticFields(clazz) ?? [];
for (const name of staticFieldNames) {
descriptor['staticFields'][name] = {
"isStatic": true,
// DDC only provides names of static members, we set isConst/isFinal
// to false even though they could be true.
"isConst": false,
"isFinal": false,
}
}
descriptor['staticMethods'] = {};
var staticMethodNames = sdkUtils.getStaticMethods(clazz) ?? [];
for (var name of staticMethodNames) {
descriptor['methods'][name] = {
// DDC only provides names of static members, we set isConst
// to false even though it could be true.
"isConst": false,
"isStatic": true,
}
}
return descriptor;
})()
(function() {
const sdk = ${globalLoadStrategy.loadModuleSnippet}('dart_sdk');
const dart = sdk.dart;
return dart.getClassMetadata('$libraryUri', '$className');
})()
''';

RemoteObject result;
Expand All @@ -176,35 +100,34 @@ class ClassHelper extends Domain {
final methodRefs = <FuncRef>[];
final methodDescriptors =
classDescriptor['methods'] as Map<String, dynamic>;
final staticMethodDescriptors =
classDescriptor['staticMethods'] as Map<String, dynamic>;
methodDescriptors.addAll(staticMethodDescriptors);
methodDescriptors.forEach((name, descriptor) {
final methodId = 'methods|$classId|$name';
methodRefs.add(
FuncRef(
id: methodId,
name: name,
owner: classRef,
isConst: descriptor['isConst'] as bool,
isStatic: descriptor['isStatic'] as bool,
// TODO(annagrin): get information about getters and setters from symbols.
// https://github.com/dart-lang/sdk/issues/46723
implicit: false,
isConst: descriptor['isConst'] as bool? ?? false,
isStatic: descriptor['isStatic'] as bool? ?? false,
implicit: descriptor['isImplicit'] as bool? ?? false,
isAbstract: descriptor['isAbstract'] as bool? ?? false,
isGetter: descriptor['isGetter'] as bool? ?? false,
isSetter: descriptor['isSetter'] as bool? ?? false,
),
);
});
final fieldRefs = <FieldRef>[];

final fieldDescriptors = classDescriptor['fields'] as Map<String, dynamic>;
fieldDescriptors.forEach((name, descriptor) {
final classMetaData = ClassMetaData(
jsName: descriptor['classRefName'],
runtimeKind: RuntimeObjectKind.type,
classRef: classRefFor(
descriptor['classRefLibraryId'],
descriptor['classRefDartName'],
descriptor['classLibraryId'],
descriptor['className'],
),
);

fieldRefs.add(
FieldRef(
name: name,
Expand All @@ -215,34 +138,19 @@ class ClassHelper extends Domain {
kind: classMetaData.kind,
classRef: classMetaData.classRef,
),
isConst: descriptor['isConst'] as bool,
isFinal: descriptor['isFinal'] as bool,
isStatic: descriptor['isStatic'] as bool,
isConst: descriptor['isConst'] as bool? ?? false,
isFinal: descriptor['isFinal'] as bool? ?? false,
isStatic: descriptor['isStatic'] as bool? ?? false,
id: createId(),
),
);
});

final staticFieldDescriptors =
classDescriptor['staticFields'] as Map<String, dynamic>;
staticFieldDescriptors.forEach((name, descriptor) {
fieldRefs.add(
FieldRef(
name: name,
owner: classRef,
declaredType: InstanceRef(
identityHashCode: createId().hashCode,
id: createId(),
kind: InstanceKind.kType,
classRef: classRef,
),
isConst: descriptor['isConst'] as bool,
isFinal: descriptor['isFinal'] as bool,
isStatic: descriptor['isStatic'] as bool,
id: createId(),
),
);
});
final superClassLibraryId = classDescriptor['superClassLibraryId'];
final superClassName = classDescriptor['superClassName'];
final superClassRef = superClassName == null
? null
: classRefFor(superClassLibraryId, superClassName);

// TODO: Implement the rest of these
// https://github.com/dart-lang/webdev/issues/176.
Expand All @@ -257,6 +165,7 @@ class ClassHelper extends Domain {
subclasses: [],
id: classId,
traceAllocations: false,
superClass: superClassRef,
);
}
}
47 changes: 16 additions & 31 deletions dwds/lib/src/debugging/inspector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -349,11 +349,14 @@ class AppInspector implements AppInspectorInterface {
throwInvalidParam('invoke', 'library uri is null');
}
final findLibrary = '''
(function() {
${globalLoadStrategy.loadLibrarySnippet(libraryUri)};
return library;
})();
''';
(function() {
const sdk = ${globalLoadStrategy.loadModuleSnippet}('dart_sdk');
const dart = sdk.dart;
const library = dart.getLibrary('$libraryUri');
if (!library) throw 'cannot find library for $libraryUri';
return library;
})();
''';
final remoteLibrary = await jsEvaluate(findLibrary);
return jsCallFunctionOn(remoteLibrary, jsFunction, arguments);
}
Expand Down Expand Up @@ -601,15 +604,6 @@ class AppInspector implements AppInspectorInterface {
.toList();
}

/// Compute the last possible element index in the range of [offset]..end
/// that includes [count] elements, if available.
static int? _calculateRangeEnd({
int? count,
required int offset,
required int length,
}) =>
count == null ? null : math.min(offset + count, length);

/// Calculate the number of available elements in the range.
static int _calculateRangeCount({
int? count,
Expand All @@ -634,30 +628,21 @@ class AppInspector implements AppInspectorInterface {
// TODO(#809): Sometimes we already know the type of the object, and
// we could take advantage of that to short-circuit.
final receiver = remoteObjectFor(id);
final end =
_calculateRangeEnd(count: count, offset: offset, length: length);
final rangeCount =
_calculateRangeCount(count: count, offset: offset, length: length);
final args =
[offset, rangeCount, end].map(dartIdFor).map(remoteObjectFor).toList();
[offset, rangeCount].map(dartIdFor).map(remoteObjectFor).toList();
// If this is a List, just call sublist. If it's a Map, get the entries, but
// avoid doing a toList on a large map using skip/take to get the section we
// want. To make those alternatives easier in JS, pass both count and end.
final expression = '''
function (offset, count, end) {
const sdk = ${globalLoadStrategy.loadModuleSnippet}("dart_sdk");
if (sdk.core.Map.is(this)) {
const entries = sdk.dart.dload(this, "entries");
const skipped = sdk.dart.dsend(entries, "skip", [offset])
const taken = sdk.dart.dsend(skipped, "take", [count]);
return sdk.dart.dsend(taken, "toList", []);
} else if (sdk.core.List.is(this)) {
return sdk.dart.dsendRepl(this, "sublist", [offset, end]);
} else {
return this;
}
}
''';
function (offset, count) {
const sdk = ${globalLoadStrategy.loadModuleSnippet}("dart_sdk");
const dart = sdk.dart;
return dart.getSubRange(this, offset, count);
}
''';

return await jsCallFunctionOn(receiver, expression, args);
}

Expand Down
Loading

0 comments on commit db1f552

Please sign in to comment.