Version 2.10.0-109.0.dev
Merge commit '9181df9d6bf5b3d80e59d0f249c8ff9460b0f28f' into 'dev'
diff --git a/pkg/analysis_server/test/analysis/get_navigation_test.dart b/pkg/analysis_server/test/analysis/get_navigation_test.dart
index f2f2cf1..4dbe557 100644
--- a/pkg/analysis_server/test/analysis/get_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/get_navigation_test.dart
@@ -43,6 +43,29 @@
assertHasTarget('test = 0');
}
+ Future<void> test_comment_outsideReference() async {
+ addTestFile('''
+/// Returns a [String].
+String main() {
+}''');
+ await waitForTasksFinished();
+ var search = 'Returns';
+ await _getNavigation(testFile, testCode.indexOf(search), 1);
+ expect(regions, hasLength(0));
+ }
+
+ Future<void> test_comment_reference() async {
+ addTestFile('''
+/// Returns a [String].
+String main() {
+}''');
+ await waitForTasksFinished();
+ var search = '[String';
+ await _getNavigation(testFile, testCode.indexOf(search), 1);
+ expect(regions, hasLength(1));
+ assertHasRegion('String]');
+ }
+
Future<void> test_fieldType() async {
// This test mirrors test_navigation() from
// test/integration/analysis/get_navigation_test.dart
@@ -101,20 +124,6 @@
expect(testTargets[0].kind, ElementKind.LIBRARY);
}
- Future<void> test_importKeyword() async {
- addTestFile('''
-import 'dart:math';
-
-main() {
-}''');
- await waitForTasksFinished();
- await _getNavigation(testFile, 0, 1);
- expect(regions, hasLength(1));
- assertHasRegionString("'dart:math'");
- expect(testTargets, hasLength(1));
- expect(testTargets[0].kind, ElementKind.LIBRARY);
- }
-
Future<void> test_importUri() async {
addTestFile('''
import 'dart:math';
diff --git a/pkg/analysis_server/test/integration/analysis/get_navigation_test.dart b/pkg/analysis_server/test/integration/analysis/get_navigation_test.dart
index bd69280..1288adb 100644
--- a/pkg/analysis_server/test/integration/analysis/get_navigation_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/get_navigation_test.dart
@@ -41,9 +41,7 @@
expect(target.startColumn, 7);
}
- @failingTest
Future<void> test_navigation_no_result() async {
- // This fails - it returns navigation results for a whitespace area (#28799).
var pathname = sourcePath('test.dart');
var text = r'''
//
diff --git a/pkg/analysis_server/test/lsp/definition_test.dart b/pkg/analysis_server/test/lsp/definition_test.dart
index a243579..d64412c 100644
--- a/pkg/analysis_server/test/lsp/definition_test.dart
+++ b/pkg/analysis_server/test/lsp/definition_test.dart
@@ -55,6 +55,26 @@
expect(loc.uri, equals(referencedFileUri.toString()));
}
+ Future<void> test_comment_adjacentReference() async {
+ /// Computing Dart navigation locates a node at the provided offset then
+ /// returns all navigation regions inside it. This test ensures we filter
+ /// out any regions that are in the same target node (the comment) but do
+ /// not span the requested offset.
+ final contents = '''
+ /// Te^st
+ ///
+ /// References [String].
+ main() {}
+ ''';
+
+ await initialize();
+ await openFile(mainFileUri, withoutMarkers(contents));
+ final res = await getDefinitionAsLocation(
+ mainFileUri, positionFromMarker(contents));
+
+ expect(res, hasLength(0));
+ }
+
Future<void> test_fromPlugins() async {
final pluginAnalyzedFilePath = join(projectFolderPath, 'lib', 'foo.foo');
final pluginAnalyzedFileUri = Uri.file(pluginAnalyzedFilePath);
@@ -176,6 +196,59 @@
expect(res, isEmpty);
}
+ /// Failing due to incorrect range because _DartNavigationCollector._getCodeLocation
+ /// does not handle parts.
+ @failingTest
+ Future<void> test_part() async {
+ final mainContents = '''
+ import 'lib.dart';
+
+ main() {
+ Icons.[[ad^d]]();
+ }
+ ''';
+
+ final libContents = '''
+ part 'part.dart';
+ ''';
+
+ final partContents = '''
+ part of 'lib.dart';
+
+ void unrelatedFunction() {}
+
+ class Icons {
+ /// `targetRange` should not include the dartDoc but should include the full
+ /// function body. `targetSelectionRange` will be just the name.
+ [[String add = "Test"]];
+ }
+
+ void otherUnrelatedFunction() {}
+ ''';
+
+ final libFileUri = Uri.file(join(projectFolderPath, 'lib', 'lib.dart'));
+ final partFileUri = Uri.file(join(projectFolderPath, 'lib', 'part.dart'));
+
+ await initialize(
+ textDocumentCapabilities:
+ withLocationLinkSupport(emptyTextDocumentClientCapabilities));
+ await openFile(mainFileUri, withoutMarkers(mainContents));
+ await openFile(libFileUri, withoutMarkers(libContents));
+ await openFile(partFileUri, withoutMarkers(partContents));
+ final res = await getDefinitionAsLocationLinks(
+ mainFileUri, positionFromMarker(mainContents));
+
+ expect(res, hasLength(1));
+ var loc = res.single;
+ expect(loc.originSelectionRange, equals(rangeFromMarkers(mainContents)));
+ expect(loc.targetUri, equals(partFileUri.toString()));
+ expect(loc.targetRange, equals(rangeFromMarkers(partContents)));
+ expect(
+ loc.targetSelectionRange,
+ equals(rangeOfString(partContents, 'add')),
+ );
+ }
+
Future<void> test_sameLine() async {
final contents = '''
int plusOne(int [[value]]) => 1 + val^ue;
diff --git a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
index a0b22fb..4fd07d6 100644
--- a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
@@ -100,27 +100,6 @@
_flowAnalysis?.assignmentExpression_afterRight(node);
}
- /// Set the static type of [node] to be the least upper bound of the static
- /// types [staticType1] and [staticType2].
- ///
- /// TODO(scheglov) this is duplicate
- void _analyzeLeastUpperBoundTypes(
- Expression node, DartType staticType1, DartType staticType2) {
- // TODO(brianwilkerson) Determine whether this can still happen.
- staticType1 ??= DynamicTypeImpl.instance;
-
- // TODO(brianwilkerson) Determine whether this can still happen.
- staticType2 ??= DynamicTypeImpl.instance;
-
- DartType staticType =
- _typeSystem.getLeastUpperBound(staticType1, staticType2) ??
- DynamicTypeImpl.instance;
-
- staticType = _resolver.toLegacyTypeIfOptOut(staticType);
-
- _inferenceHelper.recordStaticType(node, staticType);
- }
-
void _checkForInvalidAssignment(
DartType writeType,
Expression right,
@@ -170,17 +149,6 @@
return true;
}
- /// Return the non-nullable variant of the [type] if null safety is enabled,
- /// otherwise return the type itself.
- ///
- // TODO(scheglov) this is duplicate
- DartType _nonNullable(DartType type) {
- if (_isNonNullableByDefault) {
- return _typeSystem.promoteToNonNull(type);
- }
- return type;
- }
-
/// Record that the static type of the given node is the given type.
///
/// @param expression the node whose type is to be recorded
@@ -348,29 +316,20 @@
var rightType = node.rightHandSide.staticType;
_inferenceHelper.recordStaticType(node, rightType);
} else if (operator == TokenType.QUESTION_QUESTION_EQ) {
+ var leftType = node.readType;
+
+ // The LHS value will be used only if it is non-null.
if (_isNonNullableByDefault) {
- // The static type of a compound assignment using ??= with NNBD is the
- // least upper bound of the static types of the LHS and RHS after
- // promoting the LHS/ to non-null (as we know its value will not be used
- // if null)
- _analyzeLeastUpperBoundTypes(
- node,
- _typeSystem.promoteToNonNull(node.readType),
- getReadType(node.rightHandSide),
- );
- } else {
- // The static type of a compound assignment using ??= before NNBD is the
- // least upper bound of the static types of the LHS and RHS.
- _analyzeLeastUpperBoundTypes(
- node,
- node.readType,
- node.rightHandSide.staticType,
- );
+ leftType = _typeSystem.promoteToNonNull(leftType);
}
+
+ var rightType = node.rightHandSide.staticType;
+ var result = _typeSystem.getLeastUpperBound(leftType, rightType);
+
+ _inferenceHelper.recordStaticType(node, result);
} else if (operator == TokenType.AMPERSAND_AMPERSAND_EQ ||
operator == TokenType.BAR_BAR_EQ) {
- _inferenceHelper.recordStaticType(
- node, _nonNullable(_typeProvider.boolType));
+ _inferenceHelper.recordStaticType(node, _typeProvider.boolType);
} else {
var rightType = node.rightHandSide.staticType;
diff --git a/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart b/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
index efa84ae..cd05675 100644
--- a/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
+++ b/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
@@ -19,7 +19,7 @@
CompilationUnit unit,
int offset,
int length) {
- var dartCollector = _DartNavigationCollector(collector);
+ var dartCollector = _DartNavigationCollector(collector, offset, length);
var visitor = _DartNavigationComputerVisitor(resourceProvider, dartCollector);
if (offset == null || length == null) {
unit.accept(visitor);
@@ -43,8 +43,11 @@
/// A Dart specific wrapper around [NavigationCollector].
class _DartNavigationCollector {
final NavigationCollector collector;
+ final int requestedOffset;
+ final int requestedLength;
- _DartNavigationCollector(this.collector);
+ _DartNavigationCollector(
+ this.collector, this.requestedOffset, this.requestedLength);
void _addRegion(int offset, int length, Element element) {
if (element is FieldFormalParameterElement) {
@@ -56,6 +59,12 @@
if (element.location == null) {
return;
}
+ // Discard elements that don't span the offset/range given (if provided).
+ if (requestedOffset != null &&
+ (offset > requestedOffset + (requestedLength ?? 0) ||
+ offset + length < requestedOffset)) {
+ return;
+ }
var converter = AnalyzerConverter();
var kind = converter.convertElementKind(element.kind);
var location = converter.locationFromElement(element);
@@ -118,9 +127,13 @@
}
// Read the declaration so we can get the offset after the doc comments.
- final declaration = codeElement.session
- .getParsedLibrary(location.file)
- .getElementDeclaration(codeElement);
+ // TODO(dantup): Skip this for parts (getParsedLibrary will throw), but find
+ // a better solution.
+ final declaration = !codeElement.session.getFile(location.file).isPart
+ ? codeElement.session
+ .getParsedLibrary(location.file)
+ .getElementDeclaration(codeElement)
+ : null;
var node = declaration?.node;
if (node is VariableDeclaration) {
node = node.parent;
diff --git a/pkg/dartdev/lib/dartdev.dart b/pkg/dartdev/lib/dartdev.dart
index d60260f..41f0901 100644
--- a/pkg/dartdev/lib/dartdev.dart
+++ b/pkg/dartdev/lib/dartdev.dart
@@ -22,6 +22,7 @@
import 'src/commands/run.dart';
import 'src/commands/test.dart';
import 'src/core.dart';
+import 'src/events.dart';
import 'src/experiments.dart';
import 'src/sdk.dart';
import 'src/utils.dart';
@@ -35,10 +36,6 @@
final stopwatch = Stopwatch();
int result;
- // The Analytics instance used to report information back to Google Analytics,
- // see lib/src/analytics.dart.
- Analytics analytics;
-
// The exit code for the dartdev process, null indicates that it has not yet
// been set yet. The value is set in the catch and finally blocks below.
int exitCode;
@@ -47,7 +44,9 @@
Object exception;
StackTrace stackTrace;
- analytics =
+ // The Analytics instance used to report information back to Google Analytics,
+ // see lib/src/analytics.dart.
+ Analytics analytics =
createAnalyticsInstance(args.contains('--disable-dartdev-analytics'));
// If we have not printed the analyticsNoticeOnFirstRunMessage to stdout,
@@ -92,11 +91,13 @@
// RunCommand.ddsHost = ddsUrl[0];
// RunCommand.ddsPort = ddsUrl[1];
}
+
String commandName;
try {
stopwatch.start();
final runner = DartdevRunner(args);
+
// Run can't be called with the '--disable-dartdev-analytics' flag, remove
// it if it is contained in args.
if (args.contains('--disable-dartdev-analytics')) {
@@ -119,14 +120,6 @@
)
.toList();
- // Before calling to run, send the first ping to analytics to have the first
- // ping, as well as the command itself, running in parallel.
- if (analytics.enabled) {
- commandName = getCommandStr(args, runner.commands.keys.toList());
- // ignore: unawaited_futures
- analytics.sendEvent(eventCategory, commandName);
- }
-
// If ... help pub ... is in the args list, remove 'help', and add '--help'
// to the end of the list. This will make it possible to use the help
// command to access subcommands of pub such as `dart help pub publish`, see
@@ -135,6 +128,17 @@
args = PubUtils.modifyArgs(args);
}
+ // For the commands format and migrate, dartdev itself sends the
+ // sendScreenView notification to analytics, for all other
+ // dartdev commands (instances of DartdevCommand) the commands send this
+ // to analytics.
+ commandName = ArgParserUtils.getCommandStr(args);
+ if (analytics.enabled &&
+ (commandName == formatCmdName || commandName == migrateCmdName)) {
+ // ignore: unawaited_futures
+ analytics.sendScreenView(commandName);
+ }
+
// Finally, call the runner to execute the command, see DartdevRunner.
result = await runner.run(args);
} catch (e, st) {
@@ -157,7 +161,22 @@
// Send analytics before exiting
if (analytics.enabled) {
- analytics.setSessionValue(exitCodeParam, exitCode);
+ // For commands that are not DartdevCommand instances, we manually create
+ // and send the UsageEvent from here:
+ if (commandName == formatCmdName) {
+ // ignore: unawaited_futures
+ FormatUsageEvent(
+ exitCode: exitCode,
+ args: args,
+ ).send(analyticsInstance);
+ } else if (commandName == migrateCmdName) {
+ // ignore: unawaited_futures
+ MigrateUsageEvent(
+ exitCode: exitCode,
+ args: args,
+ ).send(analyticsInstance);
+ }
+
// ignore: unawaited_futures
analytics.sendTiming(commandName, stopwatch.elapsedMilliseconds,
category: 'commands');
diff --git a/pkg/dartdev/lib/src/analytics.dart b/pkg/dartdev/lib/src/analytics.dart
index 5a1037a..595fec0 100644
--- a/pkg/dartdev/lib/src/analytics.dart
+++ b/pkg/dartdev/lib/src/analytics.dart
@@ -26,7 +26,6 @@
║ `dart --enable-analytics` ║
╚════════════════════════════════════════════════════════════════════════════╝
''';
-const String _unknownCommand = '<unknown>';
const String _appName = 'dartdev';
const String _dartDirectoryName = '.dart';
const String _settingsFileName = 'dartdev.json';
@@ -40,13 +39,15 @@
const String eventCategory = 'dartdev';
const String exitCodeParam = 'exitCode';
-Analytics instance;
+Analytics _instance;
+
+Analytics get analyticsInstance => _instance;
/// Create and return an [Analytics] instance, this value is cached and returned
/// on subsequent calls.
Analytics createAnalyticsInstance(bool disableAnalytics) {
- if (instance != null) {
- return instance;
+ if (_instance != null) {
+ return _instance;
}
// Dartdev tests pass a hidden 'disable-dartdev-analytics' flag which is
@@ -54,16 +55,16 @@
// Also, stdout.hasTerminal is checked, if there is no terminal we infer that
// a machine is running dartdev so we return analytics shouldn't be set.
if (disableAnalytics) {
- instance = DisabledAnalytics(_trackingId, _appName);
- return instance;
+ _instance = DisabledAnalytics(_trackingId, _appName);
+ return _instance;
}
var settingsDir = getDartStorageDirectory();
if (settingsDir == null) {
// Some systems don't support user home directories; for those, fail
// gracefully by returning a disabled analytics object.
- instance = DisabledAnalytics(_trackingId, _appName);
- return instance;
+ _instance = DisabledAnalytics(_trackingId, _appName);
+ return _instance;
}
if (!settingsDir.existsSync()) {
@@ -72,8 +73,8 @@
} catch (e) {
// If we can't create the directory for the analytics settings, fail
// gracefully by returning a disabled analytics object.
- instance = DisabledAnalytics(_trackingId, _appName);
- return instance;
+ _instance = DisabledAnalytics(_trackingId, _appName);
+ return _instance;
}
}
@@ -85,22 +86,8 @@
}
var settingsFile = File(path.join(settingsDir.path, _settingsFileName));
- instance = DartdevAnalytics(_trackingId, settingsFile, _appName);
- return instance;
-}
-
-/// Return the first member from [args] that occurs in [allCommands], otherwise
-/// '<unknown>' is returned.
-///
-/// 'help' is special cased to have 'dart analyze help', 'dart help analyze',
-/// and 'dart analyze --help' all be recorded as a call to 'help' instead of
-/// 'help' and 'analyze'.
-String getCommandStr(List<String> args, List<String> allCommands) {
- if (args.contains('help') || args.contains('-h') || args.contains('--help')) {
- return 'help';
- }
- return args.firstWhere((arg) => allCommands.contains(arg),
- orElse: () => _unknownCommand);
+ _instance = DartdevAnalytics(_trackingId, settingsFile, _appName);
+ return _instance;
}
/// The directory used to store the analytics settings file.
diff --git a/pkg/dartdev/lib/src/commands/analyze.dart b/pkg/dartdev/lib/src/commands/analyze.dart
index 139d262..08d8590 100644
--- a/pkg/dartdev/lib/src/commands/analyze.dart
+++ b/pkg/dartdev/lib/src/commands/analyze.dart
@@ -5,14 +5,18 @@
import 'dart:async';
import 'dart:io';
+import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;
import '../core.dart';
+import '../events.dart';
import '../sdk.dart';
import '../utils.dart';
import 'analyze_impl.dart';
class AnalyzeCommand extends DartdevCommand<int> {
+ static const String cmdName = 'analyze';
+
/// The maximum length of any of the existing severity labels.
static const int _severityWidth = 7;
@@ -20,7 +24,7 @@
/// message. The width left for the severity label plus the separator width.
static const int _bodyIndentWidth = _severityWidth + 3;
- AnalyzeCommand() : super('analyze', "Analyze the project's Dart code.") {
+ AnalyzeCommand() : super(cmdName, "Analyze the project's Dart code.") {
argParser
..addFlag('fatal-infos',
help: 'Treat info level issues as fatal.', negatable: false)
@@ -32,7 +36,7 @@
String get invocation => '${super.invocation} [<directory>]';
@override
- FutureOr<int> run() async {
+ FutureOr<int> runImpl() async {
if (argResults.rest.length > 1) {
usageException('Only one directory is expected.');
}
@@ -153,4 +157,19 @@
return 0;
}
}
+
+ @override
+ UsageEvent createUsageEvent(int exitCode) => AnalyzeUsageEvent(
+ usagePath,
+ exitCode: exitCode,
+ args: argResults.arguments,
+ );
+}
+
+/// The [UsageEvent] for the analyze command.
+class AnalyzeUsageEvent extends UsageEvent {
+ AnalyzeUsageEvent(String usagePath,
+ {String label, @required int exitCode, @required List<String> args})
+ : super(AnalyzeCommand.cmdName, usagePath,
+ label: label, args: args, exitCode: exitCode);
}
diff --git a/pkg/dartdev/lib/src/commands/compile.dart b/pkg/dartdev/lib/src/commands/compile.dart
index 5da7168..491d7ae 100644
--- a/pkg/dartdev/lib/src/commands/compile.dart
+++ b/pkg/dartdev/lib/src/commands/compile.dart
@@ -6,9 +6,11 @@
import 'dart:io';
import 'package:dart2native/generate.dart';
+import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;
import '../core.dart';
+import '../events.dart';
import '../sdk.dart';
import '../vm_interop_handler.dart';
@@ -39,12 +41,13 @@
stderr.flush();
return false;
}
-
return true;
}
-class CompileJSCommand extends DartdevCommand<int> {
- CompileJSCommand() : super('js', 'Compile Dart to JavaScript.') {
+class CompileJSCommand extends CompileSubcommandCommand {
+ static const String cmdName = 'js';
+
+ CompileJSCommand() : super(cmdName, 'Compile Dart to JavaScript.') {
argParser
..addOption(
commonOptions['outputFile'].flag,
@@ -63,7 +66,7 @@
String get invocation => '${super.invocation} <dart entry point>';
@override
- FutureOr<int> run() async {
+ FutureOr<int> runImpl() async {
if (!Sdk.checkArtifactExists(sdk.dart2jsSnapshot)) {
return 255;
}
@@ -97,7 +100,10 @@
}
}
-class CompileSnapshotCommand extends DartdevCommand<int> {
+class CompileSnapshotCommand extends CompileSubcommandCommand {
+ static const String jitSnapshotCmdName = 'jit-snapshot';
+ static const String kernelCmdName = 'kernel';
+
final String commandName;
final String help;
final String fileExt;
@@ -121,7 +127,7 @@
String get invocation => '${super.invocation} <dart entry point>';
@override
- FutureOr<int> run() async {
+ FutureOr<int> runImpl() async {
// We expect a single rest argument; the dart entry point.
if (argResults.rest.length != 1) {
// This throws.
@@ -157,7 +163,10 @@
}
}
-class CompileNativeCommand extends DartdevCommand<int> {
+class CompileNativeCommand extends CompileSubcommandCommand {
+ static const String exeCmdName = 'exe';
+ static const String aotSnapshotCmdName = 'aot-snapshot';
+
final String commandName;
final String format;
final String help;
@@ -194,7 +203,7 @@
String get invocation => '${super.invocation} <dart entry point>';
@override
- FutureOr<int> run() async {
+ FutureOr<int> runImpl() async {
if (!Sdk.checkArtifactExists(genKernel) ||
!Sdk.checkArtifactExists(genSnapshot)) {
return 255;
@@ -230,30 +239,64 @@
}
}
-class CompileCommand extends DartdevCommand {
- CompileCommand() : super('compile', 'Compile Dart to various formats.') {
+abstract class CompileSubcommandCommand extends DartdevCommand<int> {
+ CompileSubcommandCommand(String name, String description,
+ {bool hidden = false})
+ : super(name, description, hidden: hidden);
+
+ @override
+ UsageEvent createUsageEvent(int exitCode) => CompileUsageEvent(
+ usagePath,
+ exitCode: exitCode,
+ args: argResults.arguments,
+ );
+}
+
+class CompileCommand extends DartdevCommand<int> {
+ static const String cmdName = 'compile';
+
+ CompileCommand() : super(cmdName, 'Compile Dart to various formats.') {
addSubcommand(CompileJSCommand());
addSubcommand(CompileSnapshotCommand(
- commandName: 'jit-snapshot',
+ commandName: CompileSnapshotCommand.jitSnapshotCmdName,
help: 'to a JIT snapshot.',
fileExt: 'jit',
formatName: 'app-jit',
));
addSubcommand(CompileSnapshotCommand(
- commandName: 'kernel',
+ commandName: CompileSnapshotCommand.kernelCmdName,
help: 'to a kernel snapshot.',
fileExt: 'dill',
formatName: 'kernel',
));
addSubcommand(CompileNativeCommand(
- commandName: 'exe',
+ commandName: CompileNativeCommand.exeCmdName,
help: 'to a self-contained executable.',
format: 'exe',
));
addSubcommand(CompileNativeCommand(
- commandName: 'aot-snapshot',
+ commandName: CompileNativeCommand.aotSnapshotCmdName,
help: 'to an AOT snapshot.',
format: 'aot',
));
}
+
+ @override
+ UsageEvent createUsageEvent(int exitCode) => null;
+
+ @override
+ FutureOr<int> runImpl() {
+ // do nothing, this command is never run
+ return 0;
+ }
+}
+
+/// The [UsageEvent] for all compile commands, we could have each compile
+/// event be its own class instance, but for the time being [usagePath] takes
+/// care of the only difference.
+class CompileUsageEvent extends UsageEvent {
+ CompileUsageEvent(String usagePath,
+ {String label, @required int exitCode, @required List<String> args})
+ : super(CompileCommand.cmdName, usagePath,
+ label: label, exitCode: exitCode, args: args);
}
diff --git a/pkg/dartdev/lib/src/commands/create.dart b/pkg/dartdev/lib/src/commands/create.dart
index 4eda721..920de13 100644
--- a/pkg/dartdev/lib/src/commands/create.dart
+++ b/pkg/dartdev/lib/src/commands/create.dart
@@ -7,14 +7,18 @@
import 'dart:io' as io;
import 'dart:math' as math;
+import 'package:meta/meta.dart';
import 'package:path/path.dart' as p;
import 'package:stagehand/stagehand.dart' as stagehand;
import '../core.dart';
+import '../events.dart';
import '../sdk.dart';
/// A command to create a new project from a set of templates.
-class CreateCommand extends DartdevCommand {
+class CreateCommand extends DartdevCommand<int> {
+ static const String cmdName = 'create';
+
static String defaultTemplateId = 'console-simple';
static List<String> legalTemplateIds = [
@@ -31,7 +35,7 @@
stagehand.getGenerator(templateId);
CreateCommand({bool verbose = false})
- : super('create', 'Create a new project.') {
+ : super(cmdName, 'Create a new project.') {
argParser.addOption(
'template',
allowed: legalTemplateIds,
@@ -60,7 +64,7 @@
String get invocation => '${super.invocation} <directory>';
@override
- FutureOr<int> run() async {
+ FutureOr<int> runImpl() async {
if (argResults['list-templates']) {
log.stdout(_availableTemplatesJson());
return 0;
@@ -139,6 +143,13 @@
}
@override
+ UsageEvent createUsageEvent(int exitCode) => CreateUsageEvent(
+ usagePath,
+ exitCode: exitCode,
+ args: argResults.arguments,
+ );
+
+ @override
String get usageFooter {
int width = legalTemplateIds.map((s) => s.length).reduce(math.max);
String desc = generators.map((g) {
@@ -169,6 +180,14 @@
}
}
+/// The [UsageEvent] for the create command.
+class CreateUsageEvent extends UsageEvent {
+ CreateUsageEvent(String usagePath,
+ {String label, @required int exitCode, @required List<String> args})
+ : super(CreateCommand.cmdName, usagePath,
+ label: label, exitCode: exitCode, args: args);
+}
+
class DirectoryGeneratorTarget extends stagehand.GeneratorTarget {
final stagehand.Generator generator;
final io.Directory dir;
diff --git a/pkg/dartdev/lib/src/commands/fix.dart b/pkg/dartdev/lib/src/commands/fix.dart
index 36a8579..338158e 100644
--- a/pkg/dartdev/lib/src/commands/fix.dart
+++ b/pkg/dartdev/lib/src/commands/fix.dart
@@ -6,19 +6,23 @@
import 'dart:io';
import 'package:analysis_server_client/protocol.dart' hide AnalysisError;
+import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;
import '../core.dart';
+import '../events.dart';
import '../sdk.dart';
import '../utils.dart';
import 'analyze_impl.dart';
-class FixCommand extends DartdevCommand {
+class FixCommand extends DartdevCommand<int> {
+ static const String cmdName = 'fix';
+
// This command is hidden as its currently experimental.
- FixCommand() : super('fix', 'Fix Dart source code.', hidden: true);
+ FixCommand() : super(cmdName, 'Fix Dart source code.', hidden: true);
@override
- FutureOr<int> run() async {
+ FutureOr<int> runImpl() async {
log.stdout('\n*** The `fix` command is provisional and subject to change '
'or removal in future releases. ***\n');
@@ -76,7 +80,21 @@
}
log.stdout('Done.');
}
-
return 0;
}
+
+ @override
+ UsageEvent createUsageEvent(int exitCode) => FixUsageEvent(
+ usagePath,
+ exitCode: exitCode,
+ args: argResults.arguments,
+ );
+}
+
+/// The [UsageEvent] for the fix command.
+class FixUsageEvent extends UsageEvent {
+ FixUsageEvent(String usagePath,
+ {String label, @required int exitCode, @required List<String> args})
+ : super(FixCommand.cmdName, usagePath,
+ label: label, exitCode: exitCode, args: args);
}
diff --git a/pkg/dartdev/lib/src/commands/pub.dart b/pkg/dartdev/lib/src/commands/pub.dart
index 6b40ebc..c30bc61 100644
--- a/pkg/dartdev/lib/src/commands/pub.dart
+++ b/pkg/dartdev/lib/src/commands/pub.dart
@@ -5,14 +5,37 @@
import 'dart:async';
import 'package:args/args.dart';
+import 'package:meta/meta.dart';
import '../core.dart';
+import '../events.dart';
import '../experiments.dart';
import '../sdk.dart';
import '../vm_interop_handler.dart';
class PubCommand extends DartdevCommand<int> {
- PubCommand() : super('pub', 'Work with packages.');
+ static const String cmdName = 'pub';
+
+ PubCommand() : super(cmdName, 'Work with packages.');
+
+ // TODO(jwren) as soon as pub commands are are implemented directly in
+ // dartdev, remove this static list.
+ /// A list of all subcommands, used only for the implementation of
+ /// [usagePath], see below.
+ static List<String> pubSubcommands = [
+ 'cache',
+ 'deps',
+ 'downgrade',
+ 'get',
+ 'global',
+ 'logout',
+ 'outdated',
+ 'publish',
+ 'run',
+ 'upgrade',
+ 'uploader',
+ 'version',
+ ];
@override
ArgParser createArgParser() => ArgParser.allowAnything();
@@ -34,8 +57,26 @@
VmInteropHandler.run(command, args);
}
+ /// Since the pub subcommands are not subclasses of DartdevCommand, we
+ /// override [usagePath] here as a special case to cover the first subcommand
+ /// under pub, i.e. we will have the path pub/cache
@override
- FutureOr<int> run() async {
+ String get usagePath {
+ if (argResults == null) {
+ return name;
+ }
+ var args = argResults.arguments;
+ var cmdIndex = args.indexOf(name) ?? 0;
+ for (int i = cmdIndex + 1; i < args.length; i++) {
+ if (pubSubcommands.contains(args[i])) {
+ return '$name/${args[i]}';
+ }
+ }
+ return name;
+ }
+
+ @override
+ FutureOr<int> runImpl() async {
if (!Sdk.checkArtifactExists(sdk.pubSnapshot)) {
return 255;
}
@@ -65,4 +106,26 @@
VmInteropHandler.run(command, args);
return 0;
}
+
+ @override
+ UsageEvent createUsageEvent(int exitCode) => PubUsageEvent(
+ usagePath,
+ exitCode: exitCode,
+ specifiedExperiments: specifiedExperiments,
+ args: argResults.arguments,
+ );
+}
+
+/// The [UsageEvent] for the pub command.
+class PubUsageEvent extends UsageEvent {
+ PubUsageEvent(String usagePath,
+ {String label,
+ @required int exitCode,
+ @required List<String> specifiedExperiments,
+ @required List<String> args})
+ : super(PubCommand.cmdName, usagePath,
+ label: label,
+ exitCode: exitCode,
+ specifiedExperiments: specifiedExperiments,
+ args: args);
}
diff --git a/pkg/dartdev/lib/src/commands/run.dart b/pkg/dartdev/lib/src/commands/run.dart
index feeb99c..9fa39e6 100644
--- a/pkg/dartdev/lib/src/commands/run.dart
+++ b/pkg/dartdev/lib/src/commands/run.dart
@@ -8,15 +8,19 @@
import 'dart:io';
import 'package:args/args.dart';
+import 'package:meta/meta.dart';
import 'package:path/path.dart';
import '../core.dart';
+import '../events.dart';
import '../experiments.dart';
import '../sdk.dart';
import '../utils.dart';
import '../vm_interop_handler.dart';
class RunCommand extends DartdevCommand<int> {
+ static const String cmdName = 'run';
+
static bool launchDds = false;
static String ddsHost;
static String ddsPort;
@@ -41,7 +45,7 @@
RunCommand({this.verbose = false})
: super(
- 'run',
+ cmdName,
'Run a Dart program.',
) {
// NOTE: When updating this list of flags, be sure to add any VM flags to
@@ -153,7 +157,7 @@
String get invocation => '${super.invocation} <dart file | package target>';
@override
- FutureOr<int> run() async {
+ FutureOr<int> runImpl() async {
// The command line arguments after 'run'
var args = argResults.arguments.toList();
@@ -236,6 +240,14 @@
VmInteropHandler.run(path, runArgs);
return 0;
}
+
+ @override
+ UsageEvent createUsageEvent(int exitCode) => RunUsageEvent(
+ usagePath,
+ exitCode: exitCode,
+ specifiedExperiments: specifiedExperiments,
+ args: argResults.arguments,
+ );
}
class _DebuggingSession {
@@ -282,3 +294,17 @@
}
}
}
+
+/// The [UsageEvent] for the run command.
+class RunUsageEvent extends UsageEvent {
+ RunUsageEvent(String usagePath,
+ {String label,
+ @required int exitCode,
+ @required List<String> specifiedExperiments,
+ @required List<String> args})
+ : super(RunCommand.cmdName, usagePath,
+ label: label,
+ exitCode: exitCode,
+ specifiedExperiments: specifiedExperiments,
+ args: args);
+}
diff --git a/pkg/dartdev/lib/src/commands/test.dart b/pkg/dartdev/lib/src/commands/test.dart
index dcb5a7f..beba8c8 100644
--- a/pkg/dartdev/lib/src/commands/test.dart
+++ b/pkg/dartdev/lib/src/commands/test.dart
@@ -5,8 +5,10 @@
import 'dart:async';
import 'package:args/args.dart';
+import 'package:meta/meta.dart';
import '../core.dart';
+import '../events.dart';
import '../experiments.dart';
import '../sdk.dart';
import '../vm_interop_handler.dart';
@@ -15,7 +17,9 @@
///
/// This command largely delegates to `pub run test`.
class TestCommand extends DartdevCommand<int> {
- TestCommand() : super('test', 'Run tests in this package.');
+ static const String cmdName = 'test';
+
+ TestCommand() : super(cmdName, 'Run tests in this package.');
@override
final ArgParser argParser = ArgParser.allowAnything();
@@ -26,7 +30,7 @@
}
@override
- FutureOr<int> run() async {
+ FutureOr<int> runImpl() async {
return _runImpl(argResults.arguments.toList());
}
@@ -70,6 +74,14 @@
return 0;
}
+ @override
+ UsageEvent createUsageEvent(int exitCode) => TestUsageEvent(
+ usagePath,
+ exitCode: exitCode,
+ specifiedExperiments: specifiedExperiments,
+ args: argResults.arguments,
+ );
+
void _printNoPubspecMessage(bool wasHelpCommand) {
log.stdout('''
No pubspec.yaml file found; please run this command from the root of your project.
@@ -118,6 +130,20 @@
}
}
+/// The [UsageEvent] for the test command.
+class TestUsageEvent extends UsageEvent {
+ TestUsageEvent(String usagePath,
+ {String label,
+ @required int exitCode,
+ @required List<String> specifiedExperiments,
+ @required List<String> args})
+ : super(TestCommand.cmdName, usagePath,
+ label: label,
+ exitCode: exitCode,
+ specifiedExperiments: specifiedExperiments,
+ args: args);
+}
+
const String _terseHelp = 'Run tests in this package.';
const String _usageHelp = 'Usage: dart test [files or directories...]';
diff --git a/pkg/dartdev/lib/src/core.dart b/pkg/dartdev/lib/src/core.dart
index cc3a505..5694415 100644
--- a/pkg/dartdev/lib/src/core.dart
+++ b/pkg/dartdev/lib/src/core.dart
@@ -2,6 +2,7 @@
// 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 'dart:async';
import 'dart:convert';
import 'dart:io';
@@ -10,6 +11,8 @@
import 'package:cli_util/cli_logging.dart';
import 'package:path/path.dart' as path;
+import 'analytics.dart';
+import 'events.dart';
import 'experiments.dart';
import 'sdk.dart';
import 'utils.dart';
@@ -39,6 +42,55 @@
@override
ArgParser get argParser => _argParser ??= createArgParser();
+ /// This method should not be overridden by subclasses, instead classes should
+ /// override [runImpl] and [createUsageEvent]. If analytics is enabled by this
+ /// command and the user, a [sendScreenView] is called to analytics, and then
+ /// after the command is run, an event is sent to analytics.
+ ///
+ /// If analytics is not enabled by this command or the user, then [runImpl] is
+ /// called and the exitCode value is returned.
+ @override
+ FutureOr<int> run() async {
+ var path = usagePath;
+ if (path != null &&
+ analyticsInstance != null &&
+ analyticsInstance.enabled) {
+ // Send the screen view to analytics
+ // ignore: unawaited_futures
+ analyticsInstance.sendScreenView(path);
+
+ // Run this command
+ var exitCode = await runImpl();
+
+ // Send the event to analytics
+ // ignore: unawaited_futures
+ createUsageEvent(exitCode)?.send(analyticsInstance);
+
+ // Finally return the exit code
+ return exitCode;
+ } else {
+ // Analytics is not enabled, run the command and return the exit code
+ return runImpl();
+ }
+ }
+
+ UsageEvent createUsageEvent(int exitCode);
+
+ FutureOr<int> runImpl();
+
+ /// The command name path to send to Google Analytics. Return null to disable
+ /// tracking of the command.
+ String get usagePath {
+ if (parent is DartdevCommand) {
+ final commandParent = parent as DartdevCommand;
+ final parentPath = commandParent.usagePath;
+ // Don't report for parents that return null for usagePath.
+ return parentPath == null ? null : '$parentPath/$name';
+ } else {
+ return name;
+ }
+ }
+
/// Create the ArgParser instance for this command.
///
/// Subclasses can override this in order to create a customized ArgParser.
diff --git a/pkg/dartdev/lib/src/events.dart b/pkg/dartdev/lib/src/events.dart
new file mode 100644
index 0000000..6cc5547
--- /dev/null
+++ b/pkg/dartdev/lib/src/events.dart
@@ -0,0 +1,204 @@
+// Copyright (c) 2020, 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:meta/meta.dart';
+import 'package:usage/usage.dart';
+
+import 'commands/analyze.dart';
+import 'commands/compile.dart';
+import 'commands/create.dart';
+import 'commands/fix.dart';
+import 'commands/pub.dart';
+import 'commands/run.dart';
+
+/// A list of all commands under dartdev.
+const List<String> allCommands = [
+ 'help',
+ AnalyzeCommand.cmdName,
+ CreateCommand.cmdName,
+ CompileCommand.cmdName,
+ FixCommand.cmdName,
+ formatCmdName,
+ migrateCmdName,
+ PubCommand.cmdName,
+ RunCommand.cmdName,
+ 'test'
+];
+
+/// The [String] identifier `dartdev`, used as the category in the events sent
+/// to analytics.
+const String _dartdev = 'dartdev';
+
+/// The [String] identifier `format`.
+const String formatCmdName = 'format';
+
+/// The [String] identifier `migrate`.
+const String migrateCmdName = 'migrate';
+
+/// The separator used to for joining the flag sets sent to analytics.
+const String _flagSeparator = ',';
+
+/// When some unknown command is used, for instance `dart foo`, the command is
+/// designated with this identifier.
+const String _unknownCommand = '<unknown>';
+
+/// The collection of custom dimensions understood by the analytics backend.
+/// When adding to this list, first ensure that the custom dimension is
+/// defined in the backend, or will be defined shortly after the relevant PR
+/// lands. The pattern here matches the flutter cli.
+enum CustomDimensions {
+ commandExitCode, // cd1
+ enabledExperiments, // cd2
+ commandFlags, // cd3
+}
+
+String cdKey(CustomDimensions cd) => 'cd${cd.index + 1}';
+
+Map<String, String> _useCdKeys(Map<CustomDimensions, String> parameters) {
+ return parameters.map(
+ (CustomDimensions k, String v) => MapEntry<String, String>(cdKey(k), v));
+}
+
+/// Utilities for parsing arguments passed to dartdev. These utilities have all
+/// been marked as static to assist with testing, see events_test.dart.
+class ArgParserUtils {
+ /// Return the first member from [args] that occurs in [allCommands],
+ /// otherwise '<unknown>' is returned.
+ ///
+ /// 'help' is special cased to have 'dart analyze help', 'dart help analyze',
+ /// and 'dart analyze --help' all be recorded as a call to 'help' instead of
+ /// 'help' and 'analyze'.
+ static String getCommandStr(List<String> args) {
+ if (args.contains('help') ||
+ args.contains('-h') ||
+ args.contains('--help')) {
+ return 'help';
+ }
+ return args.firstWhere((arg) => allCommands.contains(arg),
+ orElse: () => _unknownCommand);
+ }
+
+ /// Return true if the first character of the passed [String] is '-'.
+ static bool isFlag(String arg) => arg != null && arg.startsWith('-');
+
+ /// Returns true if and only if the passed argument equals 'help', '--help' or
+ /// '-h'.
+ static bool isHelp(String arg) =>
+ arg == 'help' || arg == '--help' || arg == '-h';
+
+ /// Given some command in args, return the set of flags after the command.
+ static List<String> parseCommandFlags(String command, List<String> args) {
+ var result = <String>[];
+ if (args == null || args.isEmpty) {
+ return result;
+ }
+
+ var indexOfCmd = args.indexOf(command);
+ if (indexOfCmd < 0) {
+ return result;
+ }
+
+ for (var i = indexOfCmd + 1; i < args.length; i++) {
+ if (!isHelp(args[i]) && isFlag(args[i])) {
+ result.add(sanitizeFlag(args[i]));
+ }
+ }
+ return result;
+ }
+
+ /// Return the passed flag, only if it is considered a flag, see [isFlag], and
+ /// if '=' is in the flag, return only the contents of the left hand side of
+ /// the '='.
+ static String sanitizeFlag(String arg) {
+ if (isFlag(arg)) {
+ if (arg.contains('=')) {
+ return arg.substring(0, arg.indexOf('='));
+ } else {
+ return arg;
+ }
+ }
+ return '';
+ }
+}
+
+/// The [UsageEvent] for the format command.
+class FormatUsageEvent extends UsageEvent {
+ FormatUsageEvent(
+ {String label, @required int exitCode, @required List<String> args})
+ : super(formatCmdName, formatCmdName,
+ label: label, exitCode: exitCode, args: args);
+}
+
+/// The [UsageEvent] for the migrate command.
+class MigrateUsageEvent extends UsageEvent {
+ MigrateUsageEvent(
+ {String label, @required int exitCode, @required List<String> args})
+ : super(migrateCmdName, migrateCmdName,
+ label: label, exitCode: exitCode, args: args);
+}
+
+/// The superclass for all dartdev events, see the [send] method to see what is
+/// sent to analytics.
+abstract class UsageEvent {
+ /// The category stores the name of this cli tool, 'dartdev'. This matches the
+ /// pattern from the flutter cli tool which always passes 'flutter' as the
+ /// category.
+ final String category;
+
+ /// The action is the command, and optionally the subcommand, joined with '/',
+ /// an example here is 'pub/get'. The usagePath getter in each of the
+ final String action;
+
+ /// The command name being executed here, 'analyze' and 'pub' are examples.
+ final String command;
+
+ /// Labels are not used yet used when reporting dartdev analytics, but the API
+ /// is included here for possible future use.
+ final String label;
+
+ /// The [String] list of arguments passed to dartdev, the list of args is not
+ /// passed back via analytics itself, but is used to compute other values such
+ /// as the [enabledExperiments] which are passed back as part of analytics.
+ final List<String> args;
+
+ /// The exit code returned from this invocation of dartdev.
+ final int exitCode;
+
+ /// A comma separated list of enabled experiments passed into the dartdev
+ /// command. If the command doesn't use the experiments, they are not reported
+ /// in the [UsageEvent].
+ final String enabledExperiments;
+
+ /// A comma separated list of flags on this commands
+ final String commandFlags;
+
+ UsageEvent(
+ this.command,
+ this.action, {
+ this.label,
+ List<String> specifiedExperiments,
+ @required this.exitCode,
+ @required this.args,
+ }) : category = _dartdev,
+ enabledExperiments = specifiedExperiments?.join(_flagSeparator),
+ commandFlags = ArgParserUtils.parseCommandFlags(command, args)
+ .join(_flagSeparator);
+
+ Future send(Analytics analytics) {
+ final Map<String, String> parameters =
+ _useCdKeys(<CustomDimensions, String>{
+ if (exitCode != null)
+ CustomDimensions.commandExitCode: exitCode.toString(),
+ if (enabledExperiments != null)
+ CustomDimensions.enabledExperiments: enabledExperiments,
+ if (commandFlags != null) CustomDimensions.commandFlags: commandFlags,
+ });
+ return analytics.sendEvent(
+ category,
+ action,
+ label: label,
+ parameters: parameters,
+ );
+ }
+}
diff --git a/pkg/dartdev/pubspec.yaml b/pkg/dartdev/pubspec.yaml
index be43698..ecc93eb 100644
--- a/pkg/dartdev/pubspec.yaml
+++ b/pkg/dartdev/pubspec.yaml
@@ -15,6 +15,8 @@
dart2native:
path: ../dart2native
dart_style: any
+ meta:
+ path: ../meta
nnbd_migration:
path: ../nnbd_migration
path: ^1.0.0
diff --git a/pkg/dartdev/test/analytics_test.dart b/pkg/dartdev/test/analytics_test.dart
index 3ce90de..31355df7 100644
--- a/pkg/dartdev/test/analytics_test.dart
+++ b/pkg/dartdev/test/analytics_test.dart
@@ -7,7 +7,6 @@
void main() {
group('DisabledAnalytics', disabledAnalyticsObject);
- group('utils', utils);
}
void disabledAnalyticsObject() {
@@ -19,21 +18,3 @@
expect(diabledAnalytics.firstRun, isFalse);
});
}
-
-void utils() {
- test('getCommandStr', () {
- var commands = <String>['help', 'foo', 'bar', 'baz'];
-
- // base cases
- expect(getCommandStr(['help'], commands), 'help');
- expect(getCommandStr(['bar', 'help'], commands), 'help');
- expect(getCommandStr(['help', 'bar'], commands), 'help');
- expect(getCommandStr(['bar', '-h'], commands), 'help');
- expect(getCommandStr(['bar', '--help'], commands), 'help');
-
- // non-trivial tests
- expect(getCommandStr(['foo'], commands), 'foo');
- expect(getCommandStr(['bar', 'baz'], commands), 'bar');
- expect(getCommandStr(['bazz'], commands), '<unknown>');
- });
-}
diff --git a/pkg/dartdev/test/core_test.dart b/pkg/dartdev/test/core_test.dart
index bc10cb9..0944f88 100644
--- a/pkg/dartdev/test/core_test.dart
+++ b/pkg/dartdev/test/core_test.dart
@@ -5,6 +5,13 @@
import 'dart:convert';
import 'dart:io';
+import 'package:dartdev/src/commands/analyze.dart';
+import 'package:dartdev/src/commands/compile.dart';
+import 'package:dartdev/src/commands/create.dart';
+import 'package:dartdev/src/commands/fix.dart';
+import 'package:dartdev/src/commands/pub.dart';
+import 'package:dartdev/src/commands/run.dart';
+import 'package:dartdev/src/commands/test.dart';
import 'package:dartdev/src/core.dart';
import 'package:path/path.dart' as path;
import 'package:test/test.dart';
@@ -12,10 +19,82 @@
import 'utils.dart';
void main() {
+ group('DartdevCommand', _dartdevCommand);
group('PackageConfig', _packageConfig);
group('Project', _project);
}
+void _dartdevCommand() {
+ void _assertDartdevCommandProperties(
+ DartdevCommand command, String name, String usagePath,
+ [int subcommandCount = 0]) {
+ expect(command, isNotNull);
+ expect(command.name, name);
+ expect(command.description, isNotEmpty);
+ expect(command.project, isNotNull);
+ expect(command.argParser, isNotNull);
+ expect(command.usagePath, usagePath);
+ expect(command.subcommands.length, subcommandCount);
+ }
+
+ test('analyze', () {
+ _assertDartdevCommandProperties(AnalyzeCommand(), 'analyze', 'analyze');
+ });
+
+ test('compile', () {
+ _assertDartdevCommandProperties(CompileCommand(), 'compile', 'compile', 5);
+ });
+
+ test('compile/js', () {
+ _assertDartdevCommandProperties(
+ CompileCommand().subcommands['js'], 'js', 'compile/js');
+ });
+
+ test('compile/jit-snapshot', () {
+ _assertDartdevCommandProperties(
+ CompileCommand().subcommands['jit-snapshot'],
+ 'jit-snapshot',
+ 'compile/jit-snapshot');
+ });
+
+ test('compile/kernel', () {
+ _assertDartdevCommandProperties(
+ CompileCommand().subcommands['kernel'], 'kernel', 'compile/kernel');
+ });
+
+ test('compile/exe', () {
+ _assertDartdevCommandProperties(
+ CompileCommand().subcommands['exe'], 'exe', 'compile/exe');
+ });
+
+ test('compile/aot-snapshot', () {
+ _assertDartdevCommandProperties(
+ CompileCommand().subcommands['aot-snapshot'],
+ 'aot-snapshot',
+ 'compile/aot-snapshot');
+ });
+
+ test('create', () {
+ _assertDartdevCommandProperties(CreateCommand(), 'create', 'create');
+ });
+
+ test('fix', () {
+ _assertDartdevCommandProperties(FixCommand(), 'fix', 'fix');
+ });
+
+ test('pub', () {
+ _assertDartdevCommandProperties(PubCommand(), 'pub', 'pub');
+ });
+
+ test('run', () {
+ _assertDartdevCommandProperties(RunCommand(), 'run', 'run');
+ });
+
+ test('test', () {
+ _assertDartdevCommandProperties(TestCommand(), 'test', 'test');
+ });
+}
+
void _packageConfig() {
test('packages', () {
PackageConfig packageConfig = PackageConfig(jsonDecode(_packageData));
diff --git a/pkg/dartdev/test/events_test.dart b/pkg/dartdev/test/events_test.dart
new file mode 100644
index 0000000..c39e7c4
--- /dev/null
+++ b/pkg/dartdev/test/events_test.dart
@@ -0,0 +1,130 @@
+// Copyright (c) 2020, 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:dartdev/dartdev.dart';
+import 'package:dartdev/src/events.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('ArgParserUtils', _argParserUtils);
+ group('event constant', _constants);
+}
+
+void _argParserUtils() {
+ test('getCommandStr help', () {
+ expect(ArgParserUtils.getCommandStr(['help']), 'help');
+ expect(ArgParserUtils.getCommandStr(['analyze', 'help']), 'help');
+ expect(ArgParserUtils.getCommandStr(['help', 'analyze']), 'help');
+ expect(ArgParserUtils.getCommandStr(['analyze', '-h']), 'help');
+ expect(ArgParserUtils.getCommandStr(['analyze', '--help']), 'help');
+ });
+
+ test('getCommandStr command', () {
+ expect(ArgParserUtils.getCommandStr(['analyze']), 'analyze');
+ expect(ArgParserUtils.getCommandStr(['analyze', 'foo']), 'analyze');
+ expect(ArgParserUtils.getCommandStr(['foo', 'bar']), '<unknown>');
+ expect(ArgParserUtils.getCommandStr([]), '<unknown>');
+ expect(ArgParserUtils.getCommandStr(['']), '<unknown>');
+ });
+
+ test('isHelp false', () {
+ expect(ArgParserUtils.isHelp(null), isFalse);
+ expect(ArgParserUtils.isHelp(''), isFalse);
+ expect(ArgParserUtils.isHelp(' '), isFalse);
+ expect(ArgParserUtils.isHelp('-help'), isFalse);
+ expect(ArgParserUtils.isHelp('--HELP'), isFalse);
+ expect(ArgParserUtils.isHelp('--Help'), isFalse);
+ expect(ArgParserUtils.isHelp('Help'), isFalse);
+ expect(ArgParserUtils.isHelp('HELP'), isFalse);
+ expect(ArgParserUtils.isHelp('foo'), isFalse);
+ });
+
+ test('isHelp true', () {
+ expect(ArgParserUtils.isHelp('help'), isTrue);
+ expect(ArgParserUtils.isHelp('--help'), isTrue);
+ expect(ArgParserUtils.isHelp('-h'), isTrue);
+ });
+
+ test('isFlag false', () {
+ expect(ArgParserUtils.isFlag(null), isFalse);
+ expect(ArgParserUtils.isFlag(''), isFalse);
+ expect(ArgParserUtils.isFlag(' '), isFalse);
+ expect(ArgParserUtils.isFlag('help'), isFalse);
+ expect(ArgParserUtils.isFlag('_flag'), isFalse);
+ });
+
+ test('isFlag true', () {
+ expect(ArgParserUtils.isFlag('-'), isTrue);
+ expect(ArgParserUtils.isFlag('--'), isTrue);
+ expect(ArgParserUtils.isFlag('--flag'), isTrue);
+ expect(ArgParserUtils.isFlag('--help'), isTrue);
+ expect(ArgParserUtils.isFlag('-h'), isTrue);
+ });
+
+ test('parseCommandFlags analyze', () {
+ expect(
+ ArgParserUtils.parseCommandFlags('analyze', [
+ '-g',
+ 'analyze',
+ ]),
+ <String>[]);
+ expect(
+ ArgParserUtils.parseCommandFlags('analyze', [
+ '-g',
+ 'analyze',
+ '--one',
+ '--two',
+ '--three=bar',
+ '-f',
+ '--fatal-infos',
+ '-h',
+ 'five'
+ ]),
+ <String>['--one', '--two', '--three', '-f', '--fatal-infos']);
+ });
+
+ test('parseCommandFlags trivial', () {
+ expect(ArgParserUtils.parseCommandFlags('foo', []), <String>[]);
+ expect(ArgParserUtils.parseCommandFlags('foo', ['']), <String>[]);
+ expect(
+ ArgParserUtils.parseCommandFlags('foo', ['bar', '-flag']), <String>[]);
+ expect(
+ ArgParserUtils.parseCommandFlags('foo', ['--global', 'bar', '-flag']),
+ <String>[]);
+ expect(ArgParserUtils.parseCommandFlags('foo', ['--global', 'fo', '-flag']),
+ <String>[]);
+ expect(
+ ArgParserUtils.parseCommandFlags('foo', ['--global', 'FOO', '-flag']),
+ <String>[]);
+ });
+
+ test('parseCommandFlags exclude help', () {
+ expect(
+ ArgParserUtils.parseCommandFlags(
+ 'analyze', ['-g', 'analyze', '--flag', '--help']),
+ <String>['--flag']);
+ expect(
+ ArgParserUtils.parseCommandFlags(
+ 'analyze', ['-g', 'analyze', '--flag', '-h']),
+ <String>['--flag']);
+ expect(
+ ArgParserUtils.parseCommandFlags(
+ 'analyze', ['-g', 'analyze', '--flag', 'help']),
+ <String>['--flag']);
+ });
+
+ test('sanitizeFlag', () {
+ expect(ArgParserUtils.sanitizeFlag(null), '');
+ expect(ArgParserUtils.sanitizeFlag(''), '');
+ expect(ArgParserUtils.sanitizeFlag('foo'), '');
+ expect(ArgParserUtils.sanitizeFlag('--foo'), '--foo');
+ expect(ArgParserUtils.sanitizeFlag('--foo=bar'), '--foo');
+ });
+}
+
+void _constants() {
+ test('allCommands', () {
+ expect(allCommands, DartdevRunner([]).commands.keys.toList());
+ });
+}
diff --git a/pkg/dartdev/test/test_all.dart b/pkg/dartdev/test/test_all.dart
index a3b6db4..ca092a4 100644
--- a/pkg/dartdev/test/test_all.dart
+++ b/pkg/dartdev/test/test_all.dart
@@ -17,6 +17,7 @@
import 'commands/run_test.dart' as run;
import 'commands/test_test.dart' as test;
import 'core_test.dart' as core;
+import 'events_test.dart' as events;
import 'experiments_test.dart' as experiments;
import 'sdk_test.dart' as sdk;
import 'utils_test.dart' as utils;
@@ -26,6 +27,7 @@
analytics.main();
analyze.main();
create.main();
+ events.main();
experiments.main();
fix.main();
flag.main();
diff --git a/pkg/dds/lib/dds.dart b/pkg/dds/lib/dds.dart
index aeb39a9..f35e4d3 100644
--- a/pkg/dds/lib/dds.dart
+++ b/pkg/dds/lib/dds.dart
@@ -114,7 +114,7 @@
/// Stop accepting requests after gracefully handling existing requests.
Future<void> shutdown();
- /// Set to `true` if this isntance of [DartDevelopmentService] requires an
+ /// Set to `true` if this instance of [DartDevelopmentService] requires an
/// authentication code to connect.
bool get authCodesEnabled;
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 96575f1..284c144 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -2558,7 +2558,9 @@
typeArgument.nullability == Nullability.legacy;
var nullability = nullable
? Nullability.nullable
- : legacy ? Nullability.legacy : Nullability.nonNullable;
+ : legacy
+ ? Nullability.legacy
+ : Nullability.nonNullable;
return _emitInterfaceType(
typeArgument.withDeclaredNullability(nullability));
} else if (typeArgument is NeverType) {
diff --git a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
index 7baad48..81776ac 100644
--- a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
+++ b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
@@ -191,7 +191,9 @@
Expression getInvocationReceiver(InvocationExpression node) =>
node is MethodInvocation
? node.receiver
- : node is DirectMethodInvocation ? node.receiver : null;
+ : node is DirectMethodInvocation
+ ? node.receiver
+ : null;
bool isInlineJS(Member e) =>
e is Procedure &&
diff --git a/pkg/dev_compiler/lib/src/kernel/type_table.dart b/pkg/dev_compiler/lib/src/kernel/type_table.dart
index 2d6b5cf..8421a66 100644
--- a/pkg/dev_compiler/lib/src/kernel/type_table.dart
+++ b/pkg/dev_compiler/lib/src/kernel/type_table.dart
@@ -74,7 +74,9 @@
String _typeString(DartType type, {bool flat = false}) {
var nullability = type.declaredNullability == Nullability.legacy
? 'L'
- : type.declaredNullability == Nullability.nullable ? 'N' : '';
+ : type.declaredNullability == Nullability.nullable
+ ? 'N'
+ : '';
assert(isKnownDartTypeImplementor(type));
if (type is InterfaceType) {
var name = '${type.classNode.name}$nullability';
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_test.dart
index 18fa6ce..25474d0 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_test.dart
@@ -19,21 +19,23 @@
bool get verbose => false;
class ModuleConfiguration {
- final String outputPath;
- final String moduleName;
+ final Uri root;
+ final String outputDir;
final String libraryUri;
+ final String moduleName;
final String jsFileName;
final String fullDillFileName;
ModuleConfiguration(
- {this.outputPath,
+ {this.root,
+ this.outputDir,
this.moduleName,
this.libraryUri,
this.jsFileName,
this.fullDillFileName});
- String get jsPath => p.join(outputPath, jsFileName);
- String get fullDillPath => p.join(outputPath, fullDillFileName);
+ Uri get jsPath => root.resolve('$outputDir/$jsFileName');
+ Uri get fullDillPath => root.resolve('$outputDir/$fullDillFileName');
}
class TestProjectConfiguration {
@@ -43,36 +45,40 @@
TestProjectConfiguration(this.rootDirectory);
ModuleConfiguration get mainModule => ModuleConfiguration(
- outputPath: outputPath,
+ root: root,
+ outputDir: outputDir,
moduleName: 'packages/_testPackage/main',
libraryUri: 'org-dartlang-app:/lib/main.dart',
jsFileName: 'main.js',
fullDillFileName: 'main.full.dill');
ModuleConfiguration get testModule => ModuleConfiguration(
- outputPath: outputPath,
+ root: root,
+ outputDir: outputDir,
moduleName: 'packages/_testPackage/test_library',
libraryUri: 'package:_testPackage/test_library.dart',
jsFileName: 'test_library.js',
fullDillFileName: 'test_library.full.dill');
ModuleConfiguration get testModule2 => ModuleConfiguration(
- outputPath: outputPath,
+ root: root,
+ outputDir: outputDir,
moduleName: 'packages/_testPackage/test_library2',
libraryUri: 'package:_testPackage/test_library2.dart',
jsFileName: 'test_library2.js',
fullDillFileName: 'test_library2.full.dill');
- String get root => rootDirectory.path;
- String get outputPath => p.join(root, outputDir);
- String get packagesPath => p.join(root, '.packages');
+ String get rootPath => rootDirectory.path;
+ Uri get root => rootDirectory.uri;
+ Uri get outputPath => root.resolve(outputDir);
+ Uri get packagesPath => root.resolve('.packages');
- String get sdkRoot => computePlatformBinariesLocation().path;
- String get sdkSummaryPath => p.join(sdkRoot, 'ddc_sdk.dill');
- String get librariesPath => p.join(sdkRoot, 'lib', 'libraries.json');
+ Uri get sdkRoot => computePlatformBinariesLocation();
+ Uri get sdkSummaryPath => sdkRoot.resolve('ddc_sdk.dill');
+ Uri get librariesPath => sdkRoot.resolve('lib/libraries.json');
void createTestProject() {
- var pubspec = rootDirectory.uri.resolve('pubspec.yaml');
+ var pubspec = root.resolve('pubspec.yaml');
File.fromUri(pubspec)
..createSync()
..writeAsStringSync('''
@@ -83,14 +89,14 @@
sdk: '>=2.8.0 <3.0.0'
''');
- var packages = rootDirectory.uri.resolve('.packages');
+ var packages = root.resolve('.packages');
File.fromUri(packages)
..createSync()
..writeAsStringSync('''
_testPackage:lib/
''');
- var main = rootDirectory.uri.resolve('lib/main.dart');
+ var main = root.resolve('lib/main.dart');
File.fromUri(main)
..createSync(recursive: true)
..writeAsStringSync('''
@@ -108,7 +114,7 @@
}
''');
- var testLibrary = rootDirectory.uri.resolve('lib/test_library.dart');
+ var testLibrary = root.resolve('lib/test_library.dart');
File.fromUri(testLibrary)
..createSync()
..writeAsStringSync('''
@@ -127,7 +133,7 @@
}
''');
- var testLibrary2 = rootDirectory.uri.resolve('lib/test_library2.dart');
+ var testLibrary2 = root.resolve('lib/test_library2.dart');
File.fromUri(testLibrary2)
..createSync()
..writeAsStringSync('''
@@ -163,15 +169,15 @@
inputs = [
{
- 'path': config.mainModule.fullDillPath,
+ 'path': config.mainModule.fullDillPath.path,
'moduleName': config.mainModule.moduleName
},
{
- 'path': config.testModule.fullDillPath,
+ 'path': config.testModule.fullDillPath.path,
'moduleName': config.testModule.moduleName
},
{
- 'path': config.testModule2.fullDillPath,
+ 'path': config.testModule2.fullDillPath.path,
'moduleName': config.testModule2.moduleName
},
];
@@ -188,12 +194,13 @@
requestController = StreamController<Map<String, dynamic>>();
responseController = StreamController<Map<String, dynamic>>();
worker = await ExpressionCompilerWorker.create(
- librariesSpecificationUri: Uri.file(config.librariesPath),
+ librariesSpecificationUri: config.librariesPath,
// We should be able to load everything from dill and not require
- // source parsing. Webdev and google3 integration currently rely on that.
- // Make the test fail on source reading by not providing a packages.
+ // source parsing. Webdev and google3 integration currently rely on
+ // that. Make the test fail on source reading by not providing a
+ // packages file.
packagesFile: null,
- sdkSummary: Uri.file(config.sdkSummaryPath),
+ sdkSummary: config.sdkSummaryPath,
fileSystem: fileSystem,
requestStream: requestController.stream,
sendResponse: responseController.add,
@@ -360,7 +367,7 @@
inputs = [
{
- 'path': config.mainModule.fullDillPath,
+ 'path': config.mainModule.fullDillPath.path,
'moduleName': config.mainModule.moduleName
},
];
@@ -377,9 +384,9 @@
requestController = StreamController<Map<String, dynamic>>();
responseController = StreamController<Map<String, dynamic>>();
worker = await ExpressionCompilerWorker.create(
- librariesSpecificationUri: Uri.file(config.librariesPath),
+ librariesSpecificationUri: config.librariesPath,
packagesFile: null,
- sdkSummary: Uri.file(config.sdkSummaryPath),
+ sdkSummary: config.sdkSummaryPath,
fileSystem: fileSystem,
requestStream: requestController.stream,
sendResponse: responseController.add,
@@ -505,7 +512,7 @@
var dartdevc =
p.join(p.dirname(dart), 'snapshots', 'dartdevc.dart.snapshot');
- Directory(config.outputPath)..createSync();
+ Directory.fromUri(config.outputPath)..createSync();
// generate test_library2.full.dill
var args = [
@@ -513,21 +520,21 @@
config.testModule2.libraryUri,
'--no-summarize',
'-o',
- config.testModule2.jsPath,
+ config.testModule2.jsPath.toFilePath(),
'--source-map',
'--experimental-emit-debug-metadata',
'--experimental-output-compiled-kernel',
'--dart-sdk-summary',
- config.sdkSummaryPath,
+ config.sdkSummaryPath.path,
'--multi-root',
- config.root,
+ '${config.root}',
'--multi-root-scheme',
'org-dartlang-app',
'--packages',
- config.packagesPath,
+ config.packagesPath.path,
];
- var exitCode = await runProcess(dart, args, config.root);
+ var exitCode = await runProcess(dart, args, config.rootPath);
if (exitCode != 0) {
return exitCode;
}
@@ -540,21 +547,21 @@
'--summary',
'${config.testModule2.fullDillPath}=${config.testModule2.moduleName}',
'-o',
- config.testModule.jsPath,
+ config.testModule.jsPath.toFilePath(),
'--source-map',
'--experimental-emit-debug-metadata',
'--experimental-output-compiled-kernel',
'--dart-sdk-summary',
- config.sdkSummaryPath,
+ config.sdkSummaryPath.path,
'--multi-root',
- config.root,
+ '${config.root}',
'--multi-root-scheme',
'org-dartlang-app',
'--packages',
- config.packagesPath,
+ config.packagesPath.path,
];
- exitCode = await runProcess(dart, args, config.root);
+ exitCode = await runProcess(dart, args, config.rootPath);
if (exitCode != 0) {
return exitCode;
}
@@ -569,21 +576,21 @@
'--summary',
'${config.testModule.fullDillPath}=${config.testModule.moduleName}',
'-o',
- config.mainModule.jsPath,
+ config.mainModule.jsPath.toFilePath(),
'--source-map',
'--experimental-emit-debug-metadata',
'--experimental-output-compiled-kernel',
'--dart-sdk-summary',
- config.sdkSummaryPath,
+ config.sdkSummaryPath.path,
'--multi-root',
- config.root,
+ '${config.root}',
'--multi-root-scheme',
'org-dartlang-app',
'--packages',
- config.packagesPath,
+ config.packagesPath.path,
];
- return await runProcess(dart, args, config.root);
+ return await runProcess(dart, args, config.rootPath);
}
}
@@ -605,9 +612,9 @@
'--target',
'ddc',
'--output',
- config.mainModule.fullDillPath,
+ config.mainModule.fullDillPath.path,
'--dart-sdk-summary',
- config.sdkSummaryPath,
+ config.sdkSummaryPath.path,
'--exclude-non-sources',
'--source',
config.mainModule.libraryUri,
@@ -616,7 +623,7 @@
'--source',
config.testModule2.libraryUri,
'--multi-root',
- config.root,
+ '${config.root}',
'--multi-root-scheme',
'org-dartlang-app',
'--packages-file',
@@ -624,7 +631,7 @@
'--verbose'
];
- return await runProcess(dart, args, config.root);
+ return await runProcess(dart, args, config.rootPath);
}
}
diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md
index 466d85f..049e01d1 100644
--- a/pkg/vm_service/CHANGELOG.md
+++ b/pkg/vm_service/CHANGELOG.md
@@ -2,7 +2,7 @@
## 5.0.0
-- **breaking**: Update to version `4.0.0` of the spec.
+- **breaking**: Update to version `3.39.0` of the spec.
- Removes `ClientName` and `WebSocketTarget` objects
- Removes `getClientName`, `getWebSocketTarget`, `requirePermissionToResume`,
and `setClientName` RPCs.
diff --git a/pkg/vm_service/example/sample_isolates.dart b/pkg/vm_service/example/sample_isolates.dart
index 3dd216b..e57fd09 100644
--- a/pkg/vm_service/example/sample_isolates.dart
+++ b/pkg/vm_service/example/sample_isolates.dart
@@ -2,7 +2,6 @@
// 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 'dart:async';
import 'dart:isolate';
main(List<String> args) async {
diff --git a/pkg/vm_service/java/src/org/dartlang/vm/service/VmServiceBase.java b/pkg/vm_service/java/src/org/dartlang/vm/service/VmServiceBase.java
index c44b31d..207cdc5 100644
--- a/pkg/vm_service/java/src/org/dartlang/vm/service/VmServiceBase.java
+++ b/pkg/vm_service/java/src/org/dartlang/vm/service/VmServiceBase.java
@@ -132,21 +132,6 @@
@Override
public void received(Version version) {
- int major = version.getMajor();
- int minor = version.getMinor();
- if (major != VmService.versionMajor || minor != VmService.versionMinor) {
- if (major == 2 || major == 3) {
- Logging.getLogger().logInformation(
- "Difference in protocol version: client=" + VmService.versionMajor + "."
- + VmService.versionMinor + " vm=" + major + "." + minor);
- } else {
- String msg = "Incompatible protocol version: client=" + VmService.versionMajor + "."
- + VmService.versionMinor + " vm=" + major + "." + minor;
- Logging.getLogger().logError(msg);
- errMsg[0] = msg;
- }
- }
-
vmService.runtimeVersion = version;
latch.countDown();
diff --git a/pkg/vm_service/java/version.properties b/pkg/vm_service/java/version.properties
index db1ef8e5..e076127 100644
--- a/pkg/vm_service/java/version.properties
+++ b/pkg/vm_service/java/version.properties
@@ -1 +1 @@
-version=4.0
+version=3.39
diff --git a/pkg/vm_service/lib/src/dart_io_extensions.dart b/pkg/vm_service/lib/src/dart_io_extensions.dart
index ef89c64..4297e45 100644
--- a/pkg/vm_service/lib/src/dart_io_extensions.dart
+++ b/pkg/vm_service/lib/src/dart_io_extensions.dart
@@ -4,8 +4,6 @@
// TODO(bkonyi): autogenerate from service_extensions.md
-import 'dart:async';
-
import 'package:meta/meta.dart';
import 'vm_service.dart';
diff --git a/pkg/vm_service/lib/src/vm_service.dart b/pkg/vm_service/lib/src/vm_service.dart
index c518b25..4f63e01 100644
--- a/pkg/vm_service/lib/src/vm_service.dart
+++ b/pkg/vm_service/lib/src/vm_service.dart
@@ -28,7 +28,7 @@
HeapSnapshotObjectNoData,
HeapSnapshotObjectNullData;
-const String vmServiceVersion = '4.0.0';
+const String vmServiceVersion = '3.39.0';
/// @optional
const String optional = 'optional';
diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml
index fff9595..66b2910 100644
--- a/pkg/vm_service/pubspec.yaml
+++ b/pkg/vm_service/pubspec.yaml
@@ -2,7 +2,7 @@
description: >-
A library to communicate with a service implementing the Dart VM
service protocol.
-version: 5.0.0
+version: 5.0.0+1
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service
diff --git a/pkg/vm_service/test/async_generator_breakpoint_test.dart b/pkg/vm_service/test/async_generator_breakpoint_test.dart
index 3cf2655..e709594 100644
--- a/pkg/vm_service/test/async_generator_breakpoint_test.dart
+++ b/pkg/vm_service/test/async_generator_breakpoint_test.dart
@@ -2,7 +2,6 @@
// 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 'dart:async';
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';
import 'common/test_helper.dart';
diff --git a/pkg/vm_service/test/async_scope_test.dart b/pkg/vm_service/test/async_scope_test.dart
index 80813b6..9573e69 100644
--- a/pkg/vm_service/test/async_scope_test.dart
+++ b/pkg/vm_service/test/async_scope_test.dart
@@ -2,15 +2,14 @@
// 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 'dart:async';
import 'dart:developer';
import 'package:vm_service/vm_service.dart';
import 'package:test/test.dart';
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
-const int LINE_A = 20;
-const int LINE_B = 26;
+const int LINE_A = 19;
+const int LINE_B = 25;
foo() {}
diff --git a/pkg/vm_service/test/evaluate_with_scope_test.dart b/pkg/vm_service/test/evaluate_with_scope_test.dart
index 38588d8..8dfd4d4 100644
--- a/pkg/vm_service/test/evaluate_with_scope_test.dart
+++ b/pkg/vm_service/test/evaluate_with_scope_test.dart
@@ -2,8 +2,6 @@
// 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 'dart:async';
-
import 'package:vm_service/vm_service.dart';
import 'package:test/test.dart';
import 'common/test_helper.dart';
diff --git a/pkg/vm_service/test/get_allocation_profile_rpc_test.dart b/pkg/vm_service/test/get_allocation_profile_rpc_test.dart
index 0a35d093..c4540e5 100644
--- a/pkg/vm_service/test/get_allocation_profile_rpc_test.dart
+++ b/pkg/vm_service/test/get_allocation_profile_rpc_test.dart
@@ -2,7 +2,6 @@
// 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 'dart:async';
import 'package:vm_service/vm_service.dart';
import 'package:test/test.dart';
diff --git a/pkg/vm_service/test/get_cpu_samples_rpc_test.dart b/pkg/vm_service/test/get_cpu_samples_rpc_test.dart
index de49353..8b9b143 100644
--- a/pkg/vm_service/test/get_cpu_samples_rpc_test.dart
+++ b/pkg/vm_service/test/get_cpu_samples_rpc_test.dart
@@ -2,8 +2,6 @@
// 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 'dart:async';
-
import 'package:vm_service/vm_service.dart';
import 'package:test/test.dart';
diff --git a/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart b/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart
index 418b823..0b849c6 100644
--- a/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart
+++ b/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart
@@ -2,7 +2,6 @@
// 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 'dart:async';
import 'package:vm_service/vm_service.dart';
import 'package:vm_service/src/dart_io_extensions.dart';
import 'package:test/test.dart';
diff --git a/runtime/observatory/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart
index 7ee46a0..8e949ec 100644
--- a/runtime/observatory/tests/service/get_version_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_version_rpc_test.dart
@@ -11,8 +11,8 @@
(VM vm) async {
var result = await vm.invokeRpcNoUpgrade('getVersion', {});
expect(result['type'], equals('Version'));
- expect(result['major'], equals(4));
- expect(result['minor'], equals(0));
+ expect(result['major'], equals(3));
+ expect(result['minor'], equals(39));
expect(result['_privateMajor'], equals(0));
expect(result['_privateMinor'], equals(0));
},
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index f33a41c..9c7eabc 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -2290,13 +2290,6 @@
return true;
}
-bool FlowGraphCompiler::ShouldUseTypeTestingStubFor(bool optimizing,
- const AbstractType& type) {
- return FLAG_precompiled_mode ||
- (optimizing &&
- (type.IsTypeParameter() || (type.IsType() && type.IsInstantiated())));
-}
-
FlowGraphCompiler::TypeTestStubKind
FlowGraphCompiler::GetTypeTestStubKindForTypeParameter(
const TypeParameter& type_param) {
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index 47e9530..9b1764e 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -568,11 +568,6 @@
const String& dst_name,
LocationSummary* locs);
- // Returns true if we can use a type testing stub based assert
- // assignable code pattern for the given type.
- static bool ShouldUseTypeTestingStubFor(bool optimizing,
- const AbstractType& type);
-
void GenerateAssertAssignableViaTypeTestingStub(CompileType* receiver_type,
TokenPosition token_pos,
intptr_t deopt_id,
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
index bfc9b81..465352b 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
@@ -703,67 +703,19 @@
ASSERT(!token_pos.IsClassifying());
ASSERT(CheckAssertAssignableTypeTestingABILocations(*locs));
- compiler::Label is_assignable_fast, is_assignable, runtime_call;
-
- // Generate inline type check, linking to runtime call if not assignable.
- SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone());
- static_assert(
- TypeTestABI::kFunctionTypeArgumentsReg <
- TypeTestABI::kInstantiatorTypeArgumentsReg,
- "Should be ordered to push and load arguments with one instruction");
- static RegList type_args = (1 << TypeTestABI::kFunctionTypeArgumentsReg) |
- (1 << TypeTestABI::kInstantiatorTypeArgumentsReg);
-
if (locs->in(1).IsConstant()) {
const auto& dst_type = AbstractType::Cast(locs->in(1).constant());
ASSERT(dst_type.IsFinalized());
if (dst_type.IsTopTypeForSubtyping()) return; // No code needed.
- if (ShouldUseTypeTestingStubFor(is_optimizing(), dst_type)) {
- GenerateAssertAssignableViaTypeTestingStub(receiver_type, token_pos,
- deopt_id, dst_name, locs);
- return;
- }
-
- if (Instance::NullIsAssignableTo(dst_type)) {
- __ CompareObject(TypeTestABI::kInstanceReg, Object::null_object());
- __ b(&is_assignable_fast, EQ);
- }
-
- __ PushList(type_args);
-
- test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable,
- &runtime_call);
+ GenerateAssertAssignableViaTypeTestingStub(receiver_type, token_pos,
+ deopt_id, dst_name, locs);
+ return;
} else {
// TODO(dartbug.com/40813): Handle setting up the non-constant case.
UNREACHABLE();
}
-
- __ Bind(&runtime_call);
- __ ldm(IA, SP, type_args);
- __ PushObject(Object::null_object()); // Make room for the result.
- __ Push(TypeTestABI::kInstanceReg); // Push the source object.
- // Push the type of the destination.
- if (locs->in(1).IsConstant()) {
- __ PushObject(locs->in(1).constant());
- } else {
- // TODO(dartbug.com/40813): Handle setting up the non-constant case.
- UNREACHABLE();
- }
- __ PushList(type_args);
- __ PushObject(dst_name); // Push the name of the destination.
- __ LoadUniqueObject(R0, test_cache);
- __ Push(R0);
- __ PushImmediate(Smi::RawValue(kTypeCheckFromInline));
- GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 7, locs);
- // Pop the parameters supplied to the runtime entry. The result of the
- // type check runtime call is the checked value.
- __ Drop(7);
- __ Pop(TypeTestABI::kInstanceReg);
- __ Bind(&is_assignable);
- __ PopList(type_args);
- __ Bind(&is_assignable_fast);
}
void FlowGraphCompiler::GenerateAssertAssignableViaTypeTestingStub(
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
index b235c33..bc6983e 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
@@ -669,67 +669,19 @@
ASSERT(!TokenPosition(token_pos).IsClassifying());
ASSERT(CheckAssertAssignableTypeTestingABILocations(*locs));
- compiler::Label is_assignable_fast, is_assignable, runtime_call;
- // Generate inline type check, linking to runtime call if not assignable.
- SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone());
-
if (locs->in(1).IsConstant()) {
const auto& dst_type = AbstractType::Cast(locs->in(1).constant());
ASSERT(dst_type.IsFinalized());
if (dst_type.IsTopTypeForSubtyping()) return; // No code needed.
- if (ShouldUseTypeTestingStubFor(is_optimizing(), dst_type)) {
- GenerateAssertAssignableViaTypeTestingStub(receiver_type, token_pos,
- deopt_id, dst_name, locs);
- return;
- }
-
- if (Instance::NullIsAssignableTo(dst_type)) {
- __ CompareObject(TypeTestABI::kInstanceReg, Object::null_object());
- __ b(&is_assignable_fast, EQ);
- }
-
- __ PushPair(TypeTestABI::kFunctionTypeArgumentsReg,
- TypeTestABI::kInstantiatorTypeArgumentsReg);
-
- test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable,
- &runtime_call);
+ GenerateAssertAssignableViaTypeTestingStub(receiver_type, token_pos,
+ deopt_id, dst_name, locs);
+ return;
} else {
// TODO(dartbug.com/40813): Handle setting up the non-constant case.
UNREACHABLE();
}
-
- __ Bind(&runtime_call);
- __ ldp(TypeTestABI::kFunctionTypeArgumentsReg,
- TypeTestABI::kInstantiatorTypeArgumentsReg,
- compiler::Address(SP, 0 * kWordSize, compiler::Address::PairOffset));
- // Make room for the result and push the source object.
- __ PushPair(TypeTestABI::kInstanceReg, NULL_REG);
- // Push the destination type and the instantiator type arguments.
- if (locs->in(1).IsConstant()) {
- __ LoadObject(TMP, locs->in(1).constant());
- __ PushPair(TypeTestABI::kInstantiatorTypeArgumentsReg, TMP);
- } else {
- // TODO(dartbug.com/40813): Handle setting up the non-constant case.
- UNREACHABLE();
- }
- // Push the function type arguments and the name of the destination.
- __ LoadObject(TMP, dst_name);
- __ PushPair(TMP, TypeTestABI::kFunctionTypeArgumentsReg);
-
- __ LoadUniqueObject(R0, test_cache);
- __ LoadObject(TMP, Smi::ZoneHandle(zone(), Smi::New(kTypeCheckFromInline)));
- __ PushPair(TMP, R0);
- GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 7, locs);
- // Pop the parameters supplied to the runtime entry. The result of the
- // type check runtime call is the checked value.
- __ Drop(7);
- __ Pop(TypeTestABI::kInstanceReg);
- __ Bind(&is_assignable);
- __ PopPair(TypeTestABI::kFunctionTypeArgumentsReg,
- TypeTestABI::kInstantiatorTypeArgumentsReg);
- __ Bind(&is_assignable_fast);
}
void FlowGraphCompiler::GenerateAssertAssignableViaTypeTestingStub(
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
index 4b4e217..3f867c5 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
@@ -684,59 +684,19 @@
ASSERT(!token_pos.IsClassifying());
ASSERT(CheckAssertAssignableTypeTestingABILocations(*locs));
- compiler::Label is_assignable, runtime_call;
-
- // Generate inline type check, linking to runtime call if not assignable.
- SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone());
-
if (locs->in(1).IsConstant()) {
const auto& dst_type = AbstractType::Cast(locs->in(1).constant());
ASSERT(dst_type.IsFinalized());
if (dst_type.IsTopTypeForSubtyping()) return; // No code needed.
- if (ShouldUseTypeTestingStubFor(is_optimizing(), dst_type)) {
- GenerateAssertAssignableViaTypeTestingStub(receiver_type, token_pos,
- deopt_id, dst_name, locs);
- return;
- }
-
- if (Instance::NullIsAssignableTo(dst_type)) {
- __ CompareObject(TypeTestABI::kInstanceReg, Object::null_object());
- __ j(EQUAL, &is_assignable);
- }
-
- // The registers RAX, RCX, RDX are preserved across the call.
- test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable,
- &runtime_call);
-
+ GenerateAssertAssignableViaTypeTestingStub(receiver_type, token_pos,
+ deopt_id, dst_name, locs);
+ return;
} else {
// TODO(dartbug.com/40813): Handle setting up the non-constant case.
UNREACHABLE();
}
-
- __ Bind(&runtime_call);
- __ PushObject(Object::null_object()); // Make room for the result.
- __ pushq(TypeTestABI::kInstanceReg); // Push the source object.
- // Push the destination type.
- if (locs->in(1).IsConstant()) {
- __ PushObject(locs->in(1).constant());
- } else {
- // TODO(dartbug.com/40813): Handle setting up the non-constant case.
- UNREACHABLE();
- }
- __ pushq(TypeTestABI::kInstantiatorTypeArgumentsReg);
- __ pushq(TypeTestABI::kFunctionTypeArgumentsReg);
- __ PushObject(dst_name); // Push the name of the destination.
- __ LoadUniqueObject(RAX, test_cache);
- __ pushq(RAX);
- __ PushImmediate(compiler::Immediate(Smi::RawValue(kTypeCheckFromInline)));
- GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 7, locs);
- // Pop the parameters supplied to the runtime entry. The result of the
- // type check runtime call is the checked value.
- __ Drop(7);
- __ popq(TypeTestABI::kInstanceReg);
- __ Bind(&is_assignable);
}
void FlowGraphCompiler::GenerateAssertAssignableViaTypeTestingStub(
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index df51c7d..8aec81f 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -759,15 +759,12 @@
auto const dst_type_loc =
LocationFixedRegisterOrConstant(dst_type(), TypeTestABI::kDstTypeReg);
- // When using a type testing stub, we want to prevent spilling of the
- // function/instantiator type argument vectors, since stub preserves them. So
- // we make this a `kNoCall` summary, even though most other registers can be
- // modified by the stub. To tell the register allocator about it, we reserve
- // all the other registers as temporary registers.
+ // We want to prevent spilling of the inputs (e.g. function/instantiator tav),
+ // since TTS preserves them. So we make this a `kNoCall` summary,
+ // even though most other registers can be modified by the stub. To tell the
+ // register allocator about it, we reserve all the other registers as
+ // temporary registers.
// TODO(http://dartbug.com/32788): Simplify this.
- const bool using_stub = dst_type_loc.IsConstant() &&
- FlowGraphCompiler::ShouldUseTypeTestingStubFor(
- opt, AbstractType::Cast(dst_type_loc.constant()));
const intptr_t kNonChangeableInputRegs =
(1 << TypeTestABI::kInstanceReg) |
@@ -789,14 +786,11 @@
<< kAbiFirstPreservedFpuReg) &
~(1 << FpuTMP);
- const intptr_t kNumTemps =
- using_stub ? (Utils::CountOneBits64(kCpuRegistersToPreserve) +
- Utils::CountOneBits64(kFpuRegistersToPreserve))
- : 0;
+ const intptr_t kNumTemps = (Utils::CountOneBits64(kCpuRegistersToPreserve) +
+ Utils::CountOneBits64(kFpuRegistersToPreserve));
LocationSummary* summary = new (zone) LocationSummary(
- zone, kNumInputs, kNumTemps,
- using_stub ? LocationSummary::kCallCalleeSafe : LocationSummary::kCall);
+ zone, kNumInputs, kNumTemps, LocationSummary::kCallCalleeSafe);
summary->set_in(0, Location::RegisterLocation(TypeTestABI::kInstanceReg));
summary->set_in(1, dst_type_loc);
summary->set_in(2, Location::RegisterLocation(
@@ -805,23 +799,21 @@
3, Location::RegisterLocation(TypeTestABI::kFunctionTypeArgumentsReg));
summary->set_out(0, Location::SameAsFirstInput());
- if (using_stub) {
- // Let's reserve all registers except for the input ones.
- intptr_t next_temp = 0;
- for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
- const bool should_preserve = ((1 << i) & kCpuRegistersToPreserve) != 0;
- if (should_preserve) {
- summary->set_temp(next_temp++,
- Location::RegisterLocation(static_cast<Register>(i)));
- }
+ // Let's reserve all registers except for the input ones.
+ intptr_t next_temp = 0;
+ for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
+ const bool should_preserve = ((1 << i) & kCpuRegistersToPreserve) != 0;
+ if (should_preserve) {
+ summary->set_temp(next_temp++,
+ Location::RegisterLocation(static_cast<Register>(i)));
}
+ }
- for (intptr_t i = 0; i < kNumberOfFpuRegisters; i++) {
- const bool should_preserve = ((1 << i) & kFpuRegistersToPreserve) != 0;
- if (should_preserve) {
- summary->set_temp(next_temp++, Location::FpuRegisterLocation(
- static_cast<FpuRegister>(i)));
- }
+ for (intptr_t i = 0; i < kNumberOfFpuRegisters; i++) {
+ const bool should_preserve = ((1 << i) & kFpuRegistersToPreserve) != 0;
+ if (should_preserve) {
+ summary->set_temp(next_temp++, Location::FpuRegisterLocation(
+ static_cast<FpuRegister>(i)));
}
}
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index c0ec0b2..563bbe7 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -658,15 +658,12 @@
auto const dst_type_loc =
LocationFixedRegisterOrConstant(dst_type(), TypeTestABI::kDstTypeReg);
- // When using a type testing stub, we want to prevent spilling of the
- // function/instantiator type argument vectors, since stub preserves them. So
- // we make this a `kNoCall` summary, even though most other registers can be
- // modified by the stub. To tell the register allocator about it, we reserve
- // all the other registers as temporary registers.
+ // We want to prevent spilling of the inputs (e.g. function/instantiator tav),
+ // since TTS preserves them. So we make this a `kNoCall` summary,
+ // even though most other registers can be modified by the stub. To tell the
+ // register allocator about it, we reserve all the other registers as
+ // temporary registers.
// TODO(http://dartbug.com/32788): Simplify this.
- const bool using_stub = dst_type_loc.IsConstant() &&
- FlowGraphCompiler::ShouldUseTypeTestingStubFor(
- opt, AbstractType::Cast(dst_type_loc.constant()));
const intptr_t kNonChangeableInputRegs =
(1 << TypeTestABI::kInstanceReg) |
@@ -686,14 +683,11 @@
const intptr_t kFpuRegistersToPreserve =
Utils::SignedNBitMask(kNumberOfFpuRegisters) & ~(1l << FpuTMP);
- const intptr_t kNumTemps =
- using_stub ? (Utils::CountOneBits64(kCpuRegistersToPreserve) +
- Utils::CountOneBits64(kFpuRegistersToPreserve))
- : 0;
+ const intptr_t kNumTemps = (Utils::CountOneBits64(kCpuRegistersToPreserve) +
+ Utils::CountOneBits64(kFpuRegistersToPreserve));
LocationSummary* summary = new (zone) LocationSummary(
- zone, kNumInputs, kNumTemps,
- using_stub ? LocationSummary::kCallCalleeSafe : LocationSummary::kCall);
+ zone, kNumInputs, kNumTemps, LocationSummary::kCallCalleeSafe);
summary->set_in(0, Location::RegisterLocation(TypeTestABI::kInstanceReg));
summary->set_in(1, dst_type_loc);
summary->set_in(2, Location::RegisterLocation(
@@ -702,23 +696,21 @@
3, Location::RegisterLocation(TypeTestABI::kFunctionTypeArgumentsReg));
summary->set_out(0, Location::SameAsFirstInput());
- if (using_stub) {
- // Let's reserve all registers except for the input ones.
- intptr_t next_temp = 0;
- for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
- const bool should_preserve = ((1 << i) & kCpuRegistersToPreserve) != 0;
- if (should_preserve) {
- summary->set_temp(next_temp++,
- Location::RegisterLocation(static_cast<Register>(i)));
- }
+ // Let's reserve all registers except for the input ones.
+ intptr_t next_temp = 0;
+ for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
+ const bool should_preserve = ((1 << i) & kCpuRegistersToPreserve) != 0;
+ if (should_preserve) {
+ summary->set_temp(next_temp++,
+ Location::RegisterLocation(static_cast<Register>(i)));
}
+ }
- for (intptr_t i = 0; i < kNumberOfFpuRegisters; i++) {
- const bool should_preserve = ((1l << i) & kFpuRegistersToPreserve) != 0;
- if (should_preserve) {
- summary->set_temp(next_temp++, Location::FpuRegisterLocation(
- static_cast<FpuRegister>(i)));
- }
+ for (intptr_t i = 0; i < kNumberOfFpuRegisters; i++) {
+ const bool should_preserve = ((1l << i) & kFpuRegistersToPreserve) != 0;
+ if (should_preserve) {
+ summary->set_temp(next_temp++, Location::FpuRegisterLocation(
+ static_cast<FpuRegister>(i)));
}
}
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index e21744e..70f492c 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -594,15 +594,12 @@
auto const dst_type_loc =
LocationFixedRegisterOrConstant(dst_type(), TypeTestABI::kDstTypeReg);
- // When using a type testing stub, we want to prevent spilling of the
- // function/instantiator type argument vectors, since stub preserves them. So
- // we make this a `kNoCall` summary, even though most other registers can be
- // modified by the stub. To tell the register allocator about it, we reserve
- // all the other registers as temporary registers.
+ // We want to prevent spilling of the inputs (e.g. function/instantiator tav),
+ // since TTS preserves them. So we make this a `kNoCall` summary,
+ // even though most other registers can be modified by the stub. To tell the
+ // register allocator about it, we reserve all the other registers as
+ // temporary registers.
// TODO(http://dartbug.com/32788): Simplify this.
- const bool using_stub = dst_type_loc.IsConstant() &&
- FlowGraphCompiler::ShouldUseTypeTestingStubFor(
- opt, AbstractType::Cast(dst_type_loc.constant()));
const intptr_t kNonChangeableInputRegs =
(1 << TypeTestABI::kInstanceReg) |
@@ -621,14 +618,11 @@
const intptr_t kFpuRegistersToPreserve =
CallingConventions::kVolatileXmmRegisters & ~(1 << FpuTMP);
- const intptr_t kNumTemps =
- using_stub ? (Utils::CountOneBits64(kCpuRegistersToPreserve) +
- Utils::CountOneBits64(kFpuRegistersToPreserve))
- : 0;
+ const intptr_t kNumTemps = (Utils::CountOneBits64(kCpuRegistersToPreserve) +
+ Utils::CountOneBits64(kFpuRegistersToPreserve));
LocationSummary* summary = new (zone) LocationSummary(
- zone, kNumInputs, kNumTemps,
- using_stub ? LocationSummary::kCallCalleeSafe : LocationSummary::kCall);
+ zone, kNumInputs, kNumTemps, LocationSummary::kCallCalleeSafe);
summary->set_in(0, Location::RegisterLocation(TypeTestABI::kInstanceReg));
summary->set_in(1, dst_type_loc);
summary->set_in(2, Location::RegisterLocation(
@@ -637,23 +631,21 @@
3, Location::RegisterLocation(TypeTestABI::kFunctionTypeArgumentsReg));
summary->set_out(0, Location::SameAsFirstInput());
- if (using_stub) {
- // Let's reserve all registers except for the input ones.
- intptr_t next_temp = 0;
- for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
- const bool should_preserve = ((1 << i) & kCpuRegistersToPreserve) != 0;
- if (should_preserve) {
- summary->set_temp(next_temp++,
- Location::RegisterLocation(static_cast<Register>(i)));
- }
+ // Let's reserve all registers except for the input ones.
+ intptr_t next_temp = 0;
+ for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
+ const bool should_preserve = ((1 << i) & kCpuRegistersToPreserve) != 0;
+ if (should_preserve) {
+ summary->set_temp(next_temp++,
+ Location::RegisterLocation(static_cast<Register>(i)));
}
+ }
- for (intptr_t i = 0; i < kNumberOfFpuRegisters; i++) {
- const bool should_preserve = ((1 << i) & kFpuRegistersToPreserve) != 0;
- if (should_preserve) {
- summary->set_temp(next_temp++, Location::FpuRegisterLocation(
- static_cast<FpuRegister>(i)));
- }
+ for (intptr_t i = 0; i < kNumberOfFpuRegisters; i++) {
+ const bool should_preserve = ((1 << i) & kFpuRegistersToPreserve) != 0;
+ if (should_preserve) {
+ summary->set_temp(next_temp++, Location::FpuRegisterLocation(
+ static_cast<FpuRegister>(i)));
}
}
diff --git a/runtime/vm/compiler/relocation.cc b/runtime/vm/compiler/relocation.cc
index df7a9dd..d84a679 100644
--- a/runtime/vm/compiler/relocation.cc
+++ b/runtime/vm/compiler/relocation.cc
@@ -434,6 +434,7 @@
// live in the "vm-isolate" - such as `Type::dynamic_type()`).
if (destination_.InVMIsolateHeap()) {
auto object_store = thread_->isolate()->object_store();
+
if (destination_.raw() == StubCode::DefaultTypeTest().raw()) {
destination_ = object_store->default_tts_stub();
} else if (destination_.raw() ==
@@ -445,6 +446,12 @@
destination_ = object_store->unreachable_tts_stub();
} else if (destination_.raw() == StubCode::SlowTypeTest().raw()) {
destination_ = object_store->slow_tts_stub();
+ } else if (destination_.raw() ==
+ StubCode::NullableTypeParameterTypeTest().raw()) {
+ destination_ = object_store->nullable_type_parameter_tts_stub();
+ } else if (destination_.raw() ==
+ StubCode::TypeParameterTypeTest().raw()) {
+ destination_ = object_store->type_parameter_tts_stub();
} else {
UNREACHABLE();
}
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index 31fa267..4d70b77 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -883,6 +883,8 @@
public:
static word InstanceSize();
static word NextFieldOffset();
+ static word parameterized_class_id_offset();
+ static word index_offset();
};
class LibraryPrefix : public AllStatic {
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index d29d7b5..1c8cd1c2fd 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -379,6 +379,9 @@
static constexpr dart::compiler::target::word Type_type_state_offset = 32;
static constexpr dart::compiler::target::word Type_nullability_offset = 33;
static constexpr dart::compiler::target::word
+ TypeParameter_parameterized_class_id_offset = 28;
+static constexpr dart::compiler::target::word TypeParameter_index_offset = 36;
+static constexpr dart::compiler::target::word
TypeArguments_instantiations_offset = 4;
static constexpr dart::compiler::target::word TypeArguments_length_offset = 8;
static constexpr dart::compiler::target::word TypeArguments_nullability_offset =
@@ -887,6 +890,9 @@
static constexpr dart::compiler::target::word Type_type_state_offset = 60;
static constexpr dart::compiler::target::word Type_nullability_offset = 61;
static constexpr dart::compiler::target::word
+ TypeParameter_parameterized_class_id_offset = 56;
+static constexpr dart::compiler::target::word TypeParameter_index_offset = 64;
+static constexpr dart::compiler::target::word
TypeArguments_instantiations_offset = 8;
static constexpr dart::compiler::target::word TypeArguments_length_offset = 16;
static constexpr dart::compiler::target::word TypeArguments_nullability_offset =
@@ -1391,6 +1397,9 @@
static constexpr dart::compiler::target::word Type_type_state_offset = 32;
static constexpr dart::compiler::target::word Type_nullability_offset = 33;
static constexpr dart::compiler::target::word
+ TypeParameter_parameterized_class_id_offset = 28;
+static constexpr dart::compiler::target::word TypeParameter_index_offset = 36;
+static constexpr dart::compiler::target::word
TypeArguments_instantiations_offset = 4;
static constexpr dart::compiler::target::word TypeArguments_length_offset = 8;
static constexpr dart::compiler::target::word TypeArguments_nullability_offset =
@@ -1896,6 +1905,9 @@
static constexpr dart::compiler::target::word Type_type_state_offset = 60;
static constexpr dart::compiler::target::word Type_nullability_offset = 61;
static constexpr dart::compiler::target::word
+ TypeParameter_parameterized_class_id_offset = 56;
+static constexpr dart::compiler::target::word TypeParameter_index_offset = 64;
+static constexpr dart::compiler::target::word
TypeArguments_instantiations_offset = 8;
static constexpr dart::compiler::target::word TypeArguments_length_offset = 16;
static constexpr dart::compiler::target::word TypeArguments_nullability_offset =
@@ -2400,6 +2412,9 @@
static constexpr dart::compiler::target::word Type_type_state_offset = 32;
static constexpr dart::compiler::target::word Type_nullability_offset = 33;
static constexpr dart::compiler::target::word
+ TypeParameter_parameterized_class_id_offset = 28;
+static constexpr dart::compiler::target::word TypeParameter_index_offset = 36;
+static constexpr dart::compiler::target::word
TypeArguments_instantiations_offset = 4;
static constexpr dart::compiler::target::word TypeArguments_length_offset = 8;
static constexpr dart::compiler::target::word TypeArguments_nullability_offset =
@@ -2902,6 +2917,9 @@
static constexpr dart::compiler::target::word Type_type_state_offset = 60;
static constexpr dart::compiler::target::word Type_nullability_offset = 61;
static constexpr dart::compiler::target::word
+ TypeParameter_parameterized_class_id_offset = 56;
+static constexpr dart::compiler::target::word TypeParameter_index_offset = 64;
+static constexpr dart::compiler::target::word
TypeArguments_instantiations_offset = 8;
static constexpr dart::compiler::target::word TypeArguments_length_offset = 16;
static constexpr dart::compiler::target::word TypeArguments_nullability_offset =
@@ -3400,6 +3418,9 @@
static constexpr dart::compiler::target::word Type_type_state_offset = 32;
static constexpr dart::compiler::target::word Type_nullability_offset = 33;
static constexpr dart::compiler::target::word
+ TypeParameter_parameterized_class_id_offset = 28;
+static constexpr dart::compiler::target::word TypeParameter_index_offset = 36;
+static constexpr dart::compiler::target::word
TypeArguments_instantiations_offset = 4;
static constexpr dart::compiler::target::word TypeArguments_length_offset = 8;
static constexpr dart::compiler::target::word TypeArguments_nullability_offset =
@@ -3899,6 +3920,9 @@
static constexpr dart::compiler::target::word Type_type_state_offset = 60;
static constexpr dart::compiler::target::word Type_nullability_offset = 61;
static constexpr dart::compiler::target::word
+ TypeParameter_parameterized_class_id_offset = 56;
+static constexpr dart::compiler::target::word TypeParameter_index_offset = 64;
+static constexpr dart::compiler::target::word
TypeArguments_instantiations_offset = 8;
static constexpr dart::compiler::target::word TypeArguments_length_offset = 16;
static constexpr dart::compiler::target::word TypeArguments_nullability_offset =
@@ -4434,6 +4458,10 @@
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 32;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 33;
static constexpr dart::compiler::target::word
+ AOT_TypeParameter_parameterized_class_id_offset = 28;
+static constexpr dart::compiler::target::word AOT_TypeParameter_index_offset =
+ 36;
+static constexpr dart::compiler::target::word
AOT_TypeArguments_instantiations_offset = 4;
static constexpr dart::compiler::target::word AOT_TypeArguments_length_offset =
8;
@@ -4992,6 +5020,10 @@
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 60;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 61;
static constexpr dart::compiler::target::word
+ AOT_TypeParameter_parameterized_class_id_offset = 56;
+static constexpr dart::compiler::target::word AOT_TypeParameter_index_offset =
+ 64;
+static constexpr dart::compiler::target::word
AOT_TypeArguments_instantiations_offset = 8;
static constexpr dart::compiler::target::word AOT_TypeArguments_length_offset =
16;
@@ -5555,6 +5587,10 @@
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 60;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 61;
static constexpr dart::compiler::target::word
+ AOT_TypeParameter_parameterized_class_id_offset = 56;
+static constexpr dart::compiler::target::word AOT_TypeParameter_index_offset =
+ 64;
+static constexpr dart::compiler::target::word
AOT_TypeArguments_instantiations_offset = 8;
static constexpr dart::compiler::target::word AOT_TypeArguments_length_offset =
16;
@@ -6112,6 +6148,10 @@
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 32;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 33;
static constexpr dart::compiler::target::word
+ AOT_TypeParameter_parameterized_class_id_offset = 28;
+static constexpr dart::compiler::target::word AOT_TypeParameter_index_offset =
+ 36;
+static constexpr dart::compiler::target::word
AOT_TypeArguments_instantiations_offset = 4;
static constexpr dart::compiler::target::word AOT_TypeArguments_length_offset =
8;
@@ -6663,6 +6703,10 @@
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 60;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 61;
static constexpr dart::compiler::target::word
+ AOT_TypeParameter_parameterized_class_id_offset = 56;
+static constexpr dart::compiler::target::word AOT_TypeParameter_index_offset =
+ 64;
+static constexpr dart::compiler::target::word
AOT_TypeArguments_instantiations_offset = 8;
static constexpr dart::compiler::target::word AOT_TypeArguments_length_offset =
16;
@@ -7219,6 +7263,10 @@
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 60;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 61;
static constexpr dart::compiler::target::word
+ AOT_TypeParameter_parameterized_class_id_offset = 56;
+static constexpr dart::compiler::target::word AOT_TypeParameter_index_offset =
+ 64;
+static constexpr dart::compiler::target::word
AOT_TypeArguments_instantiations_offset = 8;
static constexpr dart::compiler::target::word AOT_TypeArguments_length_offset =
16;
diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h
index 10cfdcd..6f1dcb6 100644
--- a/runtime/vm/compiler/runtime_offsets_list.h
+++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -249,6 +249,8 @@
FIELD(Type, type_class_id_offset) \
FIELD(Type, type_state_offset) \
FIELD(Type, nullability_offset) \
+ FIELD(TypeParameter, parameterized_class_id_offset) \
+ FIELD(TypeParameter, index_offset) \
FIELD(TypeArguments, instantiations_offset) \
FIELD(TypeArguments, length_offset) \
FIELD(TypeArguments, nullability_offset) \
diff --git a/runtime/vm/compiler/stub_code_compiler_arm.cc b/runtime/vm/compiler/stub_code_compiler_arm.cc
index 38ac210..1669dc6 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm.cc
@@ -3223,6 +3223,59 @@
__ Ret();
}
+static void BuildTypeParameterTypeTestStub(Assembler* assembler,
+ bool allow_null) {
+ Label done;
+
+ if (allow_null) {
+ __ CompareObject(TypeTestABI::kInstanceReg, NullObject());
+ __ BranchIf(EQUAL, &done);
+ }
+
+ Label function_type_param;
+ __ ldrh(TypeTestABI::kScratchReg,
+ FieldAddress(TypeTestABI::kDstTypeReg,
+ TypeParameter::parameterized_class_id_offset()));
+ __ cmp(TypeTestABI::kScratchReg, Operand(kFunctionCid));
+ __ BranchIf(EQUAL, &function_type_param);
+
+ auto handle_case = [&](Register tav) {
+ __ CompareObject(tav, NullObject());
+ __ BranchIf(EQUAL, &done);
+ __ ldrh(
+ TypeTestABI::kScratchReg,
+ FieldAddress(TypeTestABI::kDstTypeReg, TypeParameter::index_offset()));
+ __ add(TypeTestABI::kScratchReg, tav,
+ Operand(TypeTestABI::kScratchReg, LSL, 8));
+ __ ldr(TypeTestABI::kScratchReg,
+ FieldAddress(TypeTestABI::kScratchReg,
+ target::TypeArguments::InstanceSize()));
+ __ Branch(FieldAddress(TypeTestABI::kScratchReg,
+ AbstractType::type_test_stub_entry_point_offset()));
+ };
+
+ // Class type parameter: If dynamic we're done, otherwise dereference type
+ // parameter and tail call.
+ handle_case(TypeTestABI::kInstantiatorTypeArgumentsReg);
+
+ // Function type parameter: If dynamic we're done, otherwise dereference type
+ // parameter and tail call.
+ __ Bind(&function_type_param);
+ handle_case(TypeTestABI::kFunctionTypeArgumentsReg);
+
+ __ Bind(&done);
+ __ Ret();
+}
+
+void StubCodeCompiler::GenerateNullableTypeParameterTypeTestStub(
+ Assembler* assembler) {
+ BuildTypeParameterTypeTestStub(assembler, /*allow_null=*/true);
+}
+
+void StubCodeCompiler::GenerateTypeParameterTypeTestStub(Assembler* assembler) {
+ BuildTypeParameterTypeTestStub(assembler, /*allow_null=*/false);
+}
+
void StubCodeCompiler::GenerateSlowTypeTestStub(Assembler* assembler) {
Label done, call_runtime;
diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc
index afc9b10..6ff81a8 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc
@@ -3391,6 +3391,63 @@
__ Ret();
}
+static void BuildTypeParameterTypeTestStub(Assembler* assembler,
+ bool allow_null) {
+ Label done;
+
+ if (allow_null) {
+ __ CompareObject(TypeTestABI::kInstanceReg, NullObject());
+ __ BranchIf(EQUAL, &done);
+ }
+
+ Label function_type_param;
+ __ ldr(TypeTestABI::kScratchReg,
+ FieldAddress(TypeTestABI::kDstTypeReg,
+ TypeParameter::parameterized_class_id_offset()),
+ kUnsignedHalfword);
+ __ cmp(TypeTestABI::kScratchReg, Operand(kFunctionCid));
+ __ BranchIf(EQUAL, &function_type_param);
+
+ auto handle_case = [&](Register tav) {
+ __ CompareObject(tav, NullObject());
+ __ BranchIf(EQUAL, &done);
+ __ ldr(
+ TypeTestABI::kScratchReg,
+ FieldAddress(TypeTestABI::kDstTypeReg, TypeParameter::index_offset()),
+ kUnsignedHalfword);
+ __ add(TypeTestABI::kScratchReg, tav,
+ Operand(TypeTestABI::kScratchReg, LSL, 8));
+ __ ldr(TypeTestABI::kScratchReg,
+ FieldAddress(TypeTestABI::kScratchReg,
+ target::TypeArguments::InstanceSize()));
+ __ ldr(TypeTestABI::kScratchReg,
+ FieldAddress(TypeTestABI::kScratchReg,
+ AbstractType::type_test_stub_entry_point_offset()));
+ __ br(TypeTestABI::kScratchReg);
+ };
+
+ // Class type parameter: If dynamic we're done, otherwise dereference type
+ // parameter and tail call.
+ handle_case(TypeTestABI::kInstantiatorTypeArgumentsReg);
+
+ // Function type parameter: If dynamic we're done, otherwise dereference type
+ // parameter and tail call.
+ __ Bind(&function_type_param);
+ handle_case(TypeTestABI::kFunctionTypeArgumentsReg);
+
+ __ Bind(&done);
+ __ Ret();
+}
+
+void StubCodeCompiler::GenerateNullableTypeParameterTypeTestStub(
+ Assembler* assembler) {
+ BuildTypeParameterTypeTestStub(assembler, /*allow_null=*/true);
+}
+
+void StubCodeCompiler::GenerateTypeParameterTypeTestStub(Assembler* assembler) {
+ BuildTypeParameterTypeTestStub(assembler, /*allow_null=*/false);
+}
+
void StubCodeCompiler::GenerateSlowTypeTestStub(Assembler* assembler) {
Label done, call_runtime;
diff --git a/runtime/vm/compiler/stub_code_compiler_ia32.cc b/runtime/vm/compiler/stub_code_compiler_ia32.cc
index 96bf0ff..9ce50a1 100644
--- a/runtime/vm/compiler/stub_code_compiler_ia32.cc
+++ b/runtime/vm/compiler/stub_code_compiler_ia32.cc
@@ -2630,6 +2630,17 @@
__ Breakpoint();
}
+void StubCodeCompiler::GenerateNullableTypeParameterTypeTestStub(
+ Assembler* assembler) {
+ // Not implemented on ia32.
+ __ Breakpoint();
+}
+
+void StubCodeCompiler::GenerateTypeParameterTypeTestStub(Assembler* assembler) {
+ // Not implemented on ia32.
+ __ Breakpoint();
+}
+
void StubCodeCompiler::GenerateSlowTypeTestStub(Assembler* assembler) {
// Not implemented on ia32.
__ Breakpoint();
diff --git a/runtime/vm/compiler/stub_code_compiler_x64.cc b/runtime/vm/compiler/stub_code_compiler_x64.cc
index e6566c3..e7011d0 100644
--- a/runtime/vm/compiler/stub_code_compiler_x64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_x64.cc
@@ -3346,6 +3346,56 @@
__ Ret();
}
+static void BuildTypeParameterTypeTestStub(Assembler* assembler,
+ bool allow_null) {
+ Label done;
+
+ if (allow_null) {
+ __ CompareObject(TypeTestABI::kInstanceReg, NullObject());
+ __ BranchIf(EQUAL, &done);
+ }
+
+ Label function_type_param;
+ __ cmpw(FieldAddress(TypeTestABI::kDstTypeReg,
+ TypeParameter::parameterized_class_id_offset()),
+ Immediate(kFunctionCid));
+ __ BranchIf(EQUAL, &function_type_param);
+
+ auto handle_case = [&](Register tav) {
+ __ CompareObject(tav, NullObject());
+ __ BranchIf(EQUAL, &done);
+ __ movzxw(
+ TypeTestABI::kScratchReg,
+ FieldAddress(TypeTestABI::kDstTypeReg, TypeParameter::index_offset()));
+ __ movq(TypeTestABI::kScratchReg,
+ FieldAddress(tav, TypeTestABI::kScratchReg, TIMES_8,
+ target::TypeArguments::InstanceSize()));
+ __ jmp(FieldAddress(TypeTestABI::kScratchReg,
+ AbstractType::type_test_stub_entry_point_offset()));
+ };
+
+ // Class type parameter: If dynamic we're done, otherwise dereference type
+ // parameter and tail call.
+ handle_case(TypeTestABI::kInstantiatorTypeArgumentsReg);
+
+ // Function type parameter: If dynamic we're done, otherwise dereference type
+ // parameter and tail call.
+ __ Bind(&function_type_param);
+ handle_case(TypeTestABI::kFunctionTypeArgumentsReg);
+
+ __ Bind(&done);
+ __ Ret();
+}
+
+void StubCodeCompiler::GenerateNullableTypeParameterTypeTestStub(
+ Assembler* assembler) {
+ BuildTypeParameterTypeTestStub(assembler, /*allow_null=*/true);
+}
+
+void StubCodeCompiler::GenerateTypeParameterTypeTestStub(Assembler* assembler) {
+ BuildTypeParameterTypeTestStub(assembler, /*allow_null=*/false);
+}
+
void StubCodeCompiler::GenerateSlowTypeTestStub(Assembler* assembler) {
Label done, call_runtime;
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index ea46f78a..2c62815 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -326,11 +326,12 @@
static const Register kInstantiatorTypeArgumentsReg = R2;
static const Register kFunctionTypeArgumentsReg = R1;
static const Register kSubtypeTestCacheReg = R3;
+ static const Register kScratchReg = R4;
static const intptr_t kAbiRegisters =
(1 << kInstanceReg) | (1 << kDstTypeReg) |
(1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg) |
- (1 << kSubtypeTestCacheReg);
+ (1 << kSubtypeTestCacheReg) | (1 << kScratchReg);
// For call to InstanceOfStub.
static const Register kResultReg = R0;
diff --git a/runtime/vm/constants_arm64.h b/runtime/vm/constants_arm64.h
index 2ce6ac37..1c71baa 100644
--- a/runtime/vm/constants_arm64.h
+++ b/runtime/vm/constants_arm64.h
@@ -158,11 +158,12 @@
static const Register kInstantiatorTypeArgumentsReg = R2;
static const Register kFunctionTypeArgumentsReg = R1;
static const Register kSubtypeTestCacheReg = R3;
+ static const Register kScratchReg = R4;
static const intptr_t kAbiRegisters =
(1 << kInstanceReg) | (1 << kDstTypeReg) |
(1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg) |
- (1 << kSubtypeTestCacheReg);
+ (1 << kSubtypeTestCacheReg) | (1 << kScratchReg);
// For call to InstanceOfStub.
static const Register kResultReg = R0;
diff --git a/runtime/vm/constants_x64.h b/runtime/vm/constants_x64.h
index d696eac..218823e 100644
--- a/runtime/vm/constants_x64.h
+++ b/runtime/vm/constants_x64.h
@@ -148,11 +148,12 @@
static const Register kInstantiatorTypeArgumentsReg = RDX;
static const Register kFunctionTypeArgumentsReg = RCX;
static const Register kSubtypeTestCacheReg = R9;
+ static const Register kScratchReg = RSI;
static const intptr_t kAbiRegisters =
(1 << kInstanceReg) | (1 << kDstTypeReg) |
(1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg) |
- (1 << kSubtypeTestCacheReg);
+ (1 << kSubtypeTestCacheReg) | (1 << kScratchReg);
// For call to InstanceOfStub.
static const Register kResultReg = RAX;
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index f399b23..46144d1b 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -8387,6 +8387,14 @@
bool IsFunctionTypeParameter() const {
return parameterized_function() != Function::null();
}
+
+ static intptr_t parameterized_class_id_offset() {
+ return OFFSET_OF(TypeParameterLayout, parameterized_class_id_);
+ }
+ static intptr_t index_offset() {
+ return OFFSET_OF(TypeParameterLayout, index_);
+ }
+
StringPtr name() const { return raw_ptr()->name_; }
intptr_t index() const { return raw_ptr()->index_; }
void set_index(intptr_t value) const;
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 1314622..f8046bd 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -212,6 +212,8 @@
RW(Code, default_tts_stub) \
RW(Code, default_nullable_tts_stub) \
RW(Code, top_type_tts_stub) \
+ RW(Code, nullable_type_parameter_tts_stub) \
+ RW(Code, type_parameter_tts_stub) \
RW(Code, unreachable_tts_stub) \
RW(Code, slow_tts_stub) \
RW(Array, dispatch_table_code_entries) \
@@ -251,6 +253,8 @@
DO(default_tts_stub, DefaultTypeTest) \
DO(default_nullable_tts_stub, DefaultNullableTypeTest) \
DO(top_type_tts_stub, TopTypeTypeTest) \
+ DO(nullable_type_parameter_tts_stub, NullableTypeParameterTypeTest) \
+ DO(type_parameter_tts_stub, TypeParameterTypeTest) \
DO(unreachable_tts_stub, UnreachableTypeTest) \
DO(slow_tts_stub, SlowTypeTest) \
DO(write_barrier_wrappers_stub, WriteBarrierWrappers) \
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index b4f7acd..a3cf970 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -14,8 +14,8 @@
namespace dart {
-#define SERVICE_PROTOCOL_MAJOR_VERSION 4
-#define SERVICE_PROTOCOL_MINOR_VERSION 0
+#define SERVICE_PROTOCOL_MAJOR_VERSION 3
+#define SERVICE_PROTOCOL_MINOR_VERSION 39
class Array;
class EmbedderServiceHandler;
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index 5eeb755..69dde47 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1,8 +1,8 @@
-# Dart VM Service Protocol 4.0
+# Dart VM Service Protocol 3.39
> Please post feedback to the [observatory-discuss group][discuss-list]
-This document describes of _version 4.0_ of the Dart VM Service Protocol. This
+This document describes of _version 3.39_ 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.
@@ -3834,6 +3834,6 @@
3.36 | Added `getProcessMemoryUsage` RPC and `ProcessMemoryUsage` and `ProcessMemoryItem` objects.
3.37 | Added `getWebSocketTarget` RPC and `WebSocketTarget` object.
3.38 | Added `isSystemIsolate` property to `@Isolate` and `Isolate`, `isSystemIsolateGroup` property to `@IsolateGroup` and `IsolateGroup`, and properties `systemIsolates` and `systemIsolateGroups` to `VM`.
-4.0 | Removed the following deprecated RPCs and objects: `getClientName`, `getWebSocketTarget`, `setClientName`, `requireResumeApproval`, `ClientName`, and `WebSocketTarget`.
+3.39 | Removed the following deprecated RPCs and objects: `getClientName`, `getWebSocketTarget`, `setClientName`, `requireResumeApproval`, `ClientName`, and `WebSocketTarget`.
[discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
diff --git a/runtime/vm/stub_code_list.h b/runtime/vm/stub_code_list.h
index f759ea8..e38740c 100644
--- a/runtime/vm/stub_code_list.h
+++ b/runtime/vm/stub_code_list.h
@@ -70,6 +70,8 @@
V(DefaultNullableTypeTest) \
V(TopTypeTypeTest) \
V(UnreachableTypeTest) \
+ V(TypeParameterTypeTest) \
+ V(NullableTypeParameterTypeTest) \
V(SlowTypeTest) \
V(LazySpecializeTypeTest) \
V(LazySpecializeNullableTypeTest) \
diff --git a/runtime/vm/type_testing_stubs.cc b/runtime/vm/type_testing_stubs.cc
index fe40775..8f5f57c 100644
--- a/runtime/vm/type_testing_stubs.cc
+++ b/runtime/vm/type_testing_stubs.cc
@@ -91,10 +91,11 @@
CodePtr TypeTestingStubGenerator::DefaultCodeForType(
const AbstractType& type,
bool lazy_specialize /* = true */) {
+ auto isolate = Isolate::Current();
+
if (type.IsTypeRef()) {
- return Isolate::Current()->null_safety()
- ? StubCode::DefaultTypeTest().raw()
- : StubCode::DefaultNullableTypeTest().raw();
+ return isolate->null_safety() ? StubCode::DefaultTypeTest().raw()
+ : StubCode::DefaultNullableTypeTest().raw();
}
// During bootstrapping we have no access to stubs yet, so we'll just return
@@ -109,8 +110,16 @@
if (type.IsTopTypeForSubtyping()) {
return StubCode::TopTypeTypeTest().raw();
}
+ if (type.IsTypeParameter()) {
+ const bool nullable = Instance::NullIsAssignableTo(type);
+ if (nullable) {
+ return StubCode::NullableTypeParameterTypeTest().raw();
+ } else {
+ return StubCode::TypeParameterTypeTest().raw();
+ }
+ }
- if (type.IsType() || type.IsTypeParameter()) {
+ if (type.IsType()) {
const bool should_specialize = !FLAG_precompiled_mode && lazy_specialize;
const bool nullable = Instance::NullIsAssignableTo(type);
if (should_specialize) {
@@ -144,7 +153,7 @@
#if !defined(TARGET_ARCH_IA32)
ASSERT(StubCode::HasBeenInitialized());
- if (type.IsTypeRef()) {
+ if (type.IsTypeRef() || type.IsTypeParameter()) {
return TypeTestingStubGenerator::DefaultCodeForType(
type, /*lazy_specialize=*/false);
}
diff --git a/runtime/vm/type_testing_stubs_test.cc b/runtime/vm/type_testing_stubs_test.cc
index f6afdad..0a218cb 100644
--- a/runtime/vm/type_testing_stubs_test.cc
+++ b/runtime/vm/type_testing_stubs_test.cc
@@ -75,8 +75,14 @@
arguments.SetAt(5, dst_type);
// Ensure we have a) uninitialized TTS b) no/empty SubtypeTestCache.
- dst_type.SetTypeTestingStub(StubCode::LazySpecializeTypeTest());
- EXPECT(dst_type.type_test_stub() == StubCode::LazySpecializeTypeTest().raw());
+ auto& instantiated_dst_type = AbstractType::Handle(dst_type.raw());
+ if (dst_type.IsTypeParameter()) {
+ instantiated_dst_type = TypeParameter::Cast(dst_type).GetFromTypeArguments(
+ instantiator_tav, function_tav);
+ }
+ instantiated_dst_type.SetTypeTestingStub(StubCode::LazySpecializeTypeTest());
+ EXPECT(instantiated_dst_type.type_test_stub() ==
+ StubCode::LazySpecializeTypeTest().raw());
EXPECT(pool.ObjectAt(kSubtypeTestCacheIndex) == Object::null());
auto& result = Object::Handle();
@@ -92,7 +98,7 @@
result = DartEntry::InvokeCode(invoke_tts, arguments_descriptor, arguments,
thread);
stc ^= pool.ObjectAt(kSubtypeTestCacheIndex);
- tts = dst_type.type_test_stub();
+ tts = instantiated_dst_type.type_test_stub();
if (!result.IsError()) {
EXPECT(tts.raw() != StubCode::LazySpecializeTypeTest().raw());
}
@@ -102,7 +108,7 @@
result2 = DartEntry::InvokeCode(invoke_tts, arguments_descriptor, arguments,
thread);
stc2 ^= pool.ObjectAt(kSubtypeTestCacheIndex);
- tts2 = dst_type.type_test_stub();
+ tts2 = instantiated_dst_type.type_test_stub();
abi_regs_modified ^= abi_regs_modified_box.At(0);
rest_regs_modified ^= rest_regs_modified_box.At(0);
EXPECT(result2.IsError() || !abi_regs_modified.IsNull());
@@ -114,18 +120,13 @@
// SubtypeTestCache
// (This is to simulate AOT where we don't use lazy specialization but
// precompile the TTS)
- auto& dst_type_to_specialize = AbstractType::Handle(dst_type.raw());
- if (dst_type_to_specialize.IsTypeParameter()) {
- dst_type_to_specialize = TypeParameter::Cast(dst_type).GetFromTypeArguments(
- instantiator_tav, function_tav);
- }
- TypeTestingStubGenerator::SpecializeStubFor(thread, dst_type_to_specialize);
- tts = dst_type.type_test_stub();
+ TypeTestingStubGenerator::SpecializeStubFor(thread, instantiated_dst_type);
+ tts = instantiated_dst_type.type_test_stub();
result2 = DartEntry::InvokeCode(invoke_tts, arguments_descriptor, arguments,
thread);
stc2 ^= pool.ObjectAt(kSubtypeTestCacheIndex);
- tts2 = dst_type.type_test_stub();
+ tts2 = instantiated_dst_type.type_test_stub();
abi_regs_modified ^= abi_regs_modified_box.At(0);
rest_regs_modified ^= rest_regs_modified_box.At(0);
EXPECT(result2.IsError() || !abi_regs_modified.IsNull());
@@ -664,6 +665,50 @@
ExpectFailedViaTTS);
}
+ISOLATE_UNIT_TEST_CASE(TTS_TypeParameter) {
+ const char* kScript =
+ R"(
+ class A<T> {
+ T test(dynamic x) => x as T;
+ }
+ H genericFun<H>(dynamic x) => x as H;
+
+ createAInt() => A<int>();
+ createAString() => A<String>();
+ )";
+
+ const auto& root_library = Library::Handle(LoadTestScript(kScript));
+ const auto& class_a = Class::Handle(GetClass(root_library, "A"));
+ const auto& fun_generic =
+ Function::Handle(GetFunction(root_library, "genericFun"));
+
+ const auto& dst_type_t =
+ TypeParameter::Handle(GetClassTypeParameter(class_a, "T"));
+ const auto& dst_type_h =
+ TypeParameter::Handle(GetFunctionTypeParameter(fun_generic, "H"));
+
+ const auto& aint = Object::Handle(Invoke(root_library, "createAInt"));
+ const auto& astring = Object::Handle(Invoke(root_library, "createAString"));
+
+ const auto& int_tav =
+ TypeArguments::Handle(Instance::Cast(aint).GetTypeArguments());
+ const auto& string_tav =
+ TypeArguments::Handle(Instance::Cast(astring).GetTypeArguments());
+
+ const auto& int_instance = Integer::Handle(Integer::New(1));
+ const auto& string_instance = String::Handle(String::New("foo"));
+
+ RunTTSTest(int_instance, dst_type_t, int_tav, string_tav,
+ ExpectLazilyHandledViaTTS, ExpectHandledViaTTS);
+ RunTTSTest(string_instance, dst_type_t, int_tav, string_tav,
+ ExpectLazilyFailedViaTTS, ExpectFailedViaTTS);
+
+ RunTTSTest(string_instance, dst_type_h, int_tav, string_tav,
+ ExpectLazilyHandledViaTTS, ExpectHandledViaTTS);
+ RunTTSTest(int_instance, dst_type_h, int_tav, string_tav,
+ ExpectLazilyFailedViaTTS, ExpectFailedViaTTS);
+}
+
} // namespace dart
#endif // defined(TARGET_ARCH_ARM64) || defined(TARGET_ARCH_ARM) || \
diff --git a/sdk/lib/_http/http.dart b/sdk/lib/_http/http.dart
index 6e80086..151dae4 100644
--- a/sdk/lib/_http/http.dart
+++ b/sdk/lib/_http/http.dart
@@ -868,7 +868,8 @@
}
/**
- * A MIME/IANA media type used as the value of the [contentTypeHeader] header.
+ * A MIME/IANA media type used as the value of the
+ * [HttpHeaders.contentTypeHeader] header.
*
* A [ContentType] is immutable.
*/
diff --git a/sdk/lib/convert/json.dart b/sdk/lib/convert/json.dart
index 6d897a0..e55bc2a 100644
--- a/sdk/lib/convert/json.dart
+++ b/sdk/lib/convert/json.dart
@@ -64,7 +64,7 @@
/// a local variable shadows the [json] constant.
const JsonCodec json = JsonCodec();
-/// Converts [value] to a JSON string.
+/// Converts [object] to a JSON string.
///
/// If value contains objects that are not directly encodable to a JSON
/// string (a value that is not a number, boolean, string, null, list or a map
diff --git a/sdk/lib/core/map.dart b/sdk/lib/core/map.dart
index a92d08d..cbb1608 100644
--- a/sdk/lib/core/map.dart
+++ b/sdk/lib/core/map.dart
@@ -83,7 +83,7 @@
* Creates an identity map with the default implementation, [LinkedHashMap].
*
* An identity map uses [identical] for equality and [identityHashCode]
- * for hash codes of keys instead of the intrinsic [Object.operator==] and
+ * for hash codes of keys instead of the intrinsic [Object.==] and
* [Object.hashCode] of the keys.
*
* The returned map allows `null` as a key.
diff --git a/sdk/lib/core/regexp.dart b/sdk/lib/core/regexp.dart
index b75882d..ca5309f 100644
--- a/sdk/lib/core/regexp.dart
+++ b/sdk/lib/core/regexp.dart
@@ -152,7 +152,7 @@
* character is a line terminator. When true, then the "." character will
* match any single character including line terminators.
*
- * This feature is distinct from [isMultiline], as they affect the behavior
+ * This feature is distinct from [isMultiLine], as they affect the behavior
* of different pattern characters, and so they can be used together or
* separately.
*/
diff --git a/sdk/lib/io/socket.dart b/sdk/lib/io/socket.dart
index b5e814f..d2a0feb 100644
--- a/sdk/lib/io/socket.dart
+++ b/sdk/lib/io/socket.dart
@@ -176,8 +176,8 @@
* valid UTF-8 encoded file path.
*
* If [type] is omitted, the [rawAddress] must have a length of either 4 or
- * 16, in which case the type defaults to [InternetAddress.IPv4] or
- * [InternetAddress.IPv6] respectively.
+ * 16, in which case the type defaults to [InternetAddressType.IPv4] or
+ * [InternetAddressType.IPv6] respectively.
*/
external factory InternetAddress.fromRawAddress(Uint8List rawAddress,
{@Since("2.8") InternetAddressType? type});
@@ -472,24 +472,24 @@
/// [RawSocket.setRawOption] to set customize the behaviour of the underlying
/// socket.
///
-/// It allows for fine grained control of the socket options, and its values will
-/// be passed to the underlying platform's implementation of setsockopt and
+/// It allows for fine grained control of the socket options, and its values
+/// will be passed to the underlying platform's implementation of setsockopt and
/// getsockopt.
@Since("2.2")
class RawSocketOption {
/// Creates a RawSocketOption for getRawOption andSetRawOption.
///
/// The level and option arguments correspond to level and optname arguments
- /// on the get/setsockopt native calls.
+ /// on the getsockopt and setsockopt native calls.
///
/// The value argument and its length correspond to the optval and length
/// arguments on the native call.
///
- /// For a [getRawOption] call, the value parameter will be updated after a
- /// successful call (although its length will not be changed).
+ /// For a [RawSocket.getRawOption] call, the value parameter will be updated
+ /// after a successful call (although its length will not be changed).
///
- /// For a [setRawOption] call, the value parameter will be used set the
- /// option.
+ /// For a [RawSocket.setRawOption] call, the value parameter will be used set
+ /// the option.
const RawSocketOption(this.level, this.option, this.value);
/// Convenience constructor for creating an int based RawSocketOption.
diff --git a/sdk/lib/io/stdio.dart b/sdk/lib/io/stdio.dart
index a0034c6..9fc8401 100644
--- a/sdk/lib/io/stdio.dart
+++ b/sdk/lib/io/stdio.dart
@@ -41,7 +41,7 @@
* Blocks until a full line is available.
*
* Lines my be terminated by either `<CR><LF>` or `<LF>`. On Windows in cases
- * where the [stdioType] of stdin is [StdioType.termimal] the terminator may
+ * where the [stdioType] of stdin is [StdioType.terminal] the terminator may
* also be a single `<CR>`.
*
* Input bytes are converted to a string by [encoding].
diff --git a/sdk/lib/js/js.dart b/sdk/lib/js/js.dart
index 26a6141..c97d968 100644
--- a/sdk/lib/js/js.dart
+++ b/sdk/lib/js/js.dart
@@ -229,5 +229,5 @@
///
/// See [allowInterop].
///
-/// When called from Dart, [null] will be passed as the first argument.
+/// When called from Dart, `null` will be passed as the first argument.
external Function allowInteropCaptureThis(Function f);
diff --git a/tools/VERSION b/tools/VERSION
index 54f30f2..7aea38a 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 10
PATCH 0
-PRERELEASE 108
+PRERELEASE 109
PRERELEASE_PATCH 0
\ No newline at end of file