Version 2.16.0-28.0.dev
Merge commit '001df490a7c6f922f6c9e3b0d8e73443e3003de1' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8e49630..fc40635 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,17 +1,13 @@
-## 2.17.0
-
-### Core libraries
-
-- **Breaking Change** [#47653](https://github.com/dart-lang/sdk/issues/47653):
- On Windows, `Directory.rename` will no longer delete a directory if
- `newPath` specifies one. Instead, a `FileSystemException` will be thrown.
-
## 2.16.0
### Core libraries
#### `dart:core`
+- **Breaking Change** [#47653](https://github.com/dart-lang/sdk/issues/47653):
+ On Windows, `Directory.rename` will no longer delete a directory if
+ `newPath` specifies one. Instead, a `FileSystemException` will be thrown.
+
- Add `Error.throwWithStackTrace` which can `throw` an
error with an existing stack trace, instead of creating
a new stack trace.
diff --git a/pkg/analysis_server/lib/src/domain_execution.dart b/pkg/analysis_server/lib/src/domain_execution.dart
index f047af1..c96814e 100644
--- a/pkg/analysis_server/lib/src/domain_execution.dart
+++ b/pkg/analysis_server/lib/src/domain_execution.dart
@@ -125,7 +125,7 @@
if (source.uriKind != UriKind.FILE_URI) {
uri = source.uri.toString();
} else {
- uri = sourceFactory.restoreUri(source).toString();
+ uri = sourceFactory.pathToUri(file).toString();
}
return ExecutionMapUriResult(uri: uri).toResponse(request.id);
} else if (uri != null) {
diff --git a/pkg/analysis_server/lib/src/services/refactoring/move_file.dart b/pkg/analysis_server/lib/src/services/refactoring/move_file.dart
index 6e97072..f3cae42 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/move_file.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/move_file.dart
@@ -158,9 +158,7 @@
var refDir = pathContext.dirname(reference.file);
// Try to keep package: URI
if (_isPackageReference(reference)) {
- Source newSource =
- NonExistingSource(newFile, pathos.toUri(newFile), UriKind.FILE_URI);
- var restoredUri = driver.sourceFactory.restoreUri(newSource);
+ var restoredUri = driver.sourceFactory.pathToUri(newFile);
// If the new URI is not a package: URI, fall back to computing a relative
// URI below.
if (restoredUri?.isScheme('package') ?? false) {
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index d672ae5..d9a4742 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -2,6 +2,8 @@
* Deprecations and renames for `getXyz` methods in `AnalysisDriver`.
* Removed uppercase named constants from `double` in mock SDK.
* Deprecated `path` and `uri` from `AnalysisResult`.
+* Deprecated `UriResolver.restoreAbsolute`, use `pathToUri` instead.
+* Deprecated `SourceFactory.restoreAbsolute`, use `pathToUri` instead.
## 2.7.0
* Updated `ConstructorElement.displayName` to either `Class` or `Class.constructor`.
diff --git a/pkg/analyzer/lib/src/context/source.dart b/pkg/analyzer/lib/src/context/source.dart
index ff628f6..b603111 100644
--- a/pkg/analyzer/lib/src/context/source.dart
+++ b/pkg/analyzer/lib/src/context/source.dart
@@ -102,6 +102,17 @@
}
@override
+ Uri? pathToUri(String path) {
+ for (var resolver in resolvers) {
+ var uri = resolver.pathToUri(path);
+ if (uri != null) {
+ return uri;
+ }
+ }
+ return null;
+ }
+
+ @override
Source? resolveUri(Source? containingSource, String? containedUri) {
if (containedUri == null) {
return null;
@@ -128,21 +139,13 @@
}
}
+ @Deprecated('Use pathToUri() instead')
@override
Uri? restoreUri(Source source) {
if (source is InSummarySource) {
return source.uri;
}
- for (UriResolver resolver in resolvers) {
- // First see if a resolver can restore the URI.
- Uri? uri = resolver.restoreAbsolute(source);
-
- if (uri != null) {
- return uri;
- }
- }
-
- return null;
+ return pathToUri(source.fullName);
}
/// Return a source object representing the URI that results from resolving
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index a275ba2..8061657 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -832,8 +832,7 @@
var file = _pathToFile[path];
if (file == null) {
File resource = _resourceProvider.getFile(path);
- Source fileSource = resource.createSource();
- Uri uri = _sourceFactory.restoreUri(fileSource)!;
+ Uri uri = _sourceFactory.pathToUri(path)!;
file = _newFile(resource, path, uri);
}
return file;
@@ -897,10 +896,8 @@
bool hasUri(String path) {
bool? flag = _hasUriForPath[path];
if (flag == null) {
- File resource = _resourceProvider.getFile(path);
- Source fileSource = resource.createSource();
- Uri? uri = _sourceFactory.restoreUri(fileSource);
- Source? uriSource = _sourceFactory.forUri2(uri!);
+ Uri uri = _sourceFactory.pathToUri(path)!;
+ Source? uriSource = _sourceFactory.forUri2(uri);
flag = uriSource?.fullName == path;
_hasUriForPath[path] = flag;
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/uri_converter.dart b/pkg/analyzer/lib/src/dart/analysis/uri_converter.dart
index 9e6bf4a..bda06b6 100644
--- a/pkg/analyzer/lib/src/dart/analysis/uri_converter.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/uri_converter.dart
@@ -5,7 +5,6 @@
import 'package:analyzer/dart/analysis/uri_converter.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
-import 'package:analyzer/src/generated/source.dart';
import 'package:path/src/context.dart';
/// An implementation of a URI converter based on an analysis driver.
@@ -32,8 +31,7 @@
}
}
}
- Source source = provider.getFile(path).createSource();
- return driver.sourceFactory.restoreUri(source);
+ return driver.sourceFactory.pathToUri(path);
}
@override
diff --git a/pkg/analyzer/lib/src/dart/micro/analysis_context.dart b/pkg/analyzer/lib/src/dart/micro/analysis_context.dart
index ef663ca..10b3313 100644
--- a/pkg/analyzer/lib/src/dart/micro/analysis_context.dart
+++ b/pkg/analyzer/lib/src/dart/micro/analysis_context.dart
@@ -208,9 +208,7 @@
@override
Uri? pathToUri(String path, {String? containingPath}) {
- var fileUri = resourceProvider.pathContext.toUri(path);
- var fileSource = sourceFactory.forUri2(fileUri)!;
- return sourceFactory.restoreUri(fileSource);
+ return sourceFactory.pathToUri(path);
}
@override
diff --git a/pkg/analyzer/lib/src/dart/micro/library_graph.dart b/pkg/analyzer/lib/src/dart/micro/library_graph.dart
index 581a44e..d18f5bae 100644
--- a/pkg/analyzer/lib/src/dart/micro/library_graph.dart
+++ b/pkg/analyzer/lib/src/dart/micro/library_graph.dart
@@ -335,10 +335,7 @@
return file;
}
- var fileUri = _resourceProvider.pathContext.toUri(path);
- var uri = _sourceFactory.restoreUri(
- _FakeSource(path, fileUri),
- );
+ var uri = _sourceFactory.pathToUri(path);
if (uri == null) {
throw StateError('Unable to convert path to URI: $path');
}
@@ -589,19 +586,6 @@
});
}
-class _FakeSource implements Source {
- @override
- final String fullName;
-
- @override
- final Uri uri;
-
- _FakeSource(this.fullName, this.uri);
-
- @override
- dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
-
class _FileStateFiles {
final List<FileState> imported = [];
final List<FileState> exported = [];
diff --git a/pkg/analyzer/lib/src/dart/sdk/sdk.dart b/pkg/analyzer/lib/src/dart/sdk/sdk.dart
index b23e091..3520c90 100644
--- a/pkg/analyzer/lib/src/dart/sdk/sdk.dart
+++ b/pkg/analyzer/lib/src/dart/sdk/sdk.dart
@@ -128,6 +128,23 @@
return source;
}
+ @override
+ Uri? pathToUri(String path) {
+ var file = resourceProvider.getFile(path);
+
+ var uriStr = _getPath(file);
+ if (uriStr == null) {
+ return null;
+ }
+
+ try {
+ return Uri.parse(uriStr);
+ } on FormatException {
+ return null;
+ }
+ }
+
+ /// TODO(scheglov) This name is misleading, returns `dart:foo/bar.dart`.
String? _getPath(File file) {
List<SdkLibrary> libraries = libraryMap.sdkLibraries;
int length = libraries.length;
diff --git a/pkg/analyzer/lib/src/file_system/file_system.dart b/pkg/analyzer/lib/src/file_system/file_system.dart
index 16c7b2a..b7b4655 100644
--- a/pkg/analyzer/lib/src/file_system/file_system.dart
+++ b/pkg/analyzer/lib/src/file_system/file_system.dart
@@ -18,6 +18,11 @@
ResourceProvider get provider => _provider;
@override
+ Uri pathToUri(String path) {
+ return _provider.pathContext.toUri(path);
+ }
+
+ @override
Source? resolveAbsolute(Uri uri) {
if (!isFileUri(uri)) {
return null;
@@ -27,9 +32,9 @@
return file.createSource(uri);
}
+ @Deprecated('Use pathToUri() instead')
@override
- Uri restoreAbsolute(Source source) =>
- _provider.pathContext.toUri(source.fullName);
+ Uri restoreAbsolute(Source source) => pathToUri(source.fullName);
/// Return `true` if the given [uri] is a `file` URI.
static bool isFileUri(Uri uri) => uri.scheme == FILE_SCHEME;
diff --git a/pkg/analyzer/lib/src/generated/sdk.dart b/pkg/analyzer/lib/src/generated/sdk.dart
index 1fd1ec8..265ce79 100644
--- a/pkg/analyzer/lib/src/generated/sdk.dart
+++ b/pkg/analyzer/lib/src/generated/sdk.dart
@@ -59,6 +59,10 @@
/// Return the source representing the library with the given 'dart:' [uri],
/// or `null` if the given URI does not denote a library in this SDK.
Source? mapDartUri(String uri);
+
+ /// Return the `dart` URI representing the given [path] if the file is in
+ /// this SDK, or `null` if the file is not in this SDK.
+ Uri? pathToUri(String path);
}
/// Manages the DartSdk's that have been created. Clients need to create
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 69ac8ca..bb1bbd3 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -61,6 +61,11 @@
DartSdk get dartSdk => _sdk;
@override
+ Uri? pathToUri(String path) {
+ return _sdk.pathToUri(path);
+ }
+
+ @override
Source? resolveAbsolute(Uri uri) {
if (!isDartUri(uri)) {
return null;
@@ -68,12 +73,6 @@
return _sdk.mapDartUri(uri.toString());
}
- @override
- Uri? restoreAbsolute(Source source) {
- var dartSource = _sdk.fromFileUri(source.uri);
- return dartSource?.uri;
- }
-
/// Return `true` if the given URI is a `dart:` URI.
///
/// @param uri the URI being tested
@@ -285,6 +284,13 @@
/// @return a source object representing the absolute URI
Source? forUri2(Uri absoluteUri);
+ /// Return the URI that should be used to reference the file at the absolute
+ /// [path], or `null` if there is no valid way to reference the file.
+ /// The file at that path is not required to exist.
+ ///
+ /// Throws an [ArgumentError] if the [path] is not a valid path.
+ Uri? pathToUri(String path);
+
/// Return a source representing the URI that results from resolving the given
/// (possibly relative) [containedUri] against the URI associated with the
/// [containingSource], whether or not the resulting source exists, or `null`
@@ -297,6 +303,7 @@
///
/// @param source the source to get URI for
/// @return the absolute URI representing the given source
+ @Deprecated('Use pathToUri() instead')
Uri? restoreUri(Source source);
}
@@ -410,6 +417,14 @@
/// used to resolve URI's for a source factory. Subclasses of this class are
/// expected to resolve a single scheme of absolute URI.
abstract class UriResolver {
+ /// Return the absolute URI that should be used to reference the file at the
+ /// absolute [path], or `null` if this resolver cannot reference this file.
+ /// The file at that path is not required to exist.
+ ///
+ /// Throws an [ArgumentError] if the [path] is not a valid path.
+ /// ignore: deprecated_member_use_from_same_package
+ Uri? pathToUri(String path) => restoreAbsolute(_FakeSource(path));
+
/// Resolve the given absolute [uri]. Return a [Source] representing the file
/// to which it was resolved, whether or not the resulting source exists, or
/// `null` if it could not be resolved because the URI is invalid.
@@ -419,5 +434,21 @@
/// valid URI cannot be computed.
///
/// The computation should be based solely on [source.fullName].
- Uri? restoreAbsolute(Source source) => null;
+ @Deprecated('Use pathToUri() instead')
+ Uri? restoreAbsolute(Source source) {
+ return pathToUri(source.fullName);
+ }
+}
+
+class _FakeSource implements Source {
+ @override
+ final String fullName;
+
+ _FakeSource(this.fullName);
+
+ @override
+ Uri get uri => pathos.toUri(fullName);
+
+ @override
+ dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
diff --git a/pkg/analyzer/lib/src/source/package_map_resolver.dart b/pkg/analyzer/lib/src/source/package_map_resolver.dart
index 0feee31..9b96f99 100644
--- a/pkg/analyzer/lib/src/source/package_map_resolver.dart
+++ b/pkg/analyzer/lib/src/source/package_map_resolver.dart
@@ -37,6 +37,22 @@
}
@override
+ Uri? pathToUri(String path) {
+ pathos.Context pathContext = resourceProvider.pathContext;
+ for (String pkgName in packageMap.keys) {
+ Folder pkgFolder = packageMap[pkgName]![0];
+ String pkgFolderPath = pkgFolder.path;
+ if (path.startsWith(pkgFolderPath + pathContext.separator)) {
+ String relPath = path.substring(pkgFolderPath.length + 1);
+ List<String> relPathComponents = pathContext.split(relPath);
+ String relUriPath = pathos.posix.joinAll(relPathComponents);
+ return Uri.parse('$PACKAGE_SCHEME:$pkgName/$relUriPath');
+ }
+ }
+ return null;
+ }
+
+ @override
Source? resolveAbsolute(Uri uri) {
if (!isPackageUri(uri)) {
return null;
@@ -61,23 +77,6 @@
return null;
}
- @override
- Uri? restoreAbsolute(Source source) {
- String sourcePath = source.fullName;
- pathos.Context pathContext = resourceProvider.pathContext;
- for (String pkgName in packageMap.keys) {
- Folder pkgFolder = packageMap[pkgName]![0];
- String pkgFolderPath = pkgFolder.path;
- if (sourcePath.startsWith(pkgFolderPath + pathContext.separator)) {
- String relPath = sourcePath.substring(pkgFolderPath.length + 1);
- List<String> relPathComponents = pathContext.split(relPath);
- String relUriPath = pathos.posix.joinAll(relPathComponents);
- return Uri.parse('$PACKAGE_SCHEME:$pkgName/$relUriPath');
- }
- }
- return null;
- }
-
/// Returns `true` if [uri] is a `package` URI.
static bool isPackageUri(Uri uri) {
return uri.scheme == PACKAGE_SCHEME;
diff --git a/pkg/analyzer/lib/src/summary/package_bundle_reader.dart b/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
index 03cce04..d39d264 100644
--- a/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
@@ -95,6 +95,9 @@
InSummaryUriResolver(this.resourceProvider, this._dataStore);
@override
+ Uri? pathToUri(String path) => null;
+
+ @override
Source? resolveAbsolute(Uri uri) {
String uriString = uri.toString();
String? summaryPath = _dataStore.uriToSummaryPath[uriString];
diff --git a/pkg/analyzer/lib/src/summary/summary_sdk.dart b/pkg/analyzer/lib/src/summary/summary_sdk.dart
index 1ad7efe..e53670d 100644
--- a/pkg/analyzer/lib/src/summary/summary_sdk.dart
+++ b/pkg/analyzer/lib/src/summary/summary_sdk.dart
@@ -90,4 +90,10 @@
Uri uri = Uri.parse(uriStr);
return _uriResolver.resolveAbsolute(uri);
}
+
+ @override
+ Uri? pathToUri(String path) {
+ // Libraries from summaries don't have corresponding Dart files.
+ return null;
+ }
}
diff --git a/pkg/analyzer/lib/src/util/uri.dart b/pkg/analyzer/lib/src/util/uri.dart
index 4192e3f..08e3008 100644
--- a/pkg/analyzer/lib/src/util/uri.dart
+++ b/pkg/analyzer/lib/src/util/uri.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/summary/package_bundle_reader.dart';
import 'package:path/path.dart';
String fileUriToNormalizedPath(Context context, Uri fileUri) {
@@ -34,5 +35,9 @@
return null;
}
- return sourceFactory.restoreUri(source);
+ if (source is InSummarySource) {
+ return source.uri;
+ }
+
+ return sourceFactory.pathToUri(source.fullName);
}
diff --git a/pkg/analyzer/lib/src/workspace/bazel.dart b/pkg/analyzer/lib/src/workspace/bazel.dart
index d7743a0..c8d032c 100644
--- a/pkg/analyzer/lib/src/workspace/bazel.dart
+++ b/pkg/analyzer/lib/src/workspace/bazel.dart
@@ -53,6 +53,24 @@
_context = workspace.provider.pathContext;
@override
+ Uri? pathToUri(String path) {
+ // Search in each root.
+ for (var root in [
+ ..._workspace.binPaths,
+ _workspace.genfiles,
+ _workspace.readonly,
+ _workspace.root
+ ]) {
+ var uriParts = _restoreUriParts(root, path);
+ if (uriParts != null) {
+ return Uri.parse('package:${uriParts[0]}/${uriParts[1]}');
+ }
+ }
+
+ return null;
+ }
+
+ @override
Source? resolveAbsolute(Uri uri) {
var source = _sourceCache[uri];
if (source == null) {
@@ -64,26 +82,6 @@
return source;
}
- @override
- Uri? restoreAbsolute(Source source) {
- String filePath = source.fullName;
-
- // Search in each root.
- for (var root in [
- ..._workspace.binPaths,
- _workspace.genfiles,
- _workspace.readonly,
- _workspace.root
- ]) {
- var uriParts = _restoreUriParts(root, filePath);
- if (uriParts != null) {
- return Uri.parse('package:${uriParts[0]}/${uriParts[1]}');
- }
- }
-
- return null;
- }
-
Source? _resolveAbsolute(Uri uri) {
if (uri.scheme == 'file') {
var path = fileUriToNormalizedPath(_context, uri);
diff --git a/pkg/analyzer/lib/src/workspace/package_build.dart b/pkg/analyzer/lib/src/workspace/package_build.dart
index ba6e15c..53a293f 100644
--- a/pkg/analyzer/lib/src/workspace/package_build.dart
+++ b/pkg/analyzer/lib/src/workspace/package_build.dart
@@ -60,6 +60,18 @@
Map<String, List<Folder>> get packageMap => _workspace.packageMap;
@override
+ Uri? pathToUri(String path) {
+ if (_context.isWithin(_workspace.root, path)) {
+ var uriParts = _restoreUriParts(path);
+ if (uriParts != null) {
+ return Uri.parse('package:${uriParts[0]}/${uriParts[1]}');
+ }
+ }
+
+ return _normalUriResolver.pathToUri(path);
+ }
+
+ @override
Source? resolveAbsolute(Uri uri) {
if (uri.scheme != 'package') {
return null;
@@ -90,20 +102,6 @@
return basicResolverSource;
}
- @override
- Uri? restoreAbsolute(Source source) {
- String filePath = source.fullName;
-
- if (_context.isWithin(_workspace.root, filePath)) {
- var uriParts = _restoreUriParts(filePath);
- if (uriParts != null) {
- return Uri.parse('package:${uriParts[0]}/${uriParts[1]}');
- }
- }
-
- return _normalUriResolver.restoreAbsolute(source);
- }
-
List<String>? _restoreUriParts(String filePath) {
String relative = _context.relative(filePath, from: _workspace.root);
List<String> components = _context.split(relative);
diff --git a/pkg/analyzer/test/file_system/resource_uri_resolver_test.dart b/pkg/analyzer/test/file_system/resource_uri_resolver_test.dart
index c6192fb..9ae396e 100644
--- a/pkg/analyzer/test/file_system/resource_uri_resolver_test.dart
+++ b/pkg/analyzer/test/file_system/resource_uri_resolver_test.dart
@@ -29,6 +29,12 @@
expect(resolver, isNotNull);
}
+ void test_pathToUri() {
+ var path = convertPath('/test.dart');
+ var uri = toUri(path);
+ expect(resolver.pathToUri(path), uri);
+ }
+
void test_resolveAbsolute_file() {
var uri = toUri('/test.dart');
@@ -59,6 +65,7 @@
expect(source, isNull);
}
+ @Deprecated('Use pathToUri() instead')
void test_restoreAbsolute() {
var uri = toUri('/test.dart');
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index 2fd5fff..1785d44 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -44,6 +44,18 @@
expect(DartUriResolver.isDartUri(uri), isFalse);
}
+ void test_pathToUri_library() {
+ var path = convertPath('/sdk/lib/core/core.dart');
+ var dartUri = resolver.pathToUri(path);
+ expect(dartUri.toString(), 'dart:core');
+ }
+
+ void test_pathToUri_part() {
+ var path = convertPath('/sdk/lib/core/int.dart');
+ var dartUri = resolver.pathToUri(path);
+ expect(dartUri.toString(), 'dart:core/int.dart');
+ }
+
void test_resolve_dart_library() {
var source = resolver.resolveAbsolute(Uri.parse('dart:core'));
expect(source, isNotNull);
@@ -64,16 +76,18 @@
expect(result, isNull);
}
+ @Deprecated('Use pathToUri() instead')
void test_restoreAbsolute_library() {
_SourceMock source = _SourceMock();
- source.uri = toUri('/sdk/lib/core/core.dart');
+ source.fullName = convertPath('/sdk/lib/core/core.dart');
var dartUri = resolver.restoreAbsolute(source);
expect(dartUri.toString(), 'dart:core');
}
+ @Deprecated('Use pathToUri() instead')
void test_restoreAbsolute_part() {
_SourceMock source = _SourceMock();
- source.uri = toUri('/sdk/lib/core/int.dart');
+ source.fullName = convertPath('/sdk/lib/core/int.dart');
var dartUri = resolver.restoreAbsolute(source);
expect(dartUri.toString(), 'dart:core/int.dart');
}
@@ -351,6 +365,9 @@
class _SourceMock implements Source {
@override
+ late final String fullName;
+
+ @override
late final Uri uri;
@override
diff --git a/pkg/analyzer/test/generated/source_factory_test.dart b/pkg/analyzer/test/generated/source_factory_test.dart
index 98e3f04..f13f48d 100644
--- a/pkg/analyzer/test/generated/source_factory_test.dart
+++ b/pkg/analyzer/test/generated/source_factory_test.dart
@@ -39,6 +39,16 @@
expect(SourceFactory([]), isNotNull);
}
+ void test_pathToUri() {
+ File file1 = getFile("/some/file1.dart");
+ File file2 = getFile("/some/file2.dart");
+ Uri expected1 = Uri.parse("file:///my_file.dart");
+ SourceFactory factory =
+ SourceFactory([UriResolver_restoreUri(file1.path, expected1)]);
+ expect(factory.pathToUri(file1.path), expected1);
+ expect(factory.pathToUri(file2.path), isNull);
+ }
+
void test_resolveUri_absolute() {
UriResolver_absolute resolver = UriResolver_absolute();
SourceFactory factory = SourceFactory([resolver]);
@@ -95,6 +105,7 @@
expect(result.uri.toString(), 'package:package/dir/second.dart');
}
+ @Deprecated('Use pathToUri() instead')
void test_restoreUri() {
File file1 = getFile("/some/file1.dart");
File file2 = getFile("/some/file2.dart");
@@ -102,7 +113,7 @@
Source source2 = FileSource(file2);
Uri expected1 = Uri.parse("file:///my_file.dart");
SourceFactory factory =
- SourceFactory([UriResolver_restoreUri(source1, expected1)]);
+ SourceFactory([UriResolver_restoreUri(file1.path, expected1)]);
expect(factory.restoreUri(source1), same(expected1));
expect(factory.restoreUri(source2), isNull);
}
@@ -121,20 +132,20 @@
}
class UriResolver_restoreUri extends UriResolver {
- Source source1;
+ String path1;
Uri expected1;
- UriResolver_restoreUri(this.source1, this.expected1);
+ UriResolver_restoreUri(this.path1, this.expected1);
@override
- Source? resolveAbsolute(Uri uri) => null;
-
- @override
- Uri? restoreAbsolute(Source source) {
- if (identical(source, source1)) {
+ Uri? pathToUri(String path) {
+ if (path == path1) {
return expected1;
}
return null;
}
+
+ @override
+ Source? resolveAbsolute(Uri uri) => null;
}
class UriResolver_SourceFactoryTest_test_fromEncoding_valid
diff --git a/pkg/analyzer/test/source/package_map_resolver_test.dart b/pkg/analyzer/test/source/package_map_resolver_test.dart
index 19aee6d..2cd49c3 100644
--- a/pkg/analyzer/test/source/package_map_resolver_test.dart
+++ b/pkg/analyzer/test/source/package_map_resolver_test.dart
@@ -39,6 +39,33 @@
expect(PackageMapUriResolver.isPackageUri(uri), isFalse);
}
+ void test_pathToUri() {
+ String pkgFileA = provider.convertPath('/pkgA/lib/libA.dart');
+ String pkgFileB = provider.convertPath('/pkgB/lib/src/libB.dart');
+ provider.newFile(pkgFileA, 'library lib_a;');
+ provider.newFile(pkgFileB, 'library lib_b;');
+ PackageMapUriResolver resolver =
+ PackageMapUriResolver(provider, <String, List<Folder>>{
+ 'pkgA': <Folder>[provider.getFolder(provider.convertPath('/pkgA/lib'))],
+ 'pkgB': <Folder>[provider.getFolder(provider.convertPath('/pkgB/lib'))]
+ });
+ {
+ var path = provider.convertPath('/pkgA/lib/libA.dart');
+ var uri = resolver.pathToUri(path);
+ expect(uri, Uri.parse('package:pkgA/libA.dart'));
+ }
+ {
+ var path = provider.convertPath('/pkgB/lib/src/libB.dart');
+ var uri = resolver.pathToUri(path);
+ expect(uri, Uri.parse('package:pkgB/src/libB.dart'));
+ }
+ {
+ var path = provider.convertPath('/no/such/file');
+ var uri = resolver.pathToUri(path);
+ expect(uri, isNull);
+ }
+ }
+
void test_resolve_multiple_folders() {
var a = provider.newFile(provider.convertPath('/aaa/a.dart'), '');
var b = provider.newFile(provider.convertPath('/bbb/b.dart'), '');
@@ -144,6 +171,7 @@
expect(result, isNull);
}
+ @Deprecated('Use pathToUri() instead')
void test_restoreAbsolute() {
String pkgFileA = provider.convertPath('/pkgA/lib/libA.dart');
String pkgFileB = provider.convertPath('/pkgB/lib/src/libB.dart');
diff --git a/pkg/analyzer/test/src/dart/analysis/base.dart b/pkg/analyzer/test/src/dart/analysis/base.dart
index a015fec..b6c9542 100644
--- a/pkg/analyzer/test/src/dart/analysis/base.dart
+++ b/pkg/analyzer/test/src/dart/analysis/base.dart
@@ -153,10 +153,10 @@
void tearDown() {}
}
-class _GeneratedUriResolverMock implements UriResolver {
+class _GeneratedUriResolverMock extends UriResolver {
Source? Function(Uri)? resolveAbsoluteFunction;
- Uri? Function(Source)? restoreAbsoluteFunction;
+ Uri? Function(String)? pathToUriFunction;
@override
noSuchMethod(Invocation invocation) {
@@ -164,17 +164,14 @@
}
@override
- Source? resolveAbsolute(Uri uri) {
- if (resolveAbsoluteFunction != null) {
- return resolveAbsoluteFunction!(uri);
- }
- return null;
+ Uri? pathToUri(String path) {
+ return pathToUriFunction?.call(path);
}
@override
- Uri? restoreAbsolute(Source source) {
- if (restoreAbsoluteFunction != null) {
- return restoreAbsoluteFunction!(source);
+ Source? resolveAbsolute(Uri uri) {
+ if (resolveAbsoluteFunction != null) {
+ return resolveAbsoluteFunction!(uri);
}
return null;
}
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index 35c3ab2..b04f7f3 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -1246,8 +1246,7 @@
Source generatedSource = _SourceMock(generatedPath, uri);
generatedUriResolver.resolveAbsoluteFunction = (uri) => generatedSource;
- generatedUriResolver.restoreAbsoluteFunction = (Source source) {
- String path = source.fullName;
+ generatedUriResolver.pathToUriFunction = (path) {
if (path == templatePath || path == generatedPath) {
return uri;
} else {
diff --git a/pkg/analyzer/test/src/dart/analysis/feature_set_provider_test.dart b/pkg/analyzer/test/src/dart/analysis/feature_set_provider_test.dart
index dfcbe51..0f485b1 100644
--- a/pkg/analyzer/test/src/dart/analysis/feature_set_provider_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/feature_set_provider_test.dart
@@ -446,9 +446,7 @@
FeatureSet _getPathFeatureSet(String path) {
path = convertPath(path);
- var fileUri = toUri(path);
- var fileSource = sourceFactory.forUri2(fileUri)!;
- var uri = sourceFactory.restoreUri(fileSource)!;
+ var uri = sourceFactory.pathToUri(path)!;
return provider.getFeatureSet(path, uri);
}
diff --git a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
index 6899a94..b7e3039 100644
--- a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
@@ -718,10 +718,10 @@
}
}
-class _GeneratedUriResolverMock implements UriResolver {
+class _GeneratedUriResolverMock extends UriResolver {
Source? Function(Uri)? resolveAbsoluteFunction;
- Uri? Function(Source)? restoreAbsoluteFunction;
+ Uri? Function(String)? pathToUriFunction;
@override
noSuchMethod(Invocation invocation) {
@@ -729,17 +729,14 @@
}
@override
- Source? resolveAbsolute(Uri uri) {
- if (resolveAbsoluteFunction != null) {
- return resolveAbsoluteFunction!(uri);
- }
- return null;
+ Uri? pathToUri(String path) {
+ return pathToUriFunction?.call(path);
}
@override
- Uri? restoreAbsolute(Source source) {
- if (restoreAbsoluteFunction != null) {
- return restoreAbsoluteFunction!(source);
+ Source? resolveAbsolute(Uri uri) {
+ if (resolveAbsoluteFunction != null) {
+ return resolveAbsoluteFunction!(uri);
}
return null;
}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 450bc47..bdfa95c 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -72,8 +72,7 @@
Source addSource(String path, String contents) {
var file = newFile(path, content: contents);
- var fileSource = file.createSource();
- var uri = sourceFactory.restoreUri(fileSource)!;
+ var uri = sourceFactory.pathToUri(file.path)!;
return sourceFactory.forUri2(uri)!;
}
diff --git a/pkg/analyzer/test/src/workspace/bazel_test.dart b/pkg/analyzer/test/src/workspace/bazel_test.dart
index 88e983e..460a696 100644
--- a/pkg/analyzer/test/src/workspace/bazel_test.dart
+++ b/pkg/analyzer/test/src/workspace/bazel_test.dart
@@ -38,6 +38,12 @@
expect(workspace.isBazel, isTrue);
}
+ void test_pathToUri() {
+ Uri uri = toUri('/workspace/test.dart');
+ var source = resolver.resolveAbsolute(uri)!;
+ expect(resolver.pathToUri(source.fullName), uri);
+ }
+
void test_resolveAbsolute_doesNotExist() {
var source = _resolvePath('/workspace/foo.dart')!;
expect(source.exists(), isFalse);
@@ -79,6 +85,7 @@
expect(source, isNull);
}
+ @Deprecated('Use pathToUri() instead')
void test_restoreAbsolute() {
Uri uri =
resourceProvider.pathContext.toUri(convertPath('/workspace/test.dart'));
@@ -561,21 +568,25 @@
{bool exists = true, bool restore = true}) {
Uri uri = Uri.parse(uriStr);
var source = resolver.resolveAbsolute(uri)!;
- expect(source.fullName, convertPath(posixPath));
+ var path = source.fullName;
+ expect(path, convertPath(posixPath));
expect(source.uri, uri);
expect(source.exists(), exists);
// If enabled, test also "restoreAbsolute".
if (restore) {
- var uri = resolver.restoreAbsolute(source);
- expect(uri.toString(), uriStr);
+ expect(resolver.pathToUri(path), uri);
+ // ignore: deprecated_member_use_from_same_package
+ expect(resolver.restoreAbsolute(source), uri);
}
}
- void _assertRestore(String posixPath, String? expectedUri) {
+ void _assertRestore(String posixPath, String? expectedUriStr) {
+ var expectedUri = expectedUriStr != null ? Uri.parse(expectedUriStr) : null;
String path = convertPath(posixPath);
_MockSource source = _MockSource(path);
- var uri = resolver.restoreAbsolute(source);
- expect(uri?.toString(), expectedUri);
+ expect(resolver.pathToUri(path), expectedUri);
+ // ignore: deprecated_member_use_from_same_package
+ expect(resolver.restoreAbsolute(source), expectedUri);
}
}
diff --git a/pkg/analyzer/test/src/workspace/package_build_test.dart b/pkg/analyzer/test/src/workspace/package_build_test.dart
index b7a9650..6e2cf99 100644
--- a/pkg/analyzer/test/src/workspace/package_build_test.dart
+++ b/pkg/analyzer/test/src/workspace/package_build_test.dart
@@ -20,23 +20,25 @@
class MockUriResolver implements UriResolver {
Map<Uri, File> uriToFile = {};
- Map<String, Uri> pathToUri = {};
+ Map<String, Uri> pathToUriMap = {};
void add(Uri uri, File file) {
uriToFile[uri] = file;
- pathToUri[file.path] = uri;
+ pathToUriMap[file.path] = uri;
}
@override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
@override
- Source? resolveAbsolute(Uri uri) {
- return uriToFile[uri]?.createSource(uri);
+ Uri? pathToUri(String path) {
+ return pathToUriMap[path];
}
@override
- Uri? restoreAbsolute(Source source) => pathToUri[source.fullName];
+ Source? resolveAbsolute(Uri uri) {
+ return uriToFile[uri]?.createSource(uri);
+ }
}
@reflectiveTest
@@ -61,6 +63,12 @@
expect(workspace.isBazel, isFalse);
}
+ void test_pathToUri() {
+ var uri = toUri('/workspace/test.dart');
+ var source = resolver.resolveAbsolute(uri)!;
+ expect(resolver.pathToUri(source.fullName), uri);
+ }
+
void test_resolveAbsolute_doesNotExist() {
var source = _resolvePath('/workspace/foo.dart')!;
expect(source, isNotNull);
@@ -98,6 +106,7 @@
expect(source, isNull);
}
+ @Deprecated('Use pathToUri() instead')
void test_restoreAbsolute() {
Uri uri =
resourceProvider.pathContext.toUri(convertPath('/workspace/test.dart'));
@@ -207,13 +216,15 @@
Source _assertResolveUri(Uri uri, String posixPath,
{bool exists = true, bool restore = true}) {
var source = resolver.resolveAbsolute(uri)!;
- expect(source.fullName, convertPath(posixPath));
+ var path = source.fullName;
+ expect(path, convertPath(posixPath));
expect(source.uri, uri);
expect(source.exists(), exists);
// If enabled, test also "restoreAbsolute".
if (restore) {
- var restoredUri = resolver.restoreAbsolute(source);
- expect(restoredUri.toString(), uri.toString());
+ expect(resolver.pathToUri(path), uri);
+ // ignore: deprecated_member_use_from_same_package
+ expect(resolver.restoreAbsolute(source), uri);
}
return source;
}
diff --git a/pkg/compiler/lib/src/ir/static_type.dart b/pkg/compiler/lib/src/ir/static_type.dart
index b122154..9696343 100644
--- a/pkg/compiler/lib/src/ir/static_type.dart
+++ b/pkg/compiler/lib/src/ir/static_type.dart
@@ -1556,31 +1556,32 @@
// for-in [iterableType] is a subtype of `Stream`.
ir.DartType iterableType = visitNode(node.iterable);
ir.DartType iteratorType = const ir.DynamicType();
- if (node.isAsync) {
- ir.InterfaceType streamInterfaceType = getInterfaceTypeOf(iterableType);
- ir.InterfaceType streamType = typeEnvironment.getTypeAsInstanceOf(
- streamInterfaceType,
- typeEnvironment.coreTypes.streamClass,
- currentLibrary,
- typeEnvironment.coreTypes);
- if (streamType != null) {
- iteratorType = ir.InterfaceType(
- typeEnvironment.coreTypes.streamIteratorClass,
- ir.Nullability.nonNullable,
- streamType.typeArguments);
- }
- } else {
- ir.InterfaceType iterableInterfaceType = getInterfaceTypeOf(iterableType);
- ir.Member member = hierarchy.getInterfaceMember(
- iterableInterfaceType.classNode, ir.Name(Identifiers.iterator));
- if (member != null) {
- iteratorType = ir.Substitution.fromInterfaceType(
- typeEnvironment.getTypeAsInstanceOf(
- iterableInterfaceType,
- member.enclosingClass,
- currentLibrary,
- typeEnvironment.coreTypes))
- .substituteType(member.getterType);
+ ir.InterfaceType iterableInterfaceType = getInterfaceTypeOf(iterableType);
+ if (iterableInterfaceType != null) {
+ if (node.isAsync) {
+ ir.InterfaceType streamType = typeEnvironment.getTypeAsInstanceOf(
+ iterableInterfaceType,
+ typeEnvironment.coreTypes.streamClass,
+ currentLibrary,
+ typeEnvironment.coreTypes);
+ if (streamType != null) {
+ iteratorType = ir.InterfaceType(
+ typeEnvironment.coreTypes.streamIteratorClass,
+ ir.Nullability.nonNullable,
+ streamType.typeArguments);
+ }
+ } else {
+ ir.Member member = hierarchy.getInterfaceMember(
+ iterableInterfaceType.classNode, ir.Name(Identifiers.iterator));
+ if (member != null) {
+ iteratorType = ir.Substitution.fromInterfaceType(
+ typeEnvironment.getTypeAsInstanceOf(
+ iterableInterfaceType,
+ member.enclosingClass,
+ currentLibrary,
+ typeEnvironment.coreTypes))
+ .substituteType(member.getterType);
+ }
}
}
_staticTypeCache._forInIteratorTypes[node] = iteratorType;
diff --git a/pkg/dds/CHANGELOG.md b/pkg/dds/CHANGELOG.md
index cccc7a8..55fbb5e 100644
--- a/pkg/dds/CHANGELOG.md
+++ b/pkg/dds/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 2.1.5
+- Update to new CpuSamplesEvent format for CPU sample caching for improved
+ performance.
+
# 2.1.4
- A new library `package:dds/dap.dart` exposes classes required to build a custom DAP
debug-adapter on top of the base Dart DAP functionality in DDS.
diff --git a/pkg/dds/lib/src/cpu_samples_manager.dart b/pkg/dds/lib/src/cpu_samples_manager.dart
index a0c413a..108da99 100644
--- a/pkg/dds/lib/src/cpu_samples_manager.dart
+++ b/pkg/dds/lib/src/cpu_samples_manager.dart
@@ -52,21 +52,31 @@
int bufferSize = 1000000,
]) : super(bufferSize);
- void cacheSamples(CpuSamples samples) {
- String getFunctionId(ProfileFunction function) {
- final functionObject = function.function;
- if (functionObject is NativeFunction) {
- return 'native/${functionObject.name}';
- }
- return functionObject.id!;
- }
+ ProfileFunction _buildProfileFunction(dynamic function) {
+ // `kind` and `resolvedUrl` are populated in `populateFunctionDetails()`.
+ return ProfileFunction(
+ kind: '',
+ inclusiveTicks: -1,
+ exclusiveTicks: -1,
+ resolvedUrl: '',
+ function: function,
+ );
+ }
+ String _getFunctionId(dynamic function) {
+ if (function is NativeFunction) {
+ return 'native/${function.name}';
+ }
+ return function.id!;
+ }
+
+ void cacheSamples(CpuSamplesEvent samples) {
// Initialize upon seeing our first samples.
if (functions.isEmpty) {
samplePeriod = samples.samplePeriod!;
maxStackDepth = samples.maxStackDepth!;
pid = samples.pid!;
- functions.addAll(samples.functions!);
+ functions.addAll(samples.functions!.map(_buildProfileFunction));
// Build the initial id to function index mapping. This allows for us to
// lookup a ProfileFunction in the global function list stored in this
@@ -77,7 +87,7 @@
// TODO(bkonyi): investigate creating some form of stable ID for
// Functions tied to closures.
for (int i = 0; i < functions.length; ++i) {
- idToFunctionIndex[getFunctionId(functions[i])] = i;
+ idToFunctionIndex[_getFunctionId(functions[i].function)] = i;
}
// Clear tick information as we'll need to recalculate these values later
@@ -94,14 +104,14 @@
// Check to see if we've got a function object we've never seen before.
for (int i = 0; i < newFunctions.length; ++i) {
- final key = getFunctionId(newFunctions[i]);
+ final key = _getFunctionId(newFunctions[i]);
if (!idToFunctionIndex.containsKey(key)) {
idToFunctionIndex[key] = functions.length;
// Keep track of the original index and the location of the function
// in the master function list so we can update the function indicies
// for each sample in this batch.
indexMapping[i] = functions.length;
- functions.add(newFunctions[i]);
+ functions.add(_buildProfileFunction(newFunctions[i]));
// Reset tick state as we'll recalculate later.
functions.last.inclusiveTicks = 0;
@@ -159,6 +169,28 @@
return evicted;
}
+ Future<void> populateFunctionDetails(
+ DartDevelopmentServiceImpl dds, String isolateId) async {
+ final cpuSamples = await dds.vmServiceClient.sendRequest('getCpuSamples', {
+ 'isolateId': isolateId,
+ 'timeOriginMicros': 0,
+ 'timeExtentMicros': 0,
+ });
+ final fullFunctions = cpuSamples['functions'];
+ for (final func in fullFunctions) {
+ final profileFunc = ProfileFunction.parse(func)!;
+ final id = _getFunctionId(profileFunc.function!);
+ final index = idToFunctionIndex[id];
+ if (index == null) {
+ continue;
+ }
+ final result = functions[index];
+ result.kind = profileFunc.kind;
+ result.resolvedUrl = profileFunc.resolvedUrl;
+ result.function = profileFunc.function;
+ }
+ }
+
Map<String, dynamic> toJson() {
return {
'type': 'CachedCpuSamples',
diff --git a/pkg/dds/lib/src/isolate_manager.dart b/pkg/dds/lib/src/isolate_manager.dart
index 7522183..7808b2a 100644
--- a/pkg/dds/lib/src/isolate_manager.dart
+++ b/pkg/dds/lib/src/isolate_manager.dart
@@ -110,13 +110,14 @@
/// Should always be called after an isolate is resumed.
void clearResumeApprovals() => _resumeApprovalsByName.clear();
- Map<String, dynamic> getCachedCpuSamples(String userTag) {
+ Future<Map<String, dynamic>> getCachedCpuSamples(String userTag) async {
final repo = cpuSamplesManager.cpuSamplesCaches[userTag];
if (repo == null) {
throw json_rpc.RpcException.invalidParams(
'CPU sample caching is not enabled for tag: "$userTag"',
);
}
+ await repo.populateFunctionDetails(isolateManager.dds, id);
return repo.toJson();
}
@@ -283,14 +284,15 @@
);
}
- Map<String, dynamic> getCachedCpuSamples(json_rpc.Parameters parameters) {
+ Future<Map<String, dynamic>> getCachedCpuSamples(
+ json_rpc.Parameters parameters) async {
final isolateId = parameters['isolateId'].asString;
if (!isolates.containsKey(isolateId)) {
return RPCResponses.collectedSentinel;
}
final isolate = isolates[isolateId]!;
final userTag = parameters['userTag'].asString;
- return isolate.getCachedCpuSamples(userTag);
+ return await isolate.getCachedCpuSamples(userTag);
}
/// Forwards a `resume` request to the VM service.
diff --git a/pkg/dds/pubspec.yaml b/pkg/dds/pubspec.yaml
index e575eae..e323748 100644
--- a/pkg/dds/pubspec.yaml
+++ b/pkg/dds/pubspec.yaml
@@ -3,7 +3,7 @@
A library used to spawn the Dart Developer Service, used to communicate with
a Dart VM Service instance.
-version: 2.1.4
+version: 2.1.5
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/dds
diff --git a/pkg/dds/test/get_cached_cpu_samples_test.dart b/pkg/dds/test/get_cached_cpu_samples_test.dart
index 77d2bdb..d8e900e 100644
--- a/pkg/dds/test/get_cached_cpu_samples_test.dart
+++ b/pkg/dds/test/get_cached_cpu_samples_test.dart
@@ -42,8 +42,15 @@
final availableCaches = await service.getAvailableCachedCpuSamples();
expect(availableCaches.cacheNames.length, 0);
- final isolate = (await service.getVM()).isolates!.first;
-
+ IsolateRef isolate;
+ while (true) {
+ final vm = await service.getVM();
+ if (vm.isolates!.isNotEmpty) {
+ isolate = vm.isolates!.first;
+ break;
+ }
+ await Future.delayed(const Duration(seconds: 1));
+ }
try {
await service.getCachedCpuSamples(isolate.id!, 'Fake');
fail('Invalid userTag did not cause an exception');
@@ -73,7 +80,18 @@
expect(availableCaches.cacheNames.length, 1);
expect(availableCaches.cacheNames.first, kUserTag);
- final isolate = (await service.getVM()).isolates!.first;
+ IsolateRef isolate;
+ while (true) {
+ final vm = await service.getVM();
+ if (vm.isolates!.isNotEmpty) {
+ isolate = vm.isolates!.first;
+ isolate = await service.getIsolate(isolate.id!);
+ if ((isolate as Isolate).runnable!) {
+ break;
+ }
+ }
+ await Future.delayed(const Duration(seconds: 1));
+ }
final completer = Completer<void>();
int i = 0;
diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md
index 760c9d9..16605c0 100644
--- a/pkg/vm_service/CHANGELOG.md
+++ b/pkg/vm_service/CHANGELOG.md
@@ -1,5 +1,10 @@
# Changelog
+## 8.0.0
+- *breaking* Updated type of `Event.cpuSamples` from `CpuSamples` to
+ `CpuSamplesEvent`, which is less expensive to generate and serialize.
+- Added `CpuSamplesEvent` object.
+
## 7.5.0
- Update to version `3.53` of the spec.
- Added `setIsolatePauseMode` RPC.
diff --git a/pkg/vm_service/example/vm_service_assert.dart b/pkg/vm_service/example/vm_service_assert.dart
index f30e794..aa1b7c7 100644
--- a/pkg/vm_service/example/vm_service_assert.dart
+++ b/pkg/vm_service/example/vm_service_assert.dart
@@ -453,6 +453,20 @@
return obj;
}
+vms.CpuSamplesEvent assertCpuSamplesEvent(vms.CpuSamplesEvent obj) {
+ assertNotNull(obj);
+ assertInt(obj.samplePeriod!);
+ assertInt(obj.maxStackDepth!);
+ assertInt(obj.sampleCount!);
+ assertInt(obj.timeSpan!);
+ assertInt(obj.timeOriginMicros!);
+ assertInt(obj.timeExtentMicros!);
+ assertInt(obj.pid!);
+ assertListOfDynamic(obj.functions!);
+ assertListOfCpuSample(obj.samples!);
+ return obj;
+}
+
vms.CpuSample assertCpuSample(vms.CpuSample obj) {
assertNotNull(obj);
assertInt(obj.tid!);
diff --git a/pkg/vm_service/java/.gitignore b/pkg/vm_service/java/.gitignore
index a54ba8c..5fe823e 100644
--- a/pkg/vm_service/java/.gitignore
+++ b/pkg/vm_service/java/.gitignore
@@ -63,6 +63,7 @@
src/org/dartlang/vm/service/element/ContextRef.java
src/org/dartlang/vm/service/element/CpuSample.java
src/org/dartlang/vm/service/element/CpuSamples.java
+src/org/dartlang/vm/service/element/CpuSamplesEvent.java
src/org/dartlang/vm/service/element/ErrorKind.java
src/org/dartlang/vm/service/element/ErrorObj.java
src/org/dartlang/vm/service/element/ErrorRef.java
diff --git a/pkg/vm_service/java/version.properties b/pkg/vm_service/java/version.properties
index b8e9261a..84daa3b 100644
--- a/pkg/vm_service/java/version.properties
+++ b/pkg/vm_service/java/version.properties
@@ -1 +1 @@
-version=3.53
+version=3.54
diff --git a/pkg/vm_service/lib/src/vm_service.dart b/pkg/vm_service/lib/src/vm_service.dart
index 278e6cf..fcdfe9b 100644
--- a/pkg/vm_service/lib/src/vm_service.dart
+++ b/pkg/vm_service/lib/src/vm_service.dart
@@ -26,7 +26,7 @@
HeapSnapshotObjectNoData,
HeapSnapshotObjectNullData;
-const String vmServiceVersion = '3.53.0';
+const String vmServiceVersion = '3.54.0';
/// @optional
const String optional = 'optional';
@@ -123,6 +123,7 @@
'Context': Context.parse,
'ContextElement': ContextElement.parse,
'CpuSamples': CpuSamples.parse,
+ 'CpuSamplesEvent': CpuSamplesEvent.parse,
'CpuSample': CpuSample.parse,
'@Error': ErrorRef.parse,
'Error': Error.parse,
@@ -3658,6 +3659,92 @@
String toString() => '[CpuSamples]';
}
+class CpuSamplesEvent {
+ static CpuSamplesEvent? parse(Map<String, dynamic>? json) =>
+ json == null ? null : CpuSamplesEvent._fromJson(json);
+
+ /// The sampling rate for the profiler in microseconds.
+ int? samplePeriod;
+
+ /// The maximum possible stack depth for samples.
+ int? maxStackDepth;
+
+ /// The number of samples returned.
+ int? sampleCount;
+
+ /// The timespan the set of returned samples covers, in microseconds
+ /// (deprecated).
+ ///
+ /// Note: this property is deprecated and will always return -1. Use
+ /// `timeExtentMicros` instead.
+ int? timeSpan;
+
+ /// The start of the period of time in which the returned samples were
+ /// collected.
+ int? timeOriginMicros;
+
+ /// The duration of time covered by the returned samples.
+ int? timeExtentMicros;
+
+ /// The process ID for the VM.
+ int? pid;
+
+ /// A list of references to functions seen in the relevant samples. These
+ /// references can be looked up using the indicies provided in a `CpuSample`
+ /// `stack` to determine which function was on the stack.
+ List<dynamic>? functions;
+
+ /// A list of samples collected in the range `[timeOriginMicros,
+ /// timeOriginMicros + timeExtentMicros]`
+ List<CpuSample>? samples;
+
+ CpuSamplesEvent({
+ required this.samplePeriod,
+ required this.maxStackDepth,
+ required this.sampleCount,
+ required this.timeSpan,
+ required this.timeOriginMicros,
+ required this.timeExtentMicros,
+ required this.pid,
+ required this.functions,
+ required this.samples,
+ });
+
+ CpuSamplesEvent._fromJson(Map<String, dynamic> json) {
+ samplePeriod = json['samplePeriod'] ?? -1;
+ maxStackDepth = json['maxStackDepth'] ?? -1;
+ sampleCount = json['sampleCount'] ?? -1;
+ timeSpan = json['timeSpan'] ?? -1;
+ timeOriginMicros = json['timeOriginMicros'] ?? -1;
+ timeExtentMicros = json['timeExtentMicros'] ?? -1;
+ pid = json['pid'] ?? -1;
+ functions = List<dynamic>.from(
+ createServiceObject(json['functions'], const ['dynamic']) as List? ??
+ []);
+ samples = List<CpuSample>.from(
+ createServiceObject(json['samples'], const ['CpuSample']) as List? ??
+ []);
+ }
+
+ Map<String, dynamic> toJson() {
+ final json = <String, dynamic>{};
+ json.addAll({
+ 'samplePeriod': samplePeriod,
+ 'maxStackDepth': maxStackDepth,
+ 'sampleCount': sampleCount,
+ 'timeSpan': timeSpan,
+ 'timeOriginMicros': timeOriginMicros,
+ 'timeExtentMicros': timeExtentMicros,
+ 'pid': pid,
+ 'functions': functions?.map((f) => f.toJson()).toList(),
+ 'samples': samples?.map((f) => f.toJson()).toList(),
+ });
+ return json;
+ }
+
+ String toString() => '[CpuSamplesEvent]';
+}
+
/// See [getCpuSamples] and [CpuSamples].
class CpuSample {
static CpuSample? parse(Map<String, dynamic>? json) =>
@@ -4051,7 +4138,7 @@
/// A CPU profile containing recent samples.
@optional
- CpuSamples? cpuSamples;
+ CpuSamplesEvent? cpuSamples;
/// Binary data associated with the event.
///
@@ -4132,8 +4219,9 @@
last = json['last'];
updatedTag = json['updatedTag'];
previousTag = json['previousTag'];
- cpuSamples = createServiceObject(json['cpuSamples'], const ['CpuSamples'])
- as CpuSamples?;
+ cpuSamples =
+ createServiceObject(json['cpuSamples'], const ['CpuSamplesEvent'])
+ as CpuSamplesEvent?;
data = json['data'];
}
diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml
index 8bd5ed5..d613713 100644
--- a/pkg/vm_service/pubspec.yaml
+++ b/pkg/vm_service/pubspec.yaml
@@ -3,7 +3,7 @@
A library to communicate with a service implementing the Dart VM
service protocol.
-version: 7.5.0
+version: 8.0.0
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service
diff --git a/pkg/vm_service/test/common/test_helper.dart b/pkg/vm_service/test/common/test_helper.dart
index 8bf30b8..e16e307d 100644
--- a/pkg/vm_service/test/common/test_helper.dart
+++ b/pkg/vm_service/test/common/test_helper.dart
@@ -277,6 +277,7 @@
vm = await vmServiceConnectUri(serviceWebsocketAddress);
print('Done loading VM');
isolate = await getFirstIsolate(vm);
+ print('Got first isolate');
});
});
@@ -342,6 +343,8 @@
});
await service.streamListen(EventStreams.kIsolate);
+ await service.streamListen(EventStreams.kIsolate);
+
// The isolate may have started before we subscribed.
vm = await service.getVM();
if (vmIsolates.isNotEmpty) {
diff --git a/pkg/vm_service/tool/dart/generate_dart.dart b/pkg/vm_service/tool/dart/generate_dart.dart
index 4f2eb16..d59b1e7 100644
--- a/pkg/vm_service/tool/dart/generate_dart.dart
+++ b/pkg/vm_service/tool/dart/generate_dart.dart
@@ -935,6 +935,10 @@
return obj;
}
+List<dynamic> assertListOfDynamic(List<dynamic> list) {
+ return list;
+}
+
List<int> assertListOfInt(List<int> list) {
for (int elem in list) {
assertInt(elem);
diff --git a/runtime/observatory/tests/service/get_object_rpc_test.dart b/runtime/observatory/tests/service/get_object_rpc_test.dart
index d553138..a1f0582 100644
--- a/runtime/observatory/tests/service/get_object_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_object_rpc_test.dart
@@ -14,8 +14,12 @@
class _DummyClass {
static var dummyVar = 11;
final List<String> dummyList = new List<String>.filled(20, '');
+ static var dummyVarWithInit = foo();
+ late String dummyLateVarWithInit = 'bar';
+ late String dummyLateVar;
void dummyFunction(int a, [bool b = false]) {}
void dummyGenericFunction<K, V>(K a, {required V param}) {}
+ static List foo() => List<String>.filled(20, '');
}
class _DummySubClass extends _DummyClass {}
@@ -982,6 +986,83 @@
expect(result['_guardLength'], isNotNull);
},
+ // static field initializer
+ (Isolate isolate) async {
+ // Call eval to get a class id.
+ var evalResult = await invoke(isolate, 'getDummyClass');
+ var id = "${evalResult['class']['id']}/field_inits/dummyVarWithInit";
+ var params = {
+ 'objectId': id,
+ };
+ var result = await isolate.invokeRpcNoUpgrade('getObject', params);
+ expect(result['type'], equals('Function'));
+ expect(result['id'], equals(id));
+ expect(result['name'], equals('dummyVarWithInit'));
+ expect(result['_kind'], equals('FieldInitializer'));
+ expect(result['static'], equals(true));
+ expect(result['const'], equals(false));
+ expect(result['implicit'], equals(false));
+ expect(result['signature']['typeParameters'], isNull);
+ expect(result['signature']['returnType'], isNotNull);
+ expect(result['signature']['parameters'].length, 0);
+ expect(result['location']['type'], equals('SourceLocation'));
+ expect(result['code']['type'], equals('@Code'));
+ expect(result['_optimizable'], equals(true));
+ expect(result['_inlinable'], equals(false));
+ expect(result['_usageCounter'], isZero);
+ expect(result['_optimizedCallSiteCount'], isZero);
+ expect(result['_deoptimizations'], isZero);
+ },
+
+ // late field initializer
+ (Isolate isolate) async {
+ // Call eval to get a class id.
+ var evalResult = await invoke(isolate, 'getDummyClass');
+ var id = "${evalResult['class']['id']}/field_inits/dummyLateVarWithInit";
+ var params = {
+ 'objectId': id,
+ };
+ var result = await isolate.invokeRpcNoUpgrade('getObject', params);
+ expect(result['type'], equals('Function'));
+ expect(result['id'], equals(id));
+ expect(result['name'], equals('dummyLateVarWithInit'));
+ expect(result['_kind'], equals('FieldInitializer'));
+ expect(result['static'], equals(false));
+ expect(result['const'], equals(false));
+ expect(result['implicit'], equals(false));
+ expect(result['signature']['typeParameters'], isNull);
+ expect(result['signature']['returnType'], isNotNull);
+ expect(result['signature']['parameters'].length, 1);
+ expect(result['location']['type'], equals('SourceLocation'));
+ expect(result['code']['type'], equals('@Code'));
+ expect(result['_optimizable'], equals(true));
+ expect(result['_inlinable'], equals(false));
+ expect(result['_usageCounter'], isZero);
+ expect(result['_optimizedCallSiteCount'], isZero);
+ expect(result['_deoptimizations'], isZero);
+ },
+
+ // invalid late field initialize.
+ (Isolate isolate) async {
+ // Call eval to get a class id.
+ var evalResult = await invoke(isolate, 'getDummyClass');
+ var id = "${evalResult['class']['id']}/field_inits/dummyLateVar";
+ var params = {
+ 'objectId': id,
+ };
+ bool caughtException = false;
+ try {
+ await isolate.invokeRpcNoUpgrade('getObject', params);
+ expect(false, isTrue, reason: 'Unreachable');
+ } on ServerRpcException catch (e) {
+ caughtException = true;
+ expect(e.code, equals(ServerRpcException.kInvalidParams));
+ expect(
+ e.message, startsWith("getObject: invalid 'objectId' parameter: "));
+ }
+ expect(caughtException, isTrue);
+ },
+
// field with guards
(Isolate isolate) async {
var result = await isolate.vm.invokeRpcNoUpgrade('getFlagList', {});
diff --git a/runtime/observatory/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart
index 7b1f275..59afe6d 100644
--- a/runtime/observatory/tests/service/get_version_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_version_rpc_test.dart
@@ -12,7 +12,7 @@
final result = await vm.invokeRpcNoUpgrade('getVersion', {});
expect(result['type'], 'Version');
expect(result['major'], 3);
- expect(result['minor'], 53);
+ expect(result['minor'], 54);
expect(result['_privateMajor'], 0);
expect(result['_privateMinor'], 0);
},
diff --git a/runtime/observatory_2/tests/service_2/get_object_rpc_test.dart b/runtime/observatory_2/tests/service_2/get_object_rpc_test.dart
index 44912b3..9c45a9e 100644
--- a/runtime/observatory_2/tests/service_2/get_object_rpc_test.dart
+++ b/runtime/observatory_2/tests/service_2/get_object_rpc_test.dart
@@ -14,8 +14,10 @@
class _DummyClass {
static var dummyVar = 11;
final List<String> dummyList = new List<String>.filled(20, null);
+ static var dummyVarWithInit = foo();
void dummyFunction(int a, [bool b = false]) {}
void dummyGenericFunction<K, V>(K a, {V param}) {}
+ static List foo() => List<String>.filled(20, '');
}
class _DummySubClass extends _DummyClass {}
@@ -1014,6 +1016,34 @@
expect(result['_guardLength'], equals('20'));
},
+ // static field initializer
+ (Isolate isolate) async {
+ // Call eval to get a class id.
+ var evalResult = await invoke(isolate, 'getDummyClass');
+ var id = "${evalResult['class']['id']}/field_inits/dummyVarWithInit";
+ var params = {
+ 'objectId': id,
+ };
+ var result = await isolate.invokeRpcNoUpgrade('getObject', params);
+ expect(result['type'], equals('Function'));
+ expect(result['id'], equals(id));
+ expect(result['name'], equals('dummyVarWithInit'));
+ expect(result['_kind'], equals('FieldInitializer'));
+ expect(result['static'], equals(true));
+ expect(result['const'], equals(false));
+ expect(result['implicit'], equals(false));
+ expect(result['signature']['typeParameters'], isNull);
+ expect(result['signature']['returnType'], isNotNull);
+ expect(result['signature']['parameters'].length, 0);
+ expect(result['location']['type'], equals('SourceLocation'));
+ expect(result['code']['type'], equals('@Code'));
+ expect(result['_optimizable'], equals(true));
+ expect(result['_inlinable'], equals(false));
+ expect(result['_usageCounter'], isZero);
+ expect(result['_optimizedCallSiteCount'], isZero);
+ expect(result['_deoptimizations'], isZero);
+ },
+
// invalid field.
(Isolate isolate) async {
// Call eval to get a class id.
diff --git a/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart b/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart
index e9c87c9..4daa57a 100644
--- a/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart
+++ b/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart
@@ -12,7 +12,7 @@
final result = await vm.invokeRpcNoUpgrade('getVersion', {});
expect(result['type'], equals('Version'));
expect(result['major'], equals(3));
- expect(result['minor'], equals(53));
+ expect(result['minor'], equals(54));
expect(result['_privateMajor'], equals(0));
expect(result['_privateMinor'], equals(0));
},
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 71924f7..503be80 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -3702,6 +3702,9 @@
// element 2 * i + 1 is coverage hit (zero meaning code was not hit)
ArrayPtr GetCoverageArray() const;
+ // Outputs this function's service ID to the provided JSON object.
+ void AddFunctionServiceId(const JSONObject& obj) const;
+
// Sets deopt reason in all ICData-s with given deopt_id.
void SetDeoptReasonForAll(intptr_t deopt_id, ICData::DeoptReasonId reason);
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index f7fe7fe..42ab457 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -248,22 +248,36 @@
Object::PrintJSONImpl(stream, ref);
}
-static void AddFunctionServiceId(const JSONObject& jsobj,
- const Function& f,
- const Class& cls) {
- ASSERT(!cls.IsNull());
+void Function::AddFunctionServiceId(const JSONObject& jsobj) const {
+ Class& cls = Class::Handle(Owner());
// Special kinds of functions use indices in their respective lists.
intptr_t id = -1;
const char* selector = NULL;
- if (f.IsNonImplicitClosureFunction()) {
- id = ClosureFunctionsCache::FindClosureIndex(f);
+ // Regular functions known to their owner use their name (percent-encoded).
+ String& name = String::Handle(this->name());
+
+ if (IsNonImplicitClosureFunction()) {
+ id = ClosureFunctionsCache::FindClosureIndex(*this);
selector = "closures";
- } else if (f.IsImplicitClosureFunction()) {
- id = cls.FindImplicitClosureFunctionIndex(f);
+ } else if (IsImplicitClosureFunction()) {
+ id = cls.FindImplicitClosureFunctionIndex(*this);
selector = "implicit_closures";
- } else if (f.IsNoSuchMethodDispatcher() || f.IsInvokeFieldDispatcher()) {
- id = cls.FindInvocationDispatcherFunctionIndex(f);
+ } else if (IsNoSuchMethodDispatcher() || IsInvokeFieldDispatcher()) {
+ id = cls.FindInvocationDispatcherFunctionIndex(*this);
selector = "dispatchers";
+ } else if (IsFieldInitializer()) {
+ name ^= Field::NameFromInit(name);
+ const char* encoded_field_name = String::EncodeIRI(name);
+ if (cls.IsTopLevel()) {
+ const auto& library = Library::Handle(cls.library());
+ const auto& private_key = String::Handle(library.private_key());
+ jsobj.AddFixedServiceId("libraries/%s/field_inits/%s",
+ private_key.ToCString(), encoded_field_name);
+ } else {
+ jsobj.AddFixedServiceId("classes/%" Pd "/field_inits/%s", cls.id(),
+ encoded_field_name);
+ }
+ return;
}
if (id != -1) {
ASSERT(selector != NULL);
@@ -278,10 +292,8 @@
}
return;
}
- // Regular functions known to their owner use their name (percent-encoded).
- String& name = String::Handle(f.name());
Thread* thread = Thread::Current();
- if (Resolver::ResolveFunction(thread->zone(), cls, name) == f.ptr()) {
+ if (Resolver::ResolveFunction(thread->zone(), cls, name) == ptr()) {
const char* encoded_name = String::EncodeIRI(name);
if (cls.IsTopLevel()) {
const auto& library = Library::Handle(cls.library());
@@ -297,7 +309,7 @@
// Oddball functions (not known to their owner) fall back to use the object
// id ring. Current known examples are signature functions of closures
// and stubs like 'megamorphic_call_miss'.
- jsobj.AddServiceId(f);
+ jsobj.AddServiceId(*this);
}
void Function::PrintJSONImpl(JSONStream* stream, bool ref) const {
@@ -308,7 +320,7 @@
ASSERT(err.IsNull());
JSONObject jsobj(stream);
AddCommonObjectProperties(&jsobj, "Function", ref);
- AddFunctionServiceId(jsobj, *this, cls);
+ AddFunctionServiceId(jsobj);
const char* user_name = UserVisibleNameCString();
const String& vm_name = String::Handle(name());
AddNameProperties(&jsobj, user_name, vm_name.ToCString());
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 58cab0e..f1f721b 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -250,7 +250,6 @@
ProcessedSampleBuffer* SampleBlockListProcessor::BuildProcessedSampleBuffer(
SampleFilter* filter,
ProcessedSampleBuffer* buffer) {
- ASSERT(filter != NULL);
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
@@ -267,7 +266,6 @@
ProcessedSampleBuffer* SampleBlockBuffer::BuildProcessedSampleBuffer(
SampleFilter* filter,
ProcessedSampleBuffer* buffer) {
- ASSERT(filter != NULL);
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index c82c0f9..1ae3a46 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -170,7 +170,19 @@
func->AddProperty("_kind", KindToCString(kind()));
}
-void ProfileFunction::PrintToJSONArray(JSONArray* functions) {
+void ProfileFunction::PrintToJSONArray(JSONArray* functions,
+ bool print_only_ids) {
+ if (print_only_ids) {
+ JSONObject obj(functions);
+ if (kind() == kDartFunction) {
+ ASSERT(!function_.IsNull());
+ obj.AddProperty("type", "@Object");
+ function_.AddFunctionServiceId(obj);
+ } else {
+ PrintToJSONObject(&obj);
+ }
+ return;
+ }
JSONObject obj(functions);
obj.AddProperty("type", "ProfileFunction");
obj.AddProperty("kind", KindToCString(kind()));
@@ -1728,10 +1740,16 @@
PrintProfileJSON(&obj, include_code_samples);
}
-void Profile::PrintProfileJSON(JSONObject* obj, bool include_code_samples) {
+void Profile::PrintProfileJSON(JSONObject* obj,
+ bool include_code_samples,
+ bool is_event) {
ScopeTimer sw("Profile::PrintProfileJSON", FLAG_trace_profiler);
Thread* thread = Thread::Current();
- obj->AddProperty("type", "CpuSamples");
+ if (is_event) {
+ obj->AddProperty("type", "CpuSamplesEvent");
+ } else {
+ obj->AddProperty("type", "CpuSamples");
+ }
PrintHeaderJSON(obj);
if (include_code_samples) {
JSONArray codes(obj, "_codes");
@@ -1760,7 +1778,7 @@
for (intptr_t i = 0; i < functions_->length(); i++) {
ProfileFunction* function = functions_->At(i);
ASSERT(function != NULL);
- function->PrintToJSONArray(&functions);
+ function->PrintToJSONArray(&functions, is_event);
thread->CheckForSafepoint();
}
}
diff --git a/runtime/vm/profiler_service.h b/runtime/vm/profiler_service.h
index a9df89b..13a29fa 100644
--- a/runtime/vm/profiler_service.h
+++ b/runtime/vm/profiler_service.h
@@ -171,7 +171,7 @@
static const char* KindToCString(Kind kind);
- void PrintToJSONArray(JSONArray* functions);
+ void PrintToJSONArray(JSONArray* functions, bool print_only_ids = false);
// Returns true if the call was successful and |pfsp| is set.
bool GetSinglePosition(ProfileFunctionSourcePosition* pfsp);
@@ -385,7 +385,9 @@
ProfileCode* GetCodeFromPC(uword pc, int64_t timestamp);
void PrintProfileJSON(JSONStream* stream, bool include_code_samples);
- void PrintProfileJSON(JSONObject* obj, bool include_code_samples);
+ void PrintProfileJSON(JSONObject* obj,
+ bool include_code_samples,
+ bool is_event = false);
ProfileFunction* FindFunction(const Function& function);
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index dba5444..209387d 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -1791,6 +1791,18 @@
}
return field.ptr();
}
+ if (strcmp(parts[2], "field_inits") == 0) {
+ // Field initializer ids look like: "classes/17/field_inits/name"
+ const auto& field = Field::Handle(klass.LookupField(id));
+ if (field.IsNull() || (field.is_late() && !field.has_initializer())) {
+ return Object::sentinel().ptr();
+ }
+ const auto& function = Function::Handle(field.EnsureInitializerFunction());
+ if (function.IsNull()) {
+ return Object::sentinel().ptr();
+ }
+ return function.ptr();
+ }
if (strcmp(parts[2], "functions") == 0) {
// Function ids look like: "classes/17/functions/name"
@@ -1883,6 +1895,10 @@
// Library field ids look like: "libraries/17/fields/name"
return LookupClassMembers(Thread::Current(), klass, parts, num_parts);
}
+ if (strcmp(parts[2], "field_inits") == 0) {
+ // Library field ids look like: "libraries/17/field_inits/name"
+ return LookupClassMembers(Thread::Current(), klass, parts, num_parts);
+ }
if (strcmp(parts[2], "functions") == 0) {
// Library function ids look like: "libraries/17/functions/name"
return LookupClassMembers(Thread::Current(), klass, parts, num_parts);
@@ -1952,6 +1968,9 @@
if (strcmp(parts[2], "closures") == 0) {
// Closure ids look like: "classes/17/closures/11"
return LookupClassMembers(thread, cls, parts, num_parts);
+ } else if (strcmp(parts[2], "field_inits") == 0) {
+ // Field initializer ids look like: "classes/17/field_inits/name"
+ return LookupClassMembers(thread, cls, parts, num_parts);
} else if (strcmp(parts[2], "fields") == 0) {
// Field ids look like: "classes/17/fields/name"
return LookupClassMembers(thread, cls, parts, num_parts);
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index 59e9e24..c31b191 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -15,7 +15,7 @@
namespace dart {
#define SERVICE_PROTOCOL_MAJOR_VERSION 3
-#define SERVICE_PROTOCOL_MINOR_VERSION 53
+#define SERVICE_PROTOCOL_MINOR_VERSION 54
class Array;
class EmbedderServiceHandler;
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index 0865d15..6a04228 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1,8 +1,8 @@
-# Dart VM Service Protocol 3.53
+# Dart VM Service Protocol 3.54
> Please post feedback to the [observatory-discuss group][discuss-list]
-This document describes of _version 3.53_ of the Dart VM Service Protocol. This
+This document describes of _version 3.54_ of the Dart VM Service Protocol. This
protocol is used to communicate with a running Dart Virtual Machine.
To use the Service Protocol, start the VM with the *--observe* flag.
@@ -1987,6 +1987,46 @@
See [getCpuSamples](#getcpusamples) and [CpuSample](#cpusample).
+### CpuSamplesEvent
+
+```
+class CpuSamplesEvent {
+ // The sampling rate for the profiler in microseconds.
+ int samplePeriod;
+
+ // The maximum possible stack depth for samples.
+ int maxStackDepth;
+
+ // The number of samples returned.
+ int sampleCount;
+
+ // The timespan the set of returned samples covers, in microseconds (deprecated).
+ //
+ // Note: this property is deprecated and will always return -1. Use `timeExtentMicros`
+ // instead.
+ int timeSpan;
+
+ // The start of the period of time in which the returned samples were
+ // collected.
+ int timeOriginMicros;
+
+ // The duration of time covered by the returned samples.
+ int timeExtentMicros;
+
+ // The process ID for the VM.
+ int pid;
+
+ // A list of references to functions seen in the relevant samples. These references can
+ // be looked up using the indicies provided in a `CpuSample` `stack` to determine
+ // which function was on the stack.
+ (@Object|NativeFunction)[] functions;
+
+ // A list of samples collected in the range
+ // `[timeOriginMicros, timeOriginMicros + timeExtentMicros]`
+ CpuSample[] samples;
+}
+```
+
### CpuSample
```
@@ -2251,7 +2291,7 @@
string previousTag [optional];
// A CPU profile containing recent samples.
- CpuSamples cpuSamples [optional];
+ CpuSamplesEvent cpuSamples [optional];
}
```
@@ -4263,4 +4303,6 @@
3.51 | Added optional `reportLines` parameter to `getSourceReport` RPC.
3.52 | Added `lookupResolvedPackageUris` and `lookupPackageUris` RPCs and `UriList` type.
3.53 | Added `setIsolatePauseMode` RPC.
+3.54 | Added `CpuSamplesEvent`, updated `cpuSamples` property on `Event` to have type `CpuSamplesEvent`.
+
[discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
diff --git a/runtime/vm/service_event.cc b/runtime/vm/service_event.cc
index 85740cf..6ef5b54 100644
--- a/runtime/vm/service_event.cc
+++ b/runtime/vm/service_event.cc
@@ -307,7 +307,8 @@
if (kind() == kCpuSamples) {
JSONObject cpu_profile(&jsobj, "cpuSamples");
- cpu_profile_->PrintProfileJSON(&cpu_profile, false);
+ cpu_profile_->PrintProfileJSON(&cpu_profile, /*include_code_samples=*/false,
+ /*is_event=*/true);
}
}
diff --git a/tests/web/47691_test.dart b/tests/web/47691_test.dart
new file mode 100644
index 0000000..db8ae9d
--- /dev/null
+++ b/tests/web/47691_test.dart
@@ -0,0 +1,26 @@
+// 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.
+
+import 'package:expect/expect.dart';
+
+class LoadElements {
+ List call() => [];
+}
+
+class ViewModel {
+ ViewModel(this._loadElements);
+
+ final LoadElements _loadElements;
+
+ void init() {
+ final elements = _loadElements();
+ for (final element in elements) {
+ Expect.identical(element, element);
+ }
+ }
+}
+
+void main() {
+ ViewModel(LoadElements()).init();
+}
diff --git a/tests/web_2/47691_test.dart b/tests/web_2/47691_test.dart
new file mode 100644
index 0000000..7de21ae
--- /dev/null
+++ b/tests/web_2/47691_test.dart
@@ -0,0 +1,28 @@
+// 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.7
+
+import 'package:expect/expect.dart';
+
+class LoadElements {
+ List call() => [];
+}
+
+class ViewModel {
+ ViewModel(this._loadElements);
+
+ final LoadElements _loadElements;
+
+ void init() {
+ final elements = _loadElements();
+ for (final element in elements) {
+ Expect.identical(element, element);
+ }
+ }
+}
+
+void main() {
+ ViewModel(LoadElements()).init();
+}
diff --git a/tools/VERSION b/tools/VERSION
index 9cc28c9..6de95d5 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 16
PATCH 0
-PRERELEASE 27
+PRERELEASE 28
PRERELEASE_PATCH 0
\ No newline at end of file