Version 2.11.0-274.0.dev
Merge commit 'd5118d5fc83db077f23b8f7dd5d489634199ad1a' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5e40af4..2611829 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,8 +4,14 @@
#### `dart:io`
-* `HttpRequest` will now correctly follow HTTP 308 redirects
- (`HttpStatus.permanentRedirect`).
+* `HttpRequest` will now correctly follow HTTP 308 redirects
+ (`HttpStatus.permanentRedirect`).
+
+#### `dart:isolate`
+
+* Added `debugName` positional parameter to `ReceivePort` and `RawReceivePort`
+ constructors, a name which can be associated with the port and displayed in
+ tooling.
### Dart VM
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
index 2788422..7ea8635 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
@@ -10,6 +10,15 @@
class TransformSetErrorCode extends ErrorCode {
/**
* Parameters:
+ * 0: the conflicting key
+ * 1: the key that it conflicts with
+ */
+ static const TransformSetErrorCode conflictingKey = TransformSetErrorCode(
+ 'conflicting_key',
+ "The key '{0}' can't be used when '{1}' is also used.");
+
+ /**
+ * Parameters:
* 0: the character that is invalid
*/
static const TransformSetErrorCode invalidCharacter =
@@ -17,9 +26,16 @@
/**
* Parameters:
+ * 0: the actual type of the key
+ */
+ static const TransformSetErrorCode invalidKey = TransformSetErrorCode(
+ 'invalid_key', "Keys must be of type 'String' but found the type '{0}'.");
+
+ /**
+ * Parameters:
* 0: the key with which the value is associated
* 1: the expected type of the value
- * 0: the actual type of the value
+ * 2: the actual type of the value
*/
static const TransformSetErrorCode invalidValue = TransformSetErrorCode(
'invalid_value',
@@ -27,6 +43,14 @@
/**
* Parameters:
+ * 0: the list of valid parameter styles
+ */
+ static const TransformSetErrorCode invalidParameterStyle =
+ TransformSetErrorCode('invalid_parameter_style',
+ "The parameter style must be one of the following: {0}.");
+
+ /**
+ * Parameters:
* 0: the key with which the value is associated
* 1: the allowed values as a comma-separated list
*/
@@ -42,6 +66,14 @@
TransformSetErrorCode('missing_key', "Missing the required key '{0}'.");
/**
+ * Parameters:
+ * 0: the list of valid keys
+ */
+ static const TransformSetErrorCode missingOneOfMultipleKeys =
+ TransformSetErrorCode('missing_one_of_multiple_keys',
+ "Exactly one of the following keys must be provided: {0}.");
+
+ /**
* No parameters.
*/
static const TransformSetErrorCode missingTemplateEnd = TransformSetErrorCode(
@@ -55,6 +87,12 @@
TransformSetErrorCode('missing_token', "Expected to find {0}.");
/**
+ * No parameters.
+ */
+ static const TransformSetErrorCode missingUri = TransformSetErrorCode(
+ 'missing_uri', "At least one URI must be provided.");
+
+ /**
* Parameters:
* 0: the missing key
*/
@@ -76,6 +114,12 @@
'unsupported_key', "The key '{0}' isn't supported.");
/**
+ * No parameters.
+ */
+ static const TransformSetErrorCode unsupportedVersion = TransformSetErrorCode(
+ 'unsupported_version', "Only version '1' is supported at this time.");
+
+ /**
* Parameters:
* 0: a description of the expected kind of token
* 1: a description of the actial kind of token
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
index a525413..f00f631 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
@@ -102,6 +102,9 @@
static const String _openComponent = '{%';
static const String _closeComponent = '%}';
+ /// The lowest file version supported by this parser.
+ static const int oldestVersion = 1;
+
/// The highest file version supported by this parser. The version needs to be
/// incremented any time the parser is updated to disallow input that would
/// have been valid in the most recently published version of server. This
@@ -260,10 +263,12 @@
}
}
- /// Given a [map] and a set of [validKeys], ensure that only one of those keys
- /// is in the map and return it. If more than one of the keys is in the map,
- /// report a diagnostic.
- String _singleKey(YamlMap map, List<String> validKeys) {
+ /// Given a [map] and a set of [validKeys], ensure that exactly one of those
+ /// keys is in the map and return it. If more than one of the keys is in the
+ /// map, report a diagnostic for each extra key. If [required] is `true` and
+ /// none of the keys is in the map, report a diagnostic at the [errorNode].
+ String _singleKey(YamlMap map, List<String> validKeys, YamlNode errorNode,
+ {bool required = true}) {
assert(validKeys != null);
var foundKeys = <String>[];
var keyToNodeMap = <String, YamlNode>{};
@@ -277,14 +282,21 @@
}
}
if (foundKeys.isEmpty) {
- // TODO(brianwilkerson) Report the problem.
+ if (required) {
+ var validKeysList = validKeys.map((key) => "'$key'").join(', ');
+ _reportError(TransformSetErrorCode.missingOneOfMultipleKeys, errorNode,
+ [validKeysList]);
+ }
return null;
}
+ var firstKey = foundKeys[0];
for (var i = 1; i < foundKeys.length; i++) {
- // var invalidNode = keyToNodeMap[foundKeys[i]];
- // TODO(brianwilkerson) Report the problem.
+ var foundKey = foundKeys[i];
+ var invalidNode = keyToNodeMap[foundKey];
+ _reportError(TransformSetErrorCode.conflictingKey, invalidNode,
+ [foundKey, firstKey]);
}
- return foundKeys[0];
+ return firstKey;
}
/// Translate the [node] into a add-parameter modification.
@@ -294,19 +306,26 @@
var index = _translateInteger(node.valueAt(_indexKey),
ErrorContext(key: _indexKey, parentNode: node));
if (index == null) {
+ // The error has already been reported.
return;
}
var name = _translateString(
node.valueAt(_nameKey), ErrorContext(key: _nameKey, parentNode: node));
if (name == null) {
+ // The error has already been reported.
return;
}
- var style = _translateString(node.valueAt(_styleKey),
- ErrorContext(key: _styleKey, parentNode: node));
+ var styleNode = node.valueAt(_styleKey);
+ var style = _translateString(
+ styleNode, ErrorContext(key: _styleKey, parentNode: node));
if (style == null) {
+ // The error has already been reported.
return;
- } else if (!validStyles.contains(style)) {
- // TODO(brianwilkerson) Report the invalid style.
+ }
+ if (!validStyles.contains(style)) {
+ var validStylesList = validStyles.map((style) => "'$style'").join(', ');
+ _reportError(TransformSetErrorCode.invalidParameterStyle, styleNode,
+ [validStylesList]);
return;
}
var isRequired = style.startsWith('required_');
@@ -348,10 +367,10 @@
// The error has already been reported.
return null;
}
- // TODO(brianwilkerson) In order to support adding multiple type parameters
- // we might need to introduce a `TypeParameterModification` change, similar
- // to `ParameterModification`. That becomes more likely if we add support
- // for removing type parameters.
+ // In order to support adding multiple type parameters we might need to
+ // introduce a `TypeParameterModification` change, similar to
+ // `ParameterModification`. That becomes more likely if we add support for
+ // removing type parameters.
return AddTypeParameter(
index: index,
name: name,
@@ -458,7 +477,8 @@
template = _translateString(statementsNode,
ErrorContext(key: _statementsKey, parentNode: node));
} else {
- // TODO(brianwilkerson) Report the missing key.
+ _reportError(TransformSetErrorCode.missingOneOfMultipleKeys, node,
+ ["'$_expressionKey' or '$_statementsKey'"]);
return null;
}
}
@@ -505,23 +525,27 @@
/// error.
ElementDescriptor _translateElement(YamlNode node, ErrorContext context) {
if (node is YamlMap) {
- var uris = _translateList(node.valueAt(_urisKey),
+ var urisNode = node.valueAt(_urisKey);
+ var uris = _translateList(urisNode,
ErrorContext(key: _urisKey, parentNode: node), _translateUri);
- var elementKey = _singleKey(node, const [
- _classKey,
- _constantKey,
- _constructorKey,
- _enumKey,
- _extensionKey,
- _fieldKey,
- _functionKey,
- _getterKey,
- _methodKey,
- _mixinKey,
- _setterKey,
- _typedefKey,
- _variableKey
- ]);
+ var elementKey = _singleKey(
+ node,
+ const [
+ _classKey,
+ _constantKey,
+ _constructorKey,
+ _enumKey,
+ _extensionKey,
+ _fieldKey,
+ _functionKey,
+ _getterKey,
+ _methodKey,
+ _mixinKey,
+ _setterKey,
+ _typedefKey,
+ _variableKey
+ ],
+ node);
if (elementKey == null) {
// The error has already been reported.
return null;
@@ -534,14 +558,19 @@
}
var components = [elementName];
if (_containerKeyMap.containsKey(elementKey)) {
- var containerKey = _singleKey(node, _containerKeyMap[elementKey]);
+ var validContainerKeys = _containerKeyMap[elementKey];
+ var containerKey =
+ _singleKey(node, validContainerKeys, node, required: false);
var containerName = _translateString(node.valueAt(containerKey),
ErrorContext(key: containerKey, parentNode: node),
required: false);
if (containerName == null) {
if ([_constructorKey, _constantKey, _methodKey, _fieldKey]
.contains(elementKey)) {
- // TODO(brianwilkerson) Report that no container was found.
+ var validKeysList =
+ validContainerKeys.map((key) => "'$key'").join(', ');
+ _reportError(TransformSetErrorCode.missingOneOfMultipleKeys, node,
+ [validKeysList]);
return null;
}
} else {
@@ -552,6 +581,12 @@
// The error has already been reported.
return null;
}
+ if (uris.isEmpty) {
+ if ((urisNode as YamlList).isEmpty) {
+ _reportError(TransformSetErrorCode.missingUri, urisNode);
+ }
+ return null;
+ }
return ElementDescriptor(
libraryUris: uris,
kind: ElementKindUtilities.fromName(elementKey),
@@ -568,8 +603,9 @@
/// extractor.
ValueGenerator _translateImportValue(YamlMap node) {
_reportUnsupportedKeys(node, const {_kindKey, _nameKey, _urisKey});
- var uris = _translateList(node.valueAt(_urisKey),
- ErrorContext(key: _urisKey, parentNode: node), _translateUri);
+ var urisNode = node.valueAt(_urisKey);
+ var uris = _translateList(
+ urisNode, ErrorContext(key: _urisKey, parentNode: node), _translateUri);
var name = _translateString(
node.valueAt(_nameKey), ErrorContext(key: _nameKey, parentNode: node));
if (uris == null || name == null) {
@@ -577,9 +613,9 @@
return null;
}
if (uris.isEmpty) {
- // TODO(brianwilkerson) Report an empty list unless it's only empty
- // because the elements generated errors. This probably needs to be done
- // in [_translateList].
+ if ((urisNode as YamlList).isEmpty) {
+ _reportError(TransformSetErrorCode.missingUri, urisNode);
+ }
return null;
}
return ImportedName(uris, name);
@@ -604,11 +640,20 @@
/// Translate the given [node] as a key.
String _translateKey(YamlNode node) {
- if (node is YamlScalar && node.value is String) {
- return node.value as String;
+ String type;
+ if (node is YamlScalar) {
+ if (node.value is String) {
+ return node.value as String;
+ }
+ type = node.value.runtimeType.toString();
+ } else if (node is YamlList) {
+ type = 'List';
+ } else if (node is YamlMap) {
+ type = 'Map';
+ } else {
+ type = node.runtimeType.toString();
}
- // TODO(brianwilkerson) Report the invalidKey.
- // "Keys must be of type 'String' but found the type '{0}'."
+ _reportError(TransformSetErrorCode.invalidKey, node, [type]);
return null;
}
@@ -638,12 +683,12 @@
/// Translate the [node] into a remove-parameter modification.
void _translateRemoveParameterChange(YamlMap node) {
_reportUnsupportedKeys(node, const {_indexKey, _kindKey, _nameKey});
- ParameterReference reference;
- var parameterSpecKey = _singleKey(node, const [_nameKey, _indexKey]);
+ var parameterSpecKey = _singleKey(node, const [_nameKey, _indexKey], node);
if (parameterSpecKey == null) {
// The error has already been reported.
return null;
}
+ ParameterReference reference;
if (parameterSpecKey == _indexKey) {
var index = _translateInteger(node.valueAt(_indexKey),
ErrorContext(key: _indexKey, parentNode: node));
@@ -769,13 +814,14 @@
assert(node != null);
if (node is YamlMap) {
_reportUnsupportedKeys(node, const {_transformsKey, _versionKey});
- var version = _translateInteger(node.valueAt(_versionKey),
- ErrorContext(key: _versionKey, parentNode: node));
+ var versionNode = node.valueAt(_versionKey);
+ var version = _translateInteger(
+ versionNode, ErrorContext(key: _versionKey, parentNode: node));
if (version == null) {
// The error has already been reported.
return null;
- } else if (version > currentVersion) {
- // TODO(brianwilkerson) Report that the version is unsupported.
+ } else if (version < 1 || version > currentVersion) {
+ _reportError(TransformSetErrorCode.unsupportedVersion, versionNode);
return null;
}
// TODO(brianwilkerson) Version information is currently being ignored,
diff --git a/pkg/analysis_server/test/src/cider/completion_test.dart b/pkg/analysis_server/test/src/cider/completion_test.dart
index 5450ef6..f37076b 100644
--- a/pkg/analysis_server/test/src/cider/completion_test.dart
+++ b/pkg/analysis_server/test/src/cider/completion_test.dart
@@ -330,6 +330,34 @@
]);
}
+ Future<void> test_limitedResolution_class_constructor_body() async {
+ _configureToCheckNotResolved(
+ identifiers: {'print'},
+ );
+
+ await _compute(r'''
+class A<T> {
+ int f = 0;
+
+ A(int a) : f = 1 {
+ ^
+ }
+
+ void foo() {
+ print(0);
+ }
+}
+''');
+
+ _assertHasClass(text: 'A');
+ _assertHasClass(text: 'String');
+ _assertHasConstructor(text: 'A');
+ _assertHasFunction(text: 'print');
+ _assertHasMethod(text: 'foo');
+ _assertHasParameter(text: 'a');
+ _assertHasTypeParameter(text: 'T');
+ }
+
Future<void> test_limitedResolution_class_field_startWithType() async {
_configureToCheckNotResolved(
identifiers: {'print'},
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/conflicting_key_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/conflicting_key_test.dart
new file mode 100644
index 0000000..77d6de7
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/conflicting_key_test.dart
@@ -0,0 +1,52 @@
+// 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:analysis_server/src/services/correction/fix/data_driven/transform_set_error_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../transform_set_parser_test_support.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ConflictingKeyTest);
+ });
+}
+
+@reflectiveTest
+class ConflictingKeyTest extends AbstractTransformSetParserTest {
+ void test_element() {
+ assertErrors('''
+version: 1
+transforms:
+- title: ''
+ date: 2020-09-14
+ element:
+ uris: ['test.dart']
+ method: 'm'
+ class: 'C'
+ changes: []
+''', [
+ error(TransformSetErrorCode.missingOneOfMultipleKeys, 69, 53),
+ error(TransformSetErrorCode.conflictingKey, 109, 5),
+ ]);
+ }
+
+ void test_removeParameterChange() {
+ assertErrors('''
+version: 1
+transforms:
+- title: ''
+ date: 2020-09-14
+ element:
+ uris: ['test.dart']
+ function: 'f'
+ changes:
+ - kind: removeParameter
+ index: 2
+ name: 'p'
+''', [
+ error(TransformSetErrorCode.conflictingKey, 167, 4),
+ ]);
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/invalid_key_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/invalid_key_test.dart
new file mode 100644
index 0000000..0a7c158
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/invalid_key_test.dart
@@ -0,0 +1,47 @@
+// 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:analysis_server/src/services/correction/fix/data_driven/transform_set_error_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../transform_set_parser_test_support.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(InvalidKeyTest);
+ });
+}
+
+@reflectiveTest
+class InvalidKeyTest extends AbstractTransformSetParserTest {
+ void test_integer() {
+ assertErrors('''
+3: 4
+version: 1
+transforms: []
+''', [
+ error(TransformSetErrorCode.invalidKey, 0, 1),
+ ]);
+ }
+
+ void test_list() {
+ assertErrors('''
+[]: 4
+version: 1
+transforms: []
+''', [
+ error(TransformSetErrorCode.invalidKey, 0, 2),
+ ]);
+ }
+
+ void test_map() {
+ assertErrors('''
+{}: 4
+version: 1
+transforms: []
+''', [
+ error(TransformSetErrorCode.invalidKey, 0, 2),
+ ]);
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/invalid_parameter_style_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/invalid_parameter_style_test.dart
new file mode 100644
index 0000000..0fe38db
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/invalid_parameter_style_test.dart
@@ -0,0 +1,39 @@
+// 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:analysis_server/src/services/correction/fix/data_driven/transform_set_error_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../transform_set_parser_test_support.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(InvalidParameterStyleTest);
+ });
+}
+
+@reflectiveTest
+class InvalidParameterStyleTest extends AbstractTransformSetParserTest {
+ void test_invalid() {
+ assertErrors('''
+version: 1
+transforms:
+- title: ''
+ date: 2020-09-14
+ element:
+ uris: ['test.dart']
+ method: 'm'
+ inClass: 'C'
+ changes:
+ - kind: addParameter
+ style: named
+ index: 0
+ name: 'p'
+ argumentValue:
+ expression: ''
+''', [
+ error(TransformSetErrorCode.invalidParameterStyle, 171, 5),
+ ]);
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_key_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_key_test.dart
index 148f8a4..1237ba0 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_key_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_key_test.dart
@@ -128,10 +128,9 @@
- kind: 'addTypeParameter'
name: 'a'
argumentValue:
- kind: 'argument'
- index: 0
+ expression: ''
''', [
- error(TransformSetErrorCode.missingKey, 124, 104),
+ error(TransformSetErrorCode.missingKey, 124, 85),
]);
}
@@ -148,10 +147,9 @@
- kind: 'addTypeParameter'
index: 0
argumentValue:
- kind: 'argument'
- index: 0
+ expression: ''
''', [
- error(TransformSetErrorCode.missingKey, 124, 103),
+ error(TransformSetErrorCode.missingKey, 124, 84),
]);
}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_one_of_multiple_keys_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_one_of_multiple_keys_test.dart
new file mode 100644
index 0000000..255767b
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_one_of_multiple_keys_test.dart
@@ -0,0 +1,82 @@
+// 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:analysis_server/src/services/correction/fix/data_driven/transform_set_error_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../transform_set_parser_test_support.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(MissingOneOfMultipleKeysTest);
+ });
+}
+
+@reflectiveTest
+class MissingOneOfMultipleKeysTest extends AbstractTransformSetParserTest {
+ void test_codeTemplate() {
+ assertErrors('''
+version: 1
+transforms:
+- title: ''
+ date: 2020-09-14
+ element:
+ uris: ['test.dart']
+ function: 'f'
+ changes:
+ - kind: addTypeParameter
+ index: 0
+ name: 'T'
+ argumentValue:
+ variables: []
+''', [
+ error(TransformSetErrorCode.missingOneOfMultipleKeys, 207, 14),
+ ]);
+ }
+
+ void test_element() {
+ assertErrors('''
+version: 1
+transforms:
+- title: ''
+ date: 2020-09-14
+ element:
+ uris: ['test.dart']
+ changes: []
+''', [
+ error(TransformSetErrorCode.missingOneOfMultipleKeys, 69, 22),
+ ]);
+ }
+
+ void test_element_container() {
+ assertErrors('''
+version: 1
+transforms:
+- title: ''
+ date: 2020-09-14
+ element:
+ uris: ['test.dart']
+ method: 'm'
+ changes: []
+''', [
+ error(TransformSetErrorCode.missingOneOfMultipleKeys, 69, 38),
+ ]);
+ }
+
+ void test_removeParameterChange() {
+ assertErrors('''
+version: 1
+transforms:
+- title: ''
+ date: 2020-09-14
+ element:
+ uris: ['test.dart']
+ function: 'f'
+ changes:
+ - kind: removeParameter
+''', [
+ error(TransformSetErrorCode.missingOneOfMultipleKeys, 124, 22),
+ ]);
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_uri_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_uri_test.dart
new file mode 100644
index 0000000..ac21bfc
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_uri_test.dart
@@ -0,0 +1,101 @@
+// 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:analysis_server/src/services/correction/fix/data_driven/transform_set_error_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../transform_set_parser_test_support.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(MissingUriTest);
+ });
+}
+
+@reflectiveTest
+class MissingUriTest extends AbstractTransformSetParserTest {
+ void test_element_empty() {
+ assertErrors('''
+version: 1
+transforms:
+- title: ''
+ date: 2020-09-14
+ element:
+ uris: []
+ method: 'm'
+ inClass: 'C'
+ changes: []
+''', [
+ error(TransformSetErrorCode.missingUri, 75, 2),
+ ]);
+ }
+
+ void test_element_nonEmpty() {
+ assertErrors('''
+version: 1
+transforms:
+- title: ''
+ date: 2020-09-14
+ element:
+ uris: [3]
+ method: 'm'
+ inClass: 'C'
+ changes: []
+''', [
+ error(TransformSetErrorCode.invalidValue, 76, 1),
+ ]);
+ }
+
+ void test_import_empty() {
+ assertErrors('''
+version: 1
+transforms:
+- title: ''
+ date: 2020-09-14
+ element:
+ uris: ['']
+ method: 'm'
+ inClass: 'C'
+ changes:
+ - kind: 'addTypeParameter'
+ index: 0
+ name: 'T'
+ argumentValue:
+ expression: ''
+ variables:
+ t:
+ kind: 'import'
+ uris: []
+ name: 'String'
+''', [
+ error(TransformSetErrorCode.missingUri, 307, 2),
+ ]);
+ }
+
+ void test_import_nonEmpty() {
+ assertErrors('''
+version: 1
+transforms:
+- title: ''
+ date: 2020-09-14
+ element:
+ uris: ['']
+ method: 'm'
+ inClass: 'C'
+ changes:
+ - kind: 'addTypeParameter'
+ index: 0
+ name: 'T'
+ argumentValue:
+ expression: ''
+ variables:
+ t:
+ kind: 'import'
+ uris: [3]
+ name: 'String'
+''', [
+ error(TransformSetErrorCode.invalidValue, 308, 1),
+ ]);
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/test_all.dart
index d8b87c6..651508b 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/test_all.dart
@@ -4,29 +4,41 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'conflicting_key_test.dart' as conflicting_key;
import 'invalid_character_test.dart' as invalid_character;
+import 'invalid_key_test.dart' as invalid_key;
+import 'invalid_parameter_style_test.dart' as invalid_parameter_style;
import 'invalid_value_one_of_test.dart' as invalid_value_one_of;
import 'invalid_value_test.dart' as invalid_value;
import 'missing_key_test.dart' as missing_key;
+import 'missing_one_of_multiple_keys_test.dart' as missing_one_of_multiple_keys;
import 'missing_template_end_test.dart' as missing_template_end;
import 'missing_token_test.dart' as missing_token;
+import 'missing_uri_test.dart' as missing_uri;
import 'undefined_variable_test.dart' as undefined_variable;
import 'unknown_accessor_test.dart' as unknown_accessor;
import 'unsupported_key_test.dart' as unsupported_key;
+import 'unsupported_version_test.dart' as unsupported_version;
import 'wrong_token_test.dart' as wrong_token;
import 'yaml_syntax_error_test.dart' as yaml_syntax_error;
void main() {
defineReflectiveSuite(() {
+ conflicting_key.main();
invalid_character.main();
+ invalid_key.main();
+ invalid_parameter_style.main();
invalid_value_one_of.main();
invalid_value.main();
missing_key.main();
+ missing_one_of_multiple_keys.main();
missing_template_end.main();
missing_token.main();
+ missing_uri.main();
undefined_variable.main();
unknown_accessor.main();
unsupported_key.main();
+ unsupported_version.main();
wrong_token.main();
yaml_syntax_error.main();
});
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/unsupported_version_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/unsupported_version_test.dart
new file mode 100644
index 0000000..606341f
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/unsupported_version_test.dart
@@ -0,0 +1,38 @@
+// 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:analysis_server/src/services/correction/fix/data_driven/transform_set_error_code.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_parser.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../transform_set_parser_test_support.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(UnsupportedVersionTest);
+ });
+}
+
+@reflectiveTest
+class UnsupportedVersionTest extends AbstractTransformSetParserTest {
+ void test_tooHigh() {
+ var version = (TransformSetParser.currentVersion + 1).toString();
+ assertErrors('''
+version: $version
+transforms: []
+''', [
+ error(TransformSetErrorCode.unsupportedVersion, 9, version.length),
+ ]);
+ }
+
+ void test_tooLow() {
+ var version = (TransformSetParser.oldestVersion - 1).toString();
+ assertErrors('''
+version: $version
+transforms: []
+''', [
+ error(TransformSetErrorCode.unsupportedVersion, 9, 1),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart b/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
index 0695ce0..00352e2 100644
--- a/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
@@ -719,7 +719,15 @@
var enclosingExecutable = node?.thisOrAncestorMatching((e) {
return e.parent is ClassDeclaration || e.parent is CompilationUnit;
});
- enclosingExecutable?.accept(resolverVisitor);
+
+ if (enclosingExecutable != null) {
+ var enclosingClass = enclosingExecutable.parent;
+ if (enclosingClass is ClassDeclaration) {
+ resolverVisitor.enclosingClass = enclosingClass.declaredElement;
+ }
+
+ enclosingExecutable?.accept(resolverVisitor);
+ }
} else {
unit.accept(resolverVisitor);
}
diff --git a/pkg/analyzer/lib/src/pubspec/pubspec_validator.dart b/pkg/analyzer/lib/src/pubspec/pubspec_validator.dart
index af82bcf..fd22ea0 100644
--- a/pkg/analyzer/lib/src/pubspec/pubspec_validator.dart
+++ b/pkg/analyzer/lib/src/pubspec/pubspec_validator.dart
@@ -248,6 +248,7 @@
var pathEntry = _asString(dependency[PATH_FIELD]);
if (pathEntry != null) {
YamlNode pathKey() => getKey(dependency, PATH_FIELD);
+ YamlNode pathValue() => getValue(dependency, PATH_FIELD);
var context = provider.pathContext;
var normalizedPath = context.joinAll(path.posix.split(pathEntry));
var packageRoot = context.dirname(source.fullName);
@@ -256,13 +257,13 @@
dependencyPath = context.normalize(dependencyPath);
var packageFolder = provider.getFolder(dependencyPath);
if (!packageFolder.exists) {
- _reportErrorForNode(reporter, pathKey(),
+ _reportErrorForNode(reporter, pathValue(),
PubspecWarningCode.PATH_DOES_NOT_EXIST, [pathEntry]);
} else {
if (!packageFolder
.getChild(AnalysisEngine.PUBSPEC_YAML_FILE)
.exists) {
- _reportErrorForNode(reporter, pathKey(),
+ _reportErrorForNode(reporter, pathValue(),
PubspecWarningCode.PATH_PUBSPEC_DOES_NOT_EXIST, [pathEntry]);
}
}
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index e999cd9..9157cbf 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -240,6 +240,7 @@
/// Whether to generate code asserting that non-nullable return values of
/// `@Native` methods or `JS()` invocations are checked for being non-null.
+ /// Emits checks only in sound null-safety.
bool nativeNullAssertions = false;
bool _noNativeNullAssertions = false;
@@ -599,7 +600,9 @@
enableMinification = false;
}
- if (_noNativeNullAssertions) nativeNullAssertions = false;
+ if (_noNativeNullAssertions || nullSafetyMode != NullSafetyMode.sound) {
+ nativeNullAssertions = false;
+ }
}
/// Returns `true` if warnings and hints are shown for all packages.
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 464ff44..8c009af 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -1776,14 +1776,23 @@
js_ast.Fun _emitNativeFunctionBody(Procedure node) {
var name = _annotationName(node, isJSAnnotation) ?? node.name.text;
if (node.isGetter) {
- return js_ast.Fun([], js.block('{ return this.#; }', [name]));
+ var returnValue = js('this.#', [name]);
+ if (_isNullCheckableNative(node)) {
+ // Add a potential null-check on native getter if type is non-nullable.
+ returnValue = runtimeCall('checkNativeNonNull(#)', [returnValue]);
+ }
+ return js_ast.Fun([], js.block('{ return #; }', [returnValue]));
} else if (node.isSetter) {
var params = _emitParameters(node.function);
return js_ast.Fun(
params, js.block('{ this.# = #; }', [name, params.last]));
} else {
- return js.fun(
- 'function (...args) { return this.#.apply(this, args); }', name);
+ var returnValue = js('this.#.apply(this, args)', [name]);
+ if (_isNullCheckableNative(node)) {
+ // Add a potential null-check on return value if type is non-nullable.
+ returnValue = runtimeCall('checkNativeNonNull(#)', [returnValue]);
+ }
+ return js.fun('function (...args) { return #; }', [returnValue]);
}
}
@@ -2270,6 +2279,10 @@
// Fields on a native class are implicitly native.
// Methods/getters/setters are marked external/native.
if (member is Field || _isExternal(member)) {
+ // If the native member needs to be null-checked and we're running in
+ // sound null-safety, we require symbolizing it in order to access the
+ // null-check at the member definition.
+ if (_isNullCheckableNative(member)) return true;
var jsName = _annotationName(member, isJSName);
return jsName != null && jsName != name;
} else {
@@ -4215,14 +4228,8 @@
@override
js_ast.Expression visitPropertyGet(PropertyGet node) {
- var propertyGet =
- _emitPropertyGet(node.receiver, node.interfaceTarget, node.name.text);
- if (_isCheckableNative(node.interfaceTarget)) {
- // If target is a native getter with a non-nullable type, add a null check
- // for soundness.
- return runtimeCall('checkNativeNonNull(#)', [propertyGet]);
- }
- return propertyGet;
+ return _emitPropertyGet(
+ node.receiver, node.interfaceTarget, node.name.text);
}
@override
@@ -4276,8 +4283,11 @@
}
/// Return whether [member] returns a native object whose type needs to be
- /// checked.
- bool _isCheckableNative(Member member) =>
+ /// null-checked in sound null-safety.
+ ///
+ /// This is true for non-nullable native return types.
+ bool _isNullCheckableNative(Member member) =>
+ _options.soundNullSafety &&
member != null &&
member.isExternal &&
_extensionTypes.isNativeClass(member.enclosingClass) &&
@@ -4356,14 +4366,8 @@
@override
js_ast.Expression visitMethodInvocation(MethodInvocation node) {
- var methodCall = _emitMethodCall(
+ return _emitMethodCall(
node.receiver, node.interfaceTarget, node.arguments, node);
- if (_isCheckableNative(node.interfaceTarget)) {
- // If target is a native method with a non-nullable type, add a null check
- // for soundness.
- return runtimeCall('checkNativeNonNull(#)', [methodCall]);
- }
- return methodCall;
}
js_ast.Expression _emitMethodCall(Expression receiver, Member target,
@@ -5092,8 +5096,8 @@
var result = js.parseForeignJS(source).instantiate(jsArgs);
// Add a check to make sure any JS() values from a native type are typed
- // properly.
- if (_isWebLibrary(_currentLibrary.importUri)) {
+ // properly in sound null-safety.
+ if (_isWebLibrary(_currentLibrary.importUri) && _options.soundNullSafety) {
var type = node.getStaticType(_staticTypeContext);
if (type.isPotentiallyNonNullable) {
result = runtimeCall('checkNativeNonNull(#)', [result]);
diff --git a/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart b/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
index de7521d..4be55af 100644
--- a/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
+++ b/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
@@ -142,6 +142,12 @@
"collection": {
ExperimentalFlag.nonNullable,
},
+ "connectivity": {
+ ExperimentalFlag.nonNullable,
+ },
+ "connectivity_platform_interface": {
+ ExperimentalFlag.nonNullable,
+ },
"convert": {
ExperimentalFlag.nonNullable,
},
@@ -154,6 +160,12 @@
"dart_internal": {
ExperimentalFlag.nonNullable,
},
+ "device_info": {
+ ExperimentalFlag.nonNullable,
+ },
+ "device_info_platform_interface": {
+ ExperimentalFlag.nonNullable,
+ },
"fake_async": {
ExperimentalFlag.nonNullable,
},
@@ -217,6 +229,9 @@
"platform": {
ExperimentalFlag.nonNullable,
},
+ "plugin_platform_interface": {
+ ExperimentalFlag.nonNullable,
+ },
"pool": {
ExperimentalFlag.nonNullable,
},
@@ -262,7 +277,31 @@
"typed_data": {
ExperimentalFlag.nonNullable,
},
+ "url_launcher": {
+ ExperimentalFlag.nonNullable,
+ },
+ "url_launcher_linux": {
+ ExperimentalFlag.nonNullable,
+ },
+ "url_launcher_macos": {
+ ExperimentalFlag.nonNullable,
+ },
+ "url_launcher_platform_interface": {
+ ExperimentalFlag.nonNullable,
+ },
+ "url_launcher_windows": {
+ ExperimentalFlag.nonNullable,
+ },
"vector_math": {
ExperimentalFlag.nonNullable,
},
+ "video_player": {
+ ExperimentalFlag.nonNullable,
+ },
+ "video_player_platform_interface": {
+ ExperimentalFlag.nonNullable,
+ },
+ "video_player_web": {
+ ExperimentalFlag.nonNullable,
+ },
});
diff --git a/pkg/front_end/lib/src/base/command_line_options.dart b/pkg/front_end/lib/src/base/command_line_options.dart
index 3f5b1ce..a87824f 100644
--- a/pkg/front_end/lib/src/base/command_line_options.dart
+++ b/pkg/front_end/lib/src/base/command_line_options.dart
@@ -20,7 +20,6 @@
static const String linkDependencies = "--link-dependencies";
- static const String bytecode = "--bytecode";
static const String compileSdk = "--compile-sdk";
static const String dumpIr = "--dump-ir";
static const String enableExperiment = "--enable-experiment";
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 2acc197..1b3dce8 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -223,6 +223,7 @@
config
configs
configured
+connectivity
consideration
constness
consult
@@ -304,6 +305,7 @@
destroy
deterministic
dev
+device
diff
diffs
digest
@@ -590,6 +592,7 @@
lacks
lang
largest
+launcher
lattice
layer
layout
@@ -610,6 +613,7 @@
linearized
linebreak
linter
+linux
lives
ll
llub
@@ -632,6 +636,7 @@
ly
lz
m
+macos
maintaining
mangled
manipulation
@@ -806,6 +811,7 @@
pi
picking
pkg
+player
plugin
pm
pn
@@ -1251,6 +1257,7 @@
verbosity
versa
vice
+video
violated
visit*
visitors
diff --git a/pkg/frontend_server/test/frontend_server_test.dart b/pkg/frontend_server/test/frontend_server_test.dart
index 470e340..9715fb6 100644
--- a/pkg/frontend_server/test/frontend_server_test.dart
+++ b/pkg/frontend_server/test/frontend_server_test.dart
@@ -481,6 +481,8 @@
final platformKernel =
computePlatformBinariesLocation().resolve('vm_platform_strong.dill');
final ddcPlatformKernel =
+ computePlatformBinariesLocation().resolve('ddc_outline_sound.dill');
+ final ddcPlatformKernelWeak =
computePlatformBinariesLocation().resolve('ddc_sdk.dill');
final sdkRoot = computePlatformBinariesLocation();
@@ -496,14 +498,32 @@
test('compile expression', () async {
var file = File('${tempDir.path}/foo.dart')..createSync();
- file.writeAsStringSync("main() {}\n");
+ file.writeAsStringSync("main() {\n}\n");
var dillFile = File('${tempDir.path}/app.dill');
+
+ var package_config =
+ File('${tempDir.path}/.dart_tool/package_config.json')
+ ..createSync(recursive: true)
+ ..writeAsStringSync('''
+ {
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "hello",
+ "rootUri": "../",
+ "packageUri": "./"
+ }
+ ]
+ }
+ ''');
+
expect(dillFile.existsSync(), equals(false));
final List<String> args = <String>[
'--sdk-root=${sdkRoot.toFilePath()}',
'--incremental',
'--platform=${platformKernel.path}',
- '--output-dill=${dillFile.path}'
+ '--output-dill=${dillFile.path}',
+ '--packages=${package_config.path}',
];
final StreamController<List<int>> streamController =
@@ -1714,10 +1734,22 @@
test('compile to JavaScript', () async {
var file = File('${tempDir.path}/foo.dart')..createSync();
- file.writeAsStringSync("main() {}\n");
- var packages = File('${tempDir.path}/.packages')
- ..createSync()
- ..writeAsStringSync("\n");
+ file.writeAsStringSync("main() {\n}\n");
+ var package_config =
+ File('${tempDir.path}/.dart_tool/package_config.json')
+ ..createSync(recursive: true)
+ ..writeAsStringSync('''
+ {
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "hello",
+ "rootUri": "../",
+ "packageUri": "./"
+ }
+ ]
+ }
+ ''');
var dillFile = File('${tempDir.path}/app.dill');
expect(dillFile.existsSync(), false);
@@ -1727,8 +1759,9 @@
'--incremental',
'--platform=${ddcPlatformKernel.path}',
'--output-dill=${dillFile.path}',
- '--packages=${packages.path}',
+ '--packages=${package_config.path}',
'--target=dartdevc',
+ '--enable-experiment=non-nullable',
file.path,
];
@@ -1737,8 +1770,8 @@
test('compile to JavaScript with package scheme', () async {
var file = File('${tempDir.path}/foo.dart')..createSync();
- file.writeAsStringSync("main() {}\n");
- File('${tempDir.path}/.packages')
+ file.writeAsStringSync("main() {\n}\n");
+ var packages = File('${tempDir.path}/.packages')
..createSync()
..writeAsStringSync("hello:${tempDir.uri}\n");
var dillFile = File('${tempDir.path}/app.dill');
@@ -1748,22 +1781,118 @@
final List<String> args = <String>[
'--sdk-root=${sdkRoot.toFilePath()}',
'--incremental',
- '--platform=${ddcPlatformKernel.path}',
+ '--platform=${ddcPlatformKernelWeak.path}',
'--output-dill=${dillFile.path}',
'--target=dartdevc',
- '--packages=${tempDir.path}/.packages',
+ '--packages=${packages.path}',
'package:hello/foo.dart'
];
expect(await starter(args), 0);
- });
+ }, skip: 'https://github.com/dart-lang/sdk/issues/43959');
+
+ test('compile to JavaScript weak null safety', () async {
+ var file = File('${tempDir.path}/foo.dart')..createSync();
+ file.writeAsStringSync("// @dart = 2.9\nmain() {\n}\n");
+ var packages = File('${tempDir.path}/.packages')
+ ..createSync()
+ ..writeAsStringSync("hello:${tempDir.uri}\n");
+ var dillFile = File('${tempDir.path}/app.dill');
+
+ expect(dillFile.existsSync(), false);
+
+ final List<String> args = <String>[
+ '--sdk-root=${sdkRoot.toFilePath()}',
+ '--incremental',
+ '--platform=${ddcPlatformKernelWeak.path}',
+ '--output-dill=${dillFile.path}',
+ '--target=dartdevc',
+ '--packages=${packages.path}',
+ 'package:hello/foo.dart'
+ ];
+
+ expect(await starter(args), 0);
+ }, skip: 'https://github.com/dart-lang/sdk/issues/43959');
+
+ test('compile to JavaScript weak null safety then non-existent file',
+ () async {
+ var file = File('${tempDir.path}/foo.dart')..createSync();
+ file.writeAsStringSync("// @dart = 2.9\nmain() {\n}\n");
+ var packages = File('${tempDir.path}/.packages')
+ ..createSync()
+ ..writeAsStringSync("hello:${tempDir.uri}\n");
+ var dillFile = File('${tempDir.path}/app.dill');
+
+ expect(dillFile.existsSync(), false);
+
+ var library = 'package:hello/foo.dart';
+
+ final List<String> args = <String>[
+ '--sdk-root=${sdkRoot.toFilePath()}',
+ '--incremental',
+ '--platform=${ddcPlatformKernelWeak.path}',
+ '--output-dill=${dillFile.path}',
+ '--target=dartdevc',
+ '--packages=${packages.path}',
+ ];
+
+ final StreamController<List<int>> streamController =
+ StreamController<List<int>>();
+ final StreamController<List<int>> stdoutStreamController =
+ StreamController<List<int>>();
+ final IOSink ioSink = IOSink(stdoutStreamController.sink);
+ StreamController<Result> receivedResults = StreamController<Result>();
+ final outputParser = OutputParser(receivedResults);
+ stdoutStreamController.stream
+ .transform(utf8.decoder)
+ .transform(const LineSplitter())
+ .listen(outputParser.listener);
+
+ Future<int> result =
+ starter(args, input: streamController.stream, output: ioSink);
+ streamController.add('compile $library\n'.codeUnits);
+ var count = 0;
+ receivedResults.stream.listen((Result compiledResult) {
+ CompilationResult result =
+ CompilationResult.parse(compiledResult.status);
+ count++;
+ if (count == 1) {
+ // First request is to 'compile', which results in full JavaScript
+ expect(result.errorsCount, equals(0));
+ expect(result.filename, dillFile.path);
+ streamController.add('accept\n'.codeUnits);
+ streamController.add('compile foo.bar\n'.codeUnits);
+ } else {
+ expect(count, 2);
+ // Second request is to 'compile' non-existent file, that should fail.
+ expect(result.errorsCount, greaterThan(0));
+ streamController.add('quit\n'.codeUnits);
+ }
+ });
+
+ expect(await result, 0);
+ expect(count, 2);
+ }, skip: 'https://github.com/dart-lang/sdk/issues/43959');
test('compile to JavaScript with no metadata', () async {
var file = File('${tempDir.path}/foo.dart')..createSync();
file.writeAsStringSync("main() {\n\n}\n");
- File('${tempDir.path}/.packages')
- ..createSync()
- ..writeAsStringSync("hello:${tempDir.uri}\n");
+
+ var package_config =
+ File('${tempDir.path}/.dart_tool/package_config.json')
+ ..createSync(recursive: true)
+ ..writeAsStringSync('''
+ {
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "hello",
+ "rootUri": "../",
+ "packageUri": "./"
+ }
+ ]
+ }
+ ''');
var library = 'package:hello/foo.dart';
@@ -1785,7 +1914,8 @@
'--platform=${ddcPlatformKernel.path}',
'--output-dill=${dillFile.path}',
'--target=dartdevc',
- '--packages=${tempDir.path}/.packages',
+ '--packages=${package_config.path}',
+ '--enable-experiment=non-nullable',
];
final StreamController<List<int>> streamController =
@@ -1827,9 +1957,21 @@
test('compile to JavaScript with metadata', () async {
var file = File('${tempDir.path}/foo.dart')..createSync();
file.writeAsStringSync("main() {\n\n}\n");
- File('${tempDir.path}/.packages')
- ..createSync()
- ..writeAsStringSync("hello:${tempDir.uri}\n");
+ var package_config =
+ File('${tempDir.path}/.dart_tool/package_config.json')
+ ..createSync(recursive: true)
+ ..writeAsStringSync('''
+ {
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "hello",
+ "rootUri": "../",
+ "packageUri": "./"
+ }
+ ]
+ }
+ ''');
var library = 'package:hello/foo.dart';
@@ -1851,8 +1993,9 @@
'--platform=${ddcPlatformKernel.path}',
'--output-dill=${dillFile.path}',
'--target=dartdevc',
- '--packages=${tempDir.path}/.packages',
- '--experimental-emit-debug-metadata'
+ '--packages=${package_config.path}',
+ '--experimental-emit-debug-metadata',
+ '--enable-experiment=non-nullable',
];
final StreamController<List<int>> streamController =
@@ -1893,10 +2036,22 @@
test('compile expression to Javascript', () async {
var file = File('${tempDir.path}/foo.dart')..createSync();
- file.writeAsStringSync("main() {\n\n}\n");
- File('${tempDir.path}/.packages')
- ..createSync()
- ..writeAsStringSync("hello:${tempDir.uri}\n");
+ file.writeAsStringSync("main() {\n}\n");
+ var package_config =
+ File('${tempDir.path}/.dart_tool/package_config.json')
+ ..createSync(recursive: true)
+ ..writeAsStringSync('''
+ {
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "hello",
+ "rootUri": "../",
+ "packageUri": "./"
+ }
+ ]
+ }
+ ''');
var library = 'package:hello/foo.dart';
var module = 'packages/hello/foo.dart';
@@ -1914,7 +2069,8 @@
'--platform=${ddcPlatformKernel.path}',
'--output-dill=${dillFile.path}',
'--target=dartdevc',
- '--packages=${tempDir.path}/.packages',
+ '--packages=${package_config.path}',
+ '--enable-experiment=non-nullable',
];
final StreamController<List<int>> streamController =
@@ -1959,7 +2115,7 @@
// expression
outputParser.expectSources = false;
streamController.add('compile-expression-to-js abc\n'
- '$library\n1\n1\nabc\nabc\n$module\n\n'
+ '$library\n2\n1\nabc\nabc\n$module\n\n'
.codeUnits);
count += 1;
} else if (count == 1) {
@@ -1972,7 +2128,7 @@
outputParser.expectSources = false;
streamController.add('compile-expression-to-js abc\n'
- '$library\n1\n1\nabc\nabc\n$module\n2+2\n'
+ '$library\n2\n1\nabc\nabc\n$module\n2+2\n'
.codeUnits);
count += 1;
} else if (count == 2) {
@@ -2001,10 +2157,21 @@
test('mixed compile expression commands with web target', () async {
var file = File('${tempDir.path}/foo.dart')..createSync();
file.writeAsStringSync("main() {\n\n}\n");
- File('${tempDir.path}/.packages')
- ..createSync()
- ..writeAsStringSync("hello:${tempDir.uri}\n");
-
+ var package_config =
+ File('${tempDir.path}/.dart_tool/package_config.json')
+ ..createSync(recursive: true)
+ ..writeAsStringSync('''
+ {
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "hello",
+ "rootUri": "../",
+ "packageUri": "./"
+ }
+ ]
+ }
+ ''');
var library = 'package:hello/foo.dart';
var module = 'packages/hello/foo.dart';
@@ -2021,7 +2188,8 @@
'--platform=${ddcPlatformKernel.path}',
'--output-dill=${dillFile.path}',
'--target=dartdevc',
- '--packages=${tempDir.path}/.packages',
+ '--packages=${package_config.path}',
+ '--enable-experiment=non-nullable'
];
final StreamController<List<int>> streamController =
@@ -2066,7 +2234,7 @@
// expression
outputParser.expectSources = false;
streamController.add('compile-expression-to-js abc\n'
- '$library\n1\n1\nabc\nabc\n$module\n2+2\n'
+ '$library\n2\n1\nabc\nabc\n$module\n2+2\n'
.codeUnits);
count += 1;
} else if (count == 1) {
@@ -2103,7 +2271,7 @@
outputParser.expectSources = false;
streamController.add('compile-expression-to-js abc\n'
- '$library\n1\n1\nabc\nabc\n$module\n2+2\n'
+ '$library\n2\n1\nabc\nabc\n$module\n2+2\n'
.codeUnits);
count += 1;
} else if (count == 3) {
diff --git a/pkg/test_runner/lib/src/options.dart b/pkg/test_runner/lib/src/options.dart
index 7f3aed5..91a6317 100644
--- a/pkg/test_runner/lib/src/options.dart
+++ b/pkg/test_runner/lib/src/options.dart
@@ -387,12 +387,31 @@
};
/// The set of objects which the named configuration should imply.
- static final _namedConfigurationOptions = {
+ static const _namedConfigurationOptions = {
'system',
'arch',
'mode',
'compiler',
'runtime',
+ 'timeout',
+ 'nnbd',
+ 'sanitizer',
+ 'enable_asserts',
+ 'use_cfe',
+ 'analyzer_use_fasta_parser',
+ 'use_elf',
+ 'use_sdk',
+ 'hot_reload',
+ 'hot_reload_rollback',
+ 'host_checked',
+ 'csp',
+ 'minified',
+ 'vm_options',
+ 'dart2js_options',
+ 'experiments',
+ 'babel',
+ 'builder_tag',
+ 'use_qemu'
};
/// Parses a list of strings as test options.
@@ -557,8 +576,8 @@
for (var optionName in _namedConfigurationOptions) {
if (options.containsKey(optionName)) {
var namedConfig = options['named_configuration'];
- _fail("The named configuration '$namedConfig' implies "
- "'$optionName'. Try removing '$optionName'.");
+ _fail("Can't pass '--$optionName' since it is determined by the "
+ "named configuration '$namedConfig'.");
}
}
}
diff --git a/pkg/test_runner/tool/update_static_error_tests.dart b/pkg/test_runner/tool/update_static_error_tests.dart
index 6b7379a..5364fc2 100644
--- a/pkg/test_runner/tool/update_static_error_tests.dart
+++ b/pkg/test_runner/tool/update_static_error_tests.dart
@@ -303,7 +303,7 @@
/// Find the most recently-built [binary] in any of the build directories.
String _findBinary(String name, String windowsExtension) {
- String binary = Platform.isWindows ? "$name.$windowsExtension" : name;
+ var binary = Platform.isWindows ? "$name.$windowsExtension" : name;
String newestPath;
DateTime newestTime;
diff --git a/pkg/vm/lib/metadata/procedure_attributes.dart b/pkg/vm/lib/metadata/procedure_attributes.dart
index 99a0023..d6840f2 100644
--- a/pkg/vm/lib/metadata/procedure_attributes.dart
+++ b/pkg/vm/lib/metadata/procedure_attributes.dart
@@ -122,13 +122,4 @@
methodOrSetterSelectorId: methodOrSetterSelectorId,
getterSelectorId: getterSelectorId);
}
-
- /// Converts [metadata] into a bytecode attribute.
- Constant getBytecodeAttribute(ProcedureAttributesMetadata metadata) {
- return ListConstant(const DynamicType(), [
- IntConstant(_getFlags(metadata)),
- IntConstant(metadata.methodOrSetterSelectorId),
- IntConstant(metadata.getterSelectorId),
- ]);
- }
}
diff --git a/pkg/vm/lib/target/vm.dart b/pkg/vm/lib/target/vm.dart
index 174a310..97cf03a 100644
--- a/pkg/vm/lib/target/vm.dart
+++ b/pkg/vm/lib/target/vm.dart
@@ -132,8 +132,6 @@
// need to index dart:collection, as it is only needed for desugaring of
// const sets. We can remove it from this list at that time.
"dart:collection",
- // The bytecode pipeline uses the index to check if dart:ffi is used.
- "dart:ffi",
// TODO(askesc): This is for the VM host endian optimization, which
// could possibly be done more cleanly after the VM no longer supports
// doing constant evaluation on its own. See http://dartbug.com/32836
diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md
index 9299ed5..bbb753e 100644
--- a/pkg/vm_service/CHANGELOG.md
+++ b/pkg/vm_service/CHANGELOG.md
@@ -1,4 +1,12 @@
# Changelog
+
+## 5.4.0
+- Update to version `3.41.0` of the spec.
+- Added `PortList` class.
+- Added `getPorts` RPC.
+- Added optional properties `portId`, `allocationLocation`, and `debugName` to
+ `InstanceRef` and `Instance`.
+
## 5.3.1
- Rename `State` class to `_State` to avoid class name conflicts with Flutter.
@@ -6,7 +14,6 @@
- Added support for `dart:io` extensions version 1.5.
- Added combination getter/setter `socketProfilingEnabled`.
- Deprecated `startSocketProfiling` and `pauseSocketProfiling`.
-- Added support for `dart:io` extensions version 1.4.
- Update to version `3.40.0` of the spec.
- Added `IsolateFlag` class.
- Added `isolateFlags` property to `Isolate`.
diff --git a/pkg/vm_service/example/vm_service_assert.dart b/pkg/vm_service/example/vm_service_assert.dart
index e2ae6d1..617bd7c 100644
--- a/pkg/vm_service/example/vm_service_assert.dart
+++ b/pkg/vm_service/example/vm_service_assert.dart
@@ -192,6 +192,7 @@
if (obj == "MirrorReference") return obj;
if (obj == "Null") return obj;
if (obj == "PlainInstance") return obj;
+ if (obj == "ReceivePort") return obj;
if (obj == "RegExp") return obj;
if (obj == "StackTrace") return obj;
if (obj == "String") return obj;
@@ -912,6 +913,13 @@
return obj;
}
+vms.PortList assertPortList(vms.PortList obj) {
+ assertNotNull(obj);
+ assertString(obj.type);
+ assertListOfInstanceRef(obj.ports);
+ return obj;
+}
+
vms.ProfileFunction assertProfileFunction(vms.ProfileFunction obj) {
assertNotNull(obj);
assertString(obj.kind);
diff --git a/pkg/vm_service/java/.gitignore b/pkg/vm_service/java/.gitignore
index ae6691f..8803d45 100644
--- a/pkg/vm_service/java/.gitignore
+++ b/pkg/vm_service/java/.gitignore
@@ -25,6 +25,7 @@
src/org/dartlang/vm/service/consumer/InvokeConsumer.java
src/org/dartlang/vm/service/consumer/KillConsumer.java
src/org/dartlang/vm/service/consumer/PauseConsumer.java
+src/org/dartlang/vm/service/consumer/PortListConsumer.java
src/org/dartlang/vm/service/consumer/ProcessMemoryUsageConsumer.java
src/org/dartlang/vm/service/consumer/ProtocolListConsumer.java
src/org/dartlang/vm/service/consumer/ReloadSourcesConsumer.java
@@ -95,6 +96,7 @@
src/org/dartlang/vm/service/element/NullRef.java
src/org/dartlang/vm/service/element/Obj.java
src/org/dartlang/vm/service/element/ObjRef.java
+src/org/dartlang/vm/service/element/PortList.java
src/org/dartlang/vm/service/element/ProcessMemoryItem.java
src/org/dartlang/vm/service/element/ProcessMemoryUsage.java
src/org/dartlang/vm/service/element/ProfileFunction.java
diff --git a/pkg/vm_service/java/version.properties b/pkg/vm_service/java/version.properties
index d0564a6..ae41aeb 100644
--- a/pkg/vm_service/java/version.properties
+++ b/pkg/vm_service/java/version.properties
@@ -1 +1 @@
-version=3.40
+version=3.41
diff --git a/pkg/vm_service/lib/src/vm_service.dart b/pkg/vm_service/lib/src/vm_service.dart
index fd20c5b..4dfc752 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 = '3.40.0';
+const String vmServiceVersion = '3.41.0';
/// @optional
const String optional = 'optional';
@@ -157,6 +157,7 @@
'Null': NullVal.parse,
'@Object': ObjRef.parse,
'Object': Obj.parse,
+ 'PortList': PortList.parse,
'ProfileFunction': ProfileFunction.parse,
'ProtocolList': ProtocolList.parse,
'Protocol': Protocol.parse,
@@ -209,6 +210,7 @@
'getIsolateGroupMemoryUsage': const ['MemoryUsage'],
'getScripts': const ['ScriptList'],
'getObject': const ['Obj'],
+ 'getPorts': const ['PortList'],
'getRetainingPath': const ['RetainingPath'],
'getProcessMemoryUsage': const ['ProcessMemoryUsage'],
'getStack': const ['Stack'],
@@ -688,6 +690,12 @@
int count,
});
+ /// The `getPorts` RPC is used to retrieve the list of `ReceivePort` instances
+ /// for a given isolate.
+ ///
+ /// See [PortList].
+ Future<PortList> getPorts(String isolateId);
+
/// The `getRetainingPath` RPC is used to lookup a path from an object
/// specified by `targetId` to a GC root (i.e., the object which is preventing
/// this object from being garbage collected).
@@ -1318,6 +1326,11 @@
count: params['count'],
);
break;
+ case 'getPorts':
+ response = await _serviceImplementation.getPorts(
+ params['isolateId'],
+ );
+ break;
case 'getRetainingPath':
response = await _serviceImplementation.getRetainingPath(
params['isolateId'],
@@ -1771,6 +1784,10 @@
});
@override
+ Future<PortList> getPorts(String isolateId) =>
+ _call('getPorts', {'isolateId': isolateId});
+
+ @override
Future<RetainingPath> getRetainingPath(
String isolateId, String targetId, int limit) =>
_call('getRetainingPath',
@@ -2432,6 +2449,9 @@
/// An instance of the Dart class BoundedType.
static const String kBoundedType = 'BoundedType';
+
+ /// An instance of the Dart class ReceivePort.
+ static const String kReceivePort = 'ReceivePort';
}
/// A `SentinelKind` is used to distinguish different kinds of `Sentinel`
@@ -4239,6 +4259,27 @@
@optional
ContextRef closureContext;
+ /// The port ID for a ReceivePort.
+ ///
+ /// Provided for instance kinds:
+ /// - ReceivePort
+ @optional
+ int portId;
+
+ /// The stack trace associated with the allocation of a ReceivePort.
+ ///
+ /// Provided for instance kinds:
+ /// - ReceivePort
+ @optional
+ InstanceRef allocationLocation;
+
+ /// A name associated with a ReceivePort used for debugging purposes.
+ ///
+ /// Provided for instance kinds:
+ /// - ReceivePort
+ @optional
+ String debugName;
+
InstanceRef({
@required this.kind,
@required this.classRef,
@@ -4252,6 +4293,9 @@
this.pattern,
this.closureFunction,
this.closureContext,
+ this.portId,
+ this.allocationLocation,
+ this.debugName,
}) : super(id: id);
InstanceRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
@@ -4269,6 +4313,10 @@
createServiceObject(json['closureFunction'], const ['FuncRef']);
closureContext =
createServiceObject(json['closureContext'], const ['ContextRef']);
+ portId = json['portId'];
+ allocationLocation =
+ createServiceObject(json['allocationLocation'], const ['InstanceRef']);
+ debugName = json['debugName'];
}
@override
@@ -4288,6 +4336,9 @@
_setIfNotNull(json, 'pattern', pattern?.toJson());
_setIfNotNull(json, 'closureFunction', closureFunction?.toJson());
_setIfNotNull(json, 'closureContext', closureContext?.toJson());
+ _setIfNotNull(json, 'portId', portId);
+ _setIfNotNull(json, 'allocationLocation', allocationLocation?.toJson());
+ _setIfNotNull(json, 'debugName', debugName);
return json;
}
@@ -4318,6 +4369,7 @@
/// - Double (suitable for passing to Double.parse())
/// - Int (suitable for passing to int.parse())
/// - String (value may be truncated)
+ /// - StackTrace
@optional
String valueAsString;
@@ -4554,6 +4606,27 @@
@optional
InstanceRef bound;
+ /// The port ID for a ReceivePort.
+ ///
+ /// Provided for instance kinds:
+ /// - ReceivePort
+ @optional
+ int portId;
+
+ /// The stack trace associated with the allocation of a ReceivePort.
+ ///
+ /// Provided for instance kinds:
+ /// - ReceivePort
+ @optional
+ InstanceRef allocationLocation;
+
+ /// A name associated with a ReceivePort used for debugging purposes.
+ ///
+ /// Provided for instance kinds:
+ /// - ReceivePort
+ @optional
+ String debugName;
+
Instance({
@required this.kind,
@required this.classRef,
@@ -4582,6 +4655,9 @@
this.parameterIndex,
this.targetType,
this.bound,
+ this.portId,
+ this.allocationLocation,
+ this.debugName,
}) : super(id: id);
Instance._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
@@ -4627,6 +4703,10 @@
parameterIndex = json['parameterIndex'];
targetType = createServiceObject(json['targetType'], const ['InstanceRef']);
bound = createServiceObject(json['bound'], const ['InstanceRef']);
+ portId = json['portId'];
+ allocationLocation =
+ createServiceObject(json['allocationLocation'], const ['InstanceRef']);
+ debugName = json['debugName'];
}
@override
@@ -4663,6 +4743,9 @@
_setIfNotNull(json, 'parameterIndex', parameterIndex);
_setIfNotNull(json, 'targetType', targetType?.toJson());
_setIfNotNull(json, 'bound', bound?.toJson());
+ _setIfNotNull(json, 'portId', portId);
+ _setIfNotNull(json, 'allocationLocation', allocationLocation?.toJson());
+ _setIfNotNull(json, 'debugName', debugName);
return json;
}
@@ -5743,6 +5826,37 @@
String toString() => '[Obj type: ${type}, id: ${id}]';
}
+/// A `PortList` contains a list of ports associated with some isolate.
+///
+/// See [getPort].
+class PortList extends Response {
+ static PortList parse(Map<String, dynamic> json) =>
+ json == null ? null : PortList._fromJson(json);
+
+ List<InstanceRef> ports;
+
+ PortList({
+ @required this.ports,
+ });
+
+ PortList._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
+ ports = List<InstanceRef>.from(
+ createServiceObject(json['ports'], const ['InstanceRef']) ?? []);
+ }
+
+ @override
+ Map<String, dynamic> toJson() {
+ var json = <String, dynamic>{};
+ json['type'] = 'PortList';
+ json.addAll({
+ 'ports': ports.map((f) => f.toJson()).toList(),
+ });
+ return json;
+ }
+
+ String toString() => '[PortList type: ${type}, ports: ${ports}]';
+}
+
/// A `ProfileFunction` contains profiling information about a Dart or native
/// function.
///
diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml
index 7d0d07a..0c77a68 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.3.1
+version: 5.4.0
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service
diff --git a/runtime/lib/ffi.cc b/runtime/lib/ffi.cc
index b514b86..918b045 100644
--- a/runtime/lib/ffi.cc
+++ b/runtime/lib/ffi.cc
@@ -35,10 +35,6 @@
// Some checks are only performed at runtime to allow for generic code, these
// throw ArgumentExceptions.
-static bool IsPointerType(const AbstractType& type) {
- return IsFfiPointerClassId(type.type_class_id());
-}
-
static void CheckSized(const AbstractType& type_arg) {
const classid_t type_cid = type_arg.type_class_id();
if (IsFfiNativeTypeTypeClassId(type_cid) || IsFfiTypeVoidClassId(type_cid) ||
@@ -54,26 +50,6 @@
}
}
-// The following functions are runtime checks on arguments.
-
-static const Integer& AsInteger(const Instance& instance) {
- if (!instance.IsInteger()) {
- const String& error = String::Handle(String::NewFormatted(
- "Expected an int but found %s", instance.ToCString()));
- Exceptions::ThrowArgumentError(error);
- }
- return Integer::Cast(instance);
-}
-
-static const Double& AsDouble(const Instance& instance) {
- if (!instance.IsDouble()) {
- const String& error = String::Handle(String::NewFormatted(
- "Expected a double but found %s", instance.ToCString()));
- Exceptions::ThrowArgumentError(error);
- }
- return Double::Cast(instance);
-}
-
// Calculate the size of a native type.
//
// You must check [IsConcreteNativeType] and [CheckSized] first to verify that
@@ -96,75 +72,20 @@
// The remainder of this file implements the dart:ffi native methods.
DEFINE_NATIVE_ENTRY(Ffi_fromAddress, 1, 1) {
- GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0));
- GET_NON_NULL_NATIVE_ARGUMENT(Integer, arg_ptr, arguments->NativeArgAt(0));
- return Pointer::New(type_arg, arg_ptr.AsInt64Value());
+ UNREACHABLE();
}
DEFINE_NATIVE_ENTRY(Ffi_address, 0, 1) {
- GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
- return Integer::New(pointer.NativeAddress());
-}
-
-static ObjectPtr LoadValueNumeric(Zone* zone,
- const Pointer& target,
- classid_t type_cid,
- const Integer& offset) {
- // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr.
- const size_t address =
- target.NativeAddress() + static_cast<intptr_t>(offset.AsInt64Value());
- switch (type_cid) {
- case kFfiInt8Cid:
- return Integer::New(*reinterpret_cast<int8_t*>(address));
- case kFfiInt16Cid:
- return Integer::New(*reinterpret_cast<int16_t*>(address));
- case kFfiInt32Cid:
- return Integer::New(*reinterpret_cast<int32_t*>(address));
- case kFfiInt64Cid:
- return Integer::New(*reinterpret_cast<int64_t*>(address));
- case kFfiUint8Cid:
- return Integer::NewFromUint64(*reinterpret_cast<uint8_t*>(address));
- case kFfiUint16Cid:
- return Integer::NewFromUint64(*reinterpret_cast<uint16_t*>(address));
- case kFfiUint32Cid:
- return Integer::NewFromUint64(*reinterpret_cast<uint32_t*>(address));
- case kFfiUint64Cid:
- return Integer::NewFromUint64(*reinterpret_cast<uint64_t*>(address));
- case kFfiIntPtrCid:
- return Integer::New(*reinterpret_cast<intptr_t*>(address));
- case kFfiFloatCid:
- return Double::New(*reinterpret_cast<float_t*>(address));
- case kFfiDoubleCid:
- return Double::New(*reinterpret_cast<double_t*>(address));
- default:
- UNREACHABLE();
- }
+ UNREACHABLE();
}
#define DEFINE_NATIVE_ENTRY_LOAD(type) \
- DEFINE_NATIVE_ENTRY(Ffi_load##type, 0, 2) { \
- GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0)); \
- GET_NON_NULL_NATIVE_ARGUMENT(Integer, offset, arguments->NativeArgAt(1)); \
- return LoadValueNumeric(zone, pointer, kFfi##type##Cid, offset); \
- }
+ DEFINE_NATIVE_ENTRY(Ffi_load##type, 0, 2) { UNREACHABLE(); }
CLASS_LIST_FFI_NUMERIC(DEFINE_NATIVE_ENTRY_LOAD)
#undef DEFINE_NATIVE_ENTRY_LOAD
DEFINE_NATIVE_ENTRY(Ffi_loadPointer, 1, 2) {
- GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
- GET_NON_NULL_NATIVE_ARGUMENT(Integer, offset, arguments->NativeArgAt(1));
-
- const auto& pointer_type_arg =
- AbstractType::Handle(zone, pointer.type_argument());
- const AbstractType& type_arg =
- AbstractType::Handle(TypeArguments::Handle(pointer_type_arg.arguments())
- .TypeAt(Pointer::kNativeTypeArgPos));
-
- // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr.
- const size_t address =
- pointer.NativeAddress() + static_cast<intptr_t>(offset.AsInt64Value());
-
- return Pointer::New(type_arg, *reinterpret_cast<uword*>(address));
+ UNREACHABLE();
}
static ObjectPtr LoadValueStruct(Zone* zone,
@@ -208,95 +129,13 @@
return LoadValueStruct(zone, pointer_offset, pointer_type_arg);
}
-static void StoreValueNumeric(Zone* zone,
- const Pointer& pointer,
- classid_t type_cid,
- const Integer& offset,
- const Instance& new_value) {
- // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr.
- const size_t address =
- pointer.NativeAddress() + static_cast<intptr_t>(offset.AsInt64Value());
- switch (type_cid) {
- case kFfiInt8Cid:
- *reinterpret_cast<int8_t*>(address) = AsInteger(new_value).AsInt64Value();
- break;
- case kFfiInt16Cid:
- *reinterpret_cast<int16_t*>(address) =
- AsInteger(new_value).AsInt64Value();
- break;
- case kFfiInt32Cid:
- *reinterpret_cast<int32_t*>(address) =
- AsInteger(new_value).AsInt64Value();
- break;
- case kFfiInt64Cid:
- *reinterpret_cast<int64_t*>(address) =
- AsInteger(new_value).AsInt64Value();
- break;
- case kFfiUint8Cid:
- *reinterpret_cast<uint8_t*>(address) =
- AsInteger(new_value).AsInt64Value();
- break;
- case kFfiUint16Cid:
- *reinterpret_cast<uint16_t*>(address) =
- AsInteger(new_value).AsInt64Value();
- break;
- case kFfiUint32Cid:
- *reinterpret_cast<uint32_t*>(address) =
- AsInteger(new_value).AsInt64Value();
- break;
- case kFfiUint64Cid:
- *reinterpret_cast<uint64_t*>(address) =
- AsInteger(new_value).AsInt64Value();
- break;
- case kFfiIntPtrCid:
- *reinterpret_cast<intptr_t*>(address) =
- AsInteger(new_value).AsInt64Value();
- break;
- case kFfiFloatCid:
- *reinterpret_cast<float*>(address) = AsDouble(new_value).value();
- break;
- case kFfiDoubleCid:
- *reinterpret_cast<double*>(address) = AsDouble(new_value).value();
- break;
- default:
- UNREACHABLE();
- }
-}
-
#define DEFINE_NATIVE_ENTRY_STORE(type) \
- DEFINE_NATIVE_ENTRY(Ffi_store##type, 0, 3) { \
- GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0)); \
- GET_NON_NULL_NATIVE_ARGUMENT(Integer, offset, arguments->NativeArgAt(1)); \
- GET_NON_NULL_NATIVE_ARGUMENT(Instance, value, arguments->NativeArgAt(2)); \
- StoreValueNumeric(zone, pointer, kFfi##type##Cid, offset, value); \
- return Object::null(); \
- }
+ DEFINE_NATIVE_ENTRY(Ffi_store##type, 0, 3) { UNREACHABLE(); }
CLASS_LIST_FFI_NUMERIC(DEFINE_NATIVE_ENTRY_STORE)
#undef DEFINE_NATIVE_ENTRY_STORE
DEFINE_NATIVE_ENTRY(Ffi_storePointer, 0, 3) {
- GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
- GET_NON_NULL_NATIVE_ARGUMENT(Integer, offset, arguments->NativeArgAt(1));
- GET_NON_NULL_NATIVE_ARGUMENT(Pointer, new_value, arguments->NativeArgAt(2));
- AbstractType& pointer_type_arg =
- AbstractType::Handle(pointer.type_argument());
-
- auto& new_value_type =
- AbstractType::Handle(zone, new_value.GetType(Heap::kNew));
- if (!new_value_type.IsSubtypeOf(pointer_type_arg, Heap::kNew)) {
- const String& error = String::Handle(String::NewFormatted(
- "New value (%s) is not a subtype of '%s'.",
- String::Handle(new_value_type.UserVisibleName()).ToCString(),
- String::Handle(pointer_type_arg.UserVisibleName()).ToCString()));
- Exceptions::ThrowArgumentError(error);
- }
-
- ASSERT(IsPointerType(pointer_type_arg));
- // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr.
- const size_t address =
- pointer.NativeAddress() + static_cast<intptr_t>(offset.AsInt64Value());
- *reinterpret_cast<uword*>(address) = new_value.NativeAddress();
- return Object::null();
+ UNREACHABLE();
}
DEFINE_NATIVE_ENTRY(Ffi_sizeOf, 1, 0) {
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index 4b381cb..905cb26 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -51,11 +51,12 @@
return Smi::New(hash);
}
-DEFINE_NATIVE_ENTRY(RawReceivePortImpl_factory, 0, 1) {
+DEFINE_NATIVE_ENTRY(RawReceivePortImpl_factory, 0, 2) {
ASSERT(
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(0)).IsNull());
+ GET_NON_NULL_NATIVE_ARGUMENT(String, debug_name, arguments->NativeArgAt(1));
Dart_Port port_id = PortMap::CreatePort(isolate->message_handler());
- return ReceivePort::New(port_id, false /* not control port */);
+ return ReceivePort::New(port_id, debug_name, false /* not control port */);
}
DEFINE_NATIVE_ENTRY(RawReceivePortImpl_get_id, 0, 1) {
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 625ca6c..cf1e6ff 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -255,7 +255,7 @@
}
DEFINE_NATIVE_ENTRY(Internal_reachabilityFence, 0, 1) {
- return Object::null();
+ UNREACHABLE();
}
DEFINE_NATIVE_ENTRY(Internal_collectAllGarbage, 0, 0) {
diff --git a/runtime/lib/stacktrace.cc b/runtime/lib/stacktrace.cc
index 43383d4..3eabaf4 100644
--- a/runtime/lib/stacktrace.cc
+++ b/runtime/lib/stacktrace.cc
@@ -214,4 +214,12 @@
return stacktrace;
}
+bool HasStack() {
+ Thread* thread = Thread::Current();
+ StackFrameIterator frames(ValidationPolicy::kDontValidateFrames, thread,
+ StackFrameIterator::kNoCrossThreadIteration);
+ StackFrame* frame = frames.NextFrame();
+ return frame != nullptr;
+}
+
} // namespace dart
diff --git a/runtime/lib/stacktrace.h b/runtime/lib/stacktrace.h
index 9c8abae..a804d62 100644
--- a/runtime/lib/stacktrace.h
+++ b/runtime/lib/stacktrace.h
@@ -21,6 +21,9 @@
// Creates a StackTrace object to be attached to an exception.
StackTracePtr GetStackTraceForException();
+// Returns false if there is no Dart stack available.
+bool HasStack();
+
} // namespace dart
#endif // RUNTIME_LIB_STACKTRACE_H_
diff --git a/runtime/observatory/lib/src/models/objects/instance.dart b/runtime/observatory/lib/src/models/objects/instance.dart
index ab8d6d6..a0400c5 100644
--- a/runtime/observatory/lib/src/models/objects/instance.dart
+++ b/runtime/observatory/lib/src/models/objects/instance.dart
@@ -120,6 +120,9 @@
/// An instance of the Dart class TypeRef.
typeRef,
+
+ /// An instance of the Dart class RawReceivePort
+ receivePort,
}
bool isTypedData(InstanceKind? kind) {
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 4f9ead0..55c9d13 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -2781,6 +2781,8 @@
return M.InstanceKind.typeParameter;
case 'TypeRef':
return M.InstanceKind.typeRef;
+ case 'ReceivePort':
+ return M.InstanceKind.receivePort;
}
var message = 'Unrecognized instance kind: $s';
Logger.root.severe(message);
diff --git a/runtime/observatory/tests/service/get_ports_public_rpc_test.dart b/runtime/observatory/tests/service/get_ports_public_rpc_test.dart
new file mode 100644
index 0000000..cc511f7
--- /dev/null
+++ b/runtime/observatory/tests/service/get_ports_public_rpc_test.dart
@@ -0,0 +1,50 @@
+// 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 'dart:isolate' hide Isolate;
+import 'package:observatory/service_io.dart';
+import 'package:test/test.dart';
+
+import 'test_helper.dart';
+
+var port1;
+var port2;
+var port3;
+
+void warmup() {
+ port1 = RawReceivePort(null, 'port1');
+ port2 = RawReceivePort((_) {});
+ port3 = RawReceivePort((_) {}, 'port3');
+ port3.close();
+ RawReceivePort((_) {}, 'port4');
+}
+
+int countNameMatches(ports, name) {
+ var matches = 0;
+ for (var port in ports) {
+ if (port['debugName'] == name) {
+ matches++;
+ }
+ }
+ return matches;
+}
+
+final tests = <IsolateTest>[
+ (Isolate isolate) async {
+ dynamic result = await isolate.invokeRpcNoUpgrade('getPorts', {});
+ expect(result['type'], 'PortList');
+ expect(result['ports'], isList);
+ final ports = result['ports'];
+ // There are at least three ports: the three created in warm up that
+ // weren't closed. Some OSes will have other ports open but we do not try
+ // and test for these.
+ expect(ports.length, greaterThanOrEqualTo(3));
+ expect(countNameMatches(ports, 'port1'), 1);
+ expect(countNameMatches(ports, 'port3'), 0);
+ expect(countNameMatches(ports, 'port4'), 1);
+ expect(countNameMatches(ports, ''), greaterThanOrEqualTo(1));
+ },
+];
+
+main(args) async => runIsolateTests(args, tests, testeeBefore: warmup);
diff --git a/runtime/observatory/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart
index 8b56393..c8b0244 100644
--- a/runtime/observatory/tests/service/get_version_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_version_rpc_test.dart
@@ -9,12 +9,12 @@
var tests = <VMTest>[
(VM vm) async {
- var result = await vm.invokeRpcNoUpgrade('getVersion', {});
- expect(result['type'], equals('Version'));
- expect(result['major'], equals(3));
- expect(result['minor'], equals(40));
- expect(result['_privateMajor'], equals(0));
- expect(result['_privateMinor'], equals(0));
+ final result = await vm.invokeRpcNoUpgrade('getVersion', {});
+ expect(result['type'], 'Version');
+ expect(result['major'], 3);
+ expect(result['minor'], 41);
+ expect(result['_privateMajor'], 0);
+ expect(result['_privateMinor'], 0);
},
];
diff --git a/runtime/observatory_2/lib/src/models/objects/instance.dart b/runtime/observatory_2/lib/src/models/objects/instance.dart
index 66965e9..e52cdd7 100644
--- a/runtime/observatory_2/lib/src/models/objects/instance.dart
+++ b/runtime/observatory_2/lib/src/models/objects/instance.dart
@@ -120,6 +120,9 @@
/// An instance of the Dart class TypeRef.
typeRef,
+
+ /// An instance of the Dart class RawReceivePort
+ receivePort,
}
bool isTypedData(InstanceKind kind) {
diff --git a/runtime/observatory_2/lib/src/service/object.dart b/runtime/observatory_2/lib/src/service/object.dart
index 1bd33fb..fe4027b 100644
--- a/runtime/observatory_2/lib/src/service/object.dart
+++ b/runtime/observatory_2/lib/src/service/object.dart
@@ -2790,6 +2790,8 @@
return M.InstanceKind.typeParameter;
case 'TypeRef':
return M.InstanceKind.typeRef;
+ case 'ReceivePort':
+ return M.InstanceKind.receivePort;
}
var message = 'Unrecognized instance kind: $s';
Logger.root.severe(message);
diff --git a/runtime/observatory_2/tests/service_2/get_ports_public_rpc_test.dart b/runtime/observatory_2/tests/service_2/get_ports_public_rpc_test.dart
new file mode 100644
index 0000000..179823f
--- /dev/null
+++ b/runtime/observatory_2/tests/service_2/get_ports_public_rpc_test.dart
@@ -0,0 +1,50 @@
+// 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 'dart:isolate' hide Isolate;
+import 'package:observatory_2/service_io.dart';
+import 'package:test/test.dart';
+
+import 'test_helper.dart';
+
+var port1;
+var port2;
+var port3;
+
+void warmup() {
+ port1 = RawReceivePort(null, 'port1');
+ port2 = RawReceivePort((_) {});
+ port3 = RawReceivePort((_) {}, 'port3');
+ port3.close();
+ RawReceivePort((_) {}, 'port4');
+}
+
+int countNameMatches(ports, name) {
+ var matches = 0;
+ for (var port in ports) {
+ if (port['debugName'] == name) {
+ matches++;
+ }
+ }
+ return matches;
+}
+
+final tests = <IsolateTest>[
+ (Isolate isolate) async {
+ dynamic result = await isolate.invokeRpcNoUpgrade('getPorts', {});
+ expect(result['type'], 'PortList');
+ expect(result['ports'], isList);
+ final ports = result['ports'];
+ // There are at least three ports: the three created in warm up that
+ // weren't closed. Some OSes will have other ports open but we do not try
+ // and test for these.
+ expect(ports.length, greaterThanOrEqualTo(3));
+ expect(countNameMatches(ports, 'port1'), 1);
+ expect(countNameMatches(ports, 'port3'), 0);
+ expect(countNameMatches(ports, 'port4'), 1);
+ expect(countNameMatches(ports, ''), greaterThanOrEqualTo(1));
+ },
+];
+
+main(args) async => runIsolateTests(args, tests, testeeBefore: warmup);
diff --git a/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart b/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart
index d5450e5..df37cb9 100644
--- a/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart
+++ b/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart
@@ -12,7 +12,7 @@
var result = await vm.invokeRpcNoUpgrade('getVersion', {});
expect(result['type'], equals('Version'));
expect(result['major'], equals(3));
- expect(result['minor'], equals(40));
+ expect(result['minor'], equals(41));
expect(result['_privateMajor'], equals(0));
expect(result['_privateMinor'], equals(0));
},
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index b7ef75aa..8b15f7b 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -54,7 +54,7 @@
V(CapabilityImpl_factory, 1) \
V(CapabilityImpl_equals, 2) \
V(CapabilityImpl_get_hashcode, 1) \
- V(RawReceivePortImpl_factory, 1) \
+ V(RawReceivePortImpl_factory, 2) \
V(RawReceivePortImpl_get_id, 1) \
V(RawReceivePortImpl_get_sendport, 1) \
V(RawReceivePortImpl_closeInternal, 1) \
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index 6650cd6..52fcd87 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -497,7 +497,7 @@
static constexpr dart::compiler::target::word PatchClass_InstanceSize = 24;
static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 8;
static constexpr dart::compiler::target::word Pointer_InstanceSize = 12;
-static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 12;
+static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 20;
static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 16;
static constexpr dart::compiler::target::word RegExp_InstanceSize = 60;
static constexpr dart::compiler::target::word Script_InstanceSize = 56;
@@ -1017,7 +1017,7 @@
static constexpr dart::compiler::target::word PatchClass_InstanceSize = 48;
static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 16;
static constexpr dart::compiler::target::word Pointer_InstanceSize = 24;
-static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 24;
+static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 40;
static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 32;
static constexpr dart::compiler::target::word RegExp_InstanceSize = 120;
static constexpr dart::compiler::target::word Script_InstanceSize = 96;
@@ -1528,7 +1528,7 @@
static constexpr dart::compiler::target::word PatchClass_InstanceSize = 24;
static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 8;
static constexpr dart::compiler::target::word Pointer_InstanceSize = 12;
-static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 12;
+static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 20;
static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 16;
static constexpr dart::compiler::target::word RegExp_InstanceSize = 60;
static constexpr dart::compiler::target::word Script_InstanceSize = 56;
@@ -2049,7 +2049,7 @@
static constexpr dart::compiler::target::word PatchClass_InstanceSize = 48;
static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 16;
static constexpr dart::compiler::target::word Pointer_InstanceSize = 24;
-static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 24;
+static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 40;
static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 32;
static constexpr dart::compiler::target::word RegExp_InstanceSize = 120;
static constexpr dart::compiler::target::word Script_InstanceSize = 96;
@@ -2559,7 +2559,7 @@
static constexpr dart::compiler::target::word PatchClass_InstanceSize = 24;
static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 8;
static constexpr dart::compiler::target::word Pointer_InstanceSize = 12;
-static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 12;
+static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 20;
static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 16;
static constexpr dart::compiler::target::word RegExp_InstanceSize = 60;
static constexpr dart::compiler::target::word Script_InstanceSize = 56;
@@ -3073,7 +3073,7 @@
static constexpr dart::compiler::target::word PatchClass_InstanceSize = 48;
static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 16;
static constexpr dart::compiler::target::word Pointer_InstanceSize = 24;
-static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 24;
+static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 40;
static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 32;
static constexpr dart::compiler::target::word RegExp_InstanceSize = 120;
static constexpr dart::compiler::target::word Script_InstanceSize = 96;
@@ -3578,7 +3578,7 @@
static constexpr dart::compiler::target::word PatchClass_InstanceSize = 24;
static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 8;
static constexpr dart::compiler::target::word Pointer_InstanceSize = 12;
-static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 12;
+static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 20;
static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 16;
static constexpr dart::compiler::target::word RegExp_InstanceSize = 60;
static constexpr dart::compiler::target::word Script_InstanceSize = 56;
@@ -4093,7 +4093,7 @@
static constexpr dart::compiler::target::word PatchClass_InstanceSize = 48;
static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 16;
static constexpr dart::compiler::target::word Pointer_InstanceSize = 24;
-static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 24;
+static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 40;
static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 32;
static constexpr dart::compiler::target::word RegExp_InstanceSize = 120;
static constexpr dart::compiler::target::word Script_InstanceSize = 96;
@@ -4659,7 +4659,7 @@
static constexpr dart::compiler::target::word AOT_PatchClass_InstanceSize = 20;
static constexpr dart::compiler::target::word AOT_PcDescriptors_HeaderSize = 8;
static constexpr dart::compiler::target::word AOT_Pointer_InstanceSize = 12;
-static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 12;
+static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 20;
static constexpr dart::compiler::target::word AOT_RedirectionData_InstanceSize =
16;
static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 60;
@@ -5233,7 +5233,7 @@
static constexpr dart::compiler::target::word AOT_PatchClass_InstanceSize = 40;
static constexpr dart::compiler::target::word AOT_PcDescriptors_HeaderSize = 16;
static constexpr dart::compiler::target::word AOT_Pointer_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 24;
+static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 40;
static constexpr dart::compiler::target::word AOT_RedirectionData_InstanceSize =
32;
static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 120;
@@ -5811,7 +5811,7 @@
static constexpr dart::compiler::target::word AOT_PatchClass_InstanceSize = 40;
static constexpr dart::compiler::target::word AOT_PcDescriptors_HeaderSize = 16;
static constexpr dart::compiler::target::word AOT_Pointer_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 24;
+static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 40;
static constexpr dart::compiler::target::word AOT_RedirectionData_InstanceSize =
32;
static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 120;
@@ -6377,7 +6377,7 @@
static constexpr dart::compiler::target::word AOT_PatchClass_InstanceSize = 20;
static constexpr dart::compiler::target::word AOT_PcDescriptors_HeaderSize = 8;
static constexpr dart::compiler::target::word AOT_Pointer_InstanceSize = 12;
-static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 12;
+static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 20;
static constexpr dart::compiler::target::word AOT_RedirectionData_InstanceSize =
16;
static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 60;
@@ -6944,7 +6944,7 @@
static constexpr dart::compiler::target::word AOT_PatchClass_InstanceSize = 40;
static constexpr dart::compiler::target::word AOT_PcDescriptors_HeaderSize = 16;
static constexpr dart::compiler::target::word AOT_Pointer_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 24;
+static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 40;
static constexpr dart::compiler::target::word AOT_RedirectionData_InstanceSize =
32;
static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 120;
@@ -7515,7 +7515,7 @@
static constexpr dart::compiler::target::word AOT_PatchClass_InstanceSize = 40;
static constexpr dart::compiler::target::word AOT_PcDescriptors_HeaderSize = 16;
static constexpr dart::compiler::target::word AOT_Pointer_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 24;
+static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 40;
static constexpr dart::compiler::target::word AOT_RedirectionData_InstanceSize =
32;
static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 120;
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index a17966f..63db37e 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -725,6 +725,31 @@
return result.raw();
}
+ObjectPtr DartLibraryCalls::LookupOpenPorts() {
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ Function& function = Function::Handle(
+ zone, thread->isolate()->object_store()->lookup_open_ports());
+ const int kTypeArgsLen = 0;
+ const int kNumArguments = 0;
+ if (function.IsNull()) {
+ Library& isolate_lib = Library::Handle(zone, Library::IsolateLibrary());
+ ASSERT(!isolate_lib.IsNull());
+ const String& class_name = String::Handle(
+ zone, isolate_lib.PrivateName(Symbols::_RawReceivePortImpl()));
+ const String& function_name = String::Handle(
+ zone, isolate_lib.PrivateName(Symbols::_lookupOpenPorts()));
+ function = Resolver::ResolveStatic(isolate_lib, class_name, function_name,
+ kTypeArgsLen, kNumArguments,
+ Object::empty_array());
+ ASSERT(!function.IsNull());
+ thread->isolate()->object_store()->set_lookup_open_ports(function);
+ }
+ const Object& result = Object::Handle(
+ zone, DartEntry::InvokeFunction(function, Object::empty_array()));
+ return result.raw();
+}
+
ObjectPtr DartLibraryCalls::HandleMessage(const Object& handler,
const Instance& message) {
Thread* thread = Thread::Current();
diff --git a/runtime/vm/dart_entry.h b/runtime/vm/dart_entry.h
index 2ebdbe8..c85f683 100644
--- a/runtime/vm/dart_entry.h
+++ b/runtime/vm/dart_entry.h
@@ -282,6 +282,9 @@
// Returns the handler if one has been registered for this port id.
static ObjectPtr LookupHandler(Dart_Port port_id);
+ // Returns a list of open ReceivePorts.
+ static ObjectPtr LookupOpenPorts();
+
// Returns null on success, a RawError on failure.
static ObjectPtr HandleMessage(const Object& handler,
const Instance& dart_message);
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 8b8bbc0..7a1c69e 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -2385,8 +2385,9 @@
args.SetAt(2, Instance::Handle(state->BuildArgs(thread)));
args.SetAt(3, Instance::Handle(state->BuildMessage(thread)));
args.SetAt(4, is_spawn_uri ? Bool::True() : Bool::False());
- args.SetAt(5, ReceivePort::Handle(ReceivePort::New(
- isolate->main_port(), true /* control port */)));
+ args.SetAt(5, ReceivePort::Handle(
+ ReceivePort::New(isolate->main_port(), Symbols::Empty(),
+ true /* control port */)));
args.SetAt(6, capabilities);
const Library& lib = Library::Handle(Library::IsolateLibrary());
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index e5af575..bc6666b 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -7,6 +7,7 @@
#include <memory>
#include "include/dart_api.h"
+#include "lib/stacktrace.h"
#include "platform/assert.h"
#include "platform/text_buffer.h"
#include "platform/unaligned.h"
@@ -23805,6 +23806,7 @@
}
ReceivePortPtr ReceivePort::New(Dart_Port id,
+ const String& debug_name,
bool is_control_port,
Heap::Space space) {
ASSERT(id != ILLEGAL_PORT);
@@ -23812,6 +23814,8 @@
Zone* zone = thread->zone();
const SendPort& send_port =
SendPort::Handle(zone, SendPort::New(id, thread->isolate()->origin_id()));
+ const StackTrace& allocation_location_ =
+ HasStack() ? GetCurrentStackTrace(0) : StackTrace::Handle();
ReceivePort& result = ReceivePort::Handle(zone);
{
@@ -23820,6 +23824,9 @@
NoSafepointScope no_safepoint;
result ^= raw;
result.StorePointer(&result.raw_ptr()->send_port_, send_port.raw());
+ result.StorePointer(&result.raw_ptr()->debug_name_, debug_name.raw());
+ result.StorePointer(&result.raw_ptr()->allocation_location_,
+ allocation_location_.raw());
}
if (is_control_port) {
PortMap::SetPortState(id, PortMap::kControlPort);
@@ -23890,6 +23897,39 @@
return "TransferableTypedData";
}
+bool Closure::CanonicalizeEquals(const Instance& other) const {
+ if (!other.IsClosure()) return false;
+
+ const Closure& other_closure = Closure::Cast(other);
+ return (instantiator_type_arguments() ==
+ other_closure.instantiator_type_arguments()) &&
+ (function_type_arguments() ==
+ other_closure.function_type_arguments()) &&
+ (delayed_type_arguments() == other_closure.delayed_type_arguments()) &&
+ (function() == other_closure.function()) &&
+ (context() == other_closure.context());
+}
+
+void Closure::CanonicalizeFieldsLocked(Thread* thread) const {
+ TypeArguments& type_args = TypeArguments::Handle();
+ type_args = instantiator_type_arguments();
+ if (!type_args.IsNull()) {
+ type_args = type_args.Canonicalize(thread, nullptr);
+ set_instantiator_type_arguments(type_args);
+ }
+ type_args = function_type_arguments();
+ if (!type_args.IsNull()) {
+ type_args = type_args.Canonicalize(thread, nullptr);
+ set_function_type_arguments(type_args);
+ }
+ type_args = delayed_type_arguments();
+ if (!type_args.IsNull()) {
+ type_args = type_args.Canonicalize(thread, nullptr);
+ set_delayed_type_arguments(type_args);
+ }
+ // Ignore function, context, hash.
+}
+
intptr_t Closure::NumTypeParameters(Thread* thread) const {
// Only check for empty here, as the null TAV is used to mean that the
// closed-over delayed type parameters were all of dynamic type.
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 903ad3d..1bd2be8 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -10467,6 +10467,9 @@
TypeArgumentsPtr instantiator_type_arguments() const {
return raw_ptr()->instantiator_type_arguments_;
}
+ void set_instantiator_type_arguments(const TypeArguments& args) const {
+ StorePointer(&raw_ptr()->instantiator_type_arguments_, args.raw());
+ }
static intptr_t instantiator_type_arguments_offset() {
return OFFSET_OF(ClosureLayout, instantiator_type_arguments_);
}
@@ -10474,6 +10477,9 @@
TypeArgumentsPtr function_type_arguments() const {
return raw_ptr()->function_type_arguments_;
}
+ void set_function_type_arguments(const TypeArguments& args) const {
+ StorePointer(&raw_ptr()->function_type_arguments_, args.raw());
+ }
static intptr_t function_type_arguments_offset() {
return OFFSET_OF(ClosureLayout, function_type_arguments_);
}
@@ -10481,6 +10487,9 @@
TypeArgumentsPtr delayed_type_arguments() const {
return raw_ptr()->delayed_type_arguments_;
}
+ void set_delayed_type_arguments(const TypeArguments& args) const {
+ StorePointer(&raw_ptr()->delayed_type_arguments_, args.raw());
+ }
static intptr_t delayed_type_arguments_offset() {
return OFFSET_OF(ClosureLayout, delayed_type_arguments_);
}
@@ -10507,10 +10516,8 @@
return RoundedAllocationSize(sizeof(ClosureLayout));
}
- // Returns true if all elements are OK for canonicalization.
- virtual void CanonicalizeFieldsLocked(Thread* thread) const {
- // None of the fields of a closure are instances.
- }
+ virtual void CanonicalizeFieldsLocked(Thread* thread) const;
+ virtual bool CanonicalizeEquals(const Instance& other) const;
virtual uint32_t CanonicalizeHash() const {
return Function::Handle(function()).Hash();
}
@@ -10560,10 +10567,17 @@
InstancePtr handler() const { return raw_ptr()->handler_; }
void set_handler(const Instance& value) const;
+ StackTracePtr allocation_location() const {
+ return raw_ptr()->allocation_location_;
+ }
+
+ StringPtr debug_name() const { return raw_ptr()->debug_name_; }
+
static intptr_t InstanceSize() {
return RoundedAllocationSize(sizeof(ReceivePortLayout));
}
static ReceivePortPtr New(Dart_Port id,
+ const String& debug_name,
bool is_control_port,
Heap::Space space = Heap::kNew);
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index 0d6553e..acdaca6 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -1452,7 +1452,15 @@
}
void ReceivePort::PrintJSONImpl(JSONStream* stream, bool ref) const {
- Instance::PrintJSONImpl(stream, ref);
+ JSONObject obj(stream);
+ Instance::PrintSharedInstanceJSON(&obj, ref);
+ const StackTrace& allocation_location_ =
+ StackTrace::Handle(allocation_location());
+ const String& debug_name_ = String::Handle(debug_name());
+ obj.AddProperty("kind", "ReceivePort");
+ obj.AddProperty64("portId", Id());
+ obj.AddProperty("debugName", debug_name_.ToCString());
+ obj.AddProperty("allocationLocation", allocation_location_);
}
void SendPort::PrintJSONImpl(JSONStream* stream, bool ref) const {
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index dc51e07..829ae7e 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -160,6 +160,7 @@
RW(Instance, stack_overflow) \
RW(Instance, out_of_memory) \
RW(Function, lookup_port_handler) \
+ RW(Function, lookup_open_ports) \
RW(Function, handle_message_function) \
RW(Function, growable_list_factory) \
RW(Function, simple_instance_of_function) \
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 4a713b6..a124ad5 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -2726,7 +2726,9 @@
VISIT_FROM(ObjectPtr, send_port_)
SendPortPtr send_port_;
InstancePtr handler_;
- VISIT_TO(ObjectPtr, handler_)
+ StringPtr debug_name_;
+ StackTracePtr allocation_location_;
+ VISIT_TO(ObjectPtr, allocation_location_)
};
class TransferableTypedDataLayout : public InstanceLayout {
diff --git a/runtime/vm/raw_object_fields.cc b/runtime/vm/raw_object_fields.cc
index 7276a25..f5089d9 100644
--- a/runtime/vm/raw_object_fields.cc
+++ b/runtime/vm/raw_object_fields.cc
@@ -171,6 +171,8 @@
F(ExternalTypedData, length_) \
F(ReceivePort, send_port_) \
F(ReceivePort, handler_) \
+ F(ReceivePort, debug_name_) \
+ F(ReceivePort, allocation_location_) \
F(StackTrace, async_link_) \
F(StackTrace, code_array_) \
F(StackTrace, pc_offset_array_) \
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 23dfdde..d12772e 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -3142,6 +3142,30 @@
return true;
}
+static const MethodParameter* get_ports_params[] = {
+ RUNNABLE_ISOLATE_PARAMETER,
+ NULL,
+};
+
+static bool GetPorts(Thread* thread, JSONStream* js) {
+ // Ensure the array and handles created below are promptly destroyed.
+ StackZone zone(thread);
+ HANDLESCOPE(thread);
+ const GrowableObjectArray& ports = GrowableObjectArray::Handle(
+ GrowableObjectArray::RawCast(DartLibraryCalls::LookupOpenPorts()));
+ JSONObject jsobj(js);
+ jsobj.AddProperty("type", "PortList");
+ {
+ Instance& port = Instance::Handle(zone.GetZone());
+ JSONArray arr(&jsobj, "ports");
+ for (int i = 0; i < ports.Length(); ++i) {
+ port ^= ports.At(i);
+ arr.AddValue(port);
+ }
+ }
+ return true;
+}
+
#if !defined(DART_PRECOMPILED_RUNTIME)
static const char* const report_enum_names[] = {
SourceReport::kCallSitesStr,
@@ -4389,12 +4413,12 @@
return true;
}
-static const MethodParameter* get_ports_params[] = {
+static const MethodParameter* get_ports_private_params[] = {
RUNNABLE_ISOLATE_PARAMETER,
NULL,
};
-static bool GetPorts(Thread* thread, JSONStream* js) {
+static bool GetPortsPrivate(Thread* thread, JSONStream* js) {
MessageHandler* message_handler = thread->isolate()->message_handler();
PortMap::PrintPortsForMessageHandler(message_handler, js);
return true;
@@ -5054,6 +5078,8 @@
get_inbound_references_params },
{ "getInstances", GetInstances,
get_instances_params },
+ { "getPorts", GetPorts,
+ get_ports_params },
{ "getIsolate", GetIsolate,
get_isolate_params },
{ "_getIsolateObjectStore", GetIsolateObjectStore,
@@ -5074,8 +5100,8 @@
get_object_store_params },
{ "_getPersistentHandles", GetPersistentHandles,
get_persistent_handles_params, },
- { "_getPorts", GetPorts,
- get_ports_params },
+ { "_getPorts", GetPortsPrivate,
+ get_ports_private_params },
{ "getProcessMemoryUsage", GetProcessMemoryUsage,
get_process_memory_usage_params },
{ "_getReachableSize", GetReachableSize,
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index bf1d99b..9d09af1 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -15,7 +15,7 @@
namespace dart {
#define SERVICE_PROTOCOL_MAJOR_VERSION 3
-#define SERVICE_PROTOCOL_MINOR_VERSION 40
+#define SERVICE_PROTOCOL_MINOR_VERSION 41
class Array;
class EmbedderServiceHandler;
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index b8d0906..6fe2fb8 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1,8 +1,8 @@
-# Dart VM Service Protocol 3.40
+# Dart VM Service Protocol 3.41
> Please post feedback to the [observatory-discuss group][discuss-list]
-This document describes of _version 3.40_ of the Dart VM Service Protocol. This
+This document describes of _version 3.41_ 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.
@@ -47,6 +47,7 @@
- [getIsolateGroup](#getisolategroup)
- [getMemoryUsage](#getmemoryusage)
- [getObject](#getobject)
+ - [getPorts](#getports)
- [getProcessMemoryUsage](#getprocessmemoryusage)
- [getRetainingPath](#getretainingpath)
- [getScripts](#getscripts)
@@ -113,6 +114,7 @@
- [NativeFunction](#nativefunction)
- [Null](#null)
- [Object](#object)
+ - [PortList](#portlist)
- [ReloadReport](#reloadreport)
- [Response](#response)
- [RetainingObject](#retainingobject)
@@ -936,6 +938,17 @@
Float32x4List, and Float64x2List. These parameters are otherwise
ignored.
+### getPorts
+
+```
+PortList getPorts(string isolateId)
+```
+
+The _getPorts_ RPC is used to retrieve the list of `ReceivePort` instances for a
+given isolate.
+
+See [PortList](#portlist).
+
### getRetainingPath
```
@@ -2426,6 +2439,24 @@
// Provided for instance kinds:
// Closure
@Context closureContext [optional];
+
+ // The port ID for a ReceivePort.
+ //
+ // Provided for instance kinds:
+ // ReceivePort
+ int portId [optional];
+
+ // The stack trace associated with the allocation of a ReceivePort.
+ //
+ // Provided for instance kinds:
+ // ReceivePort
+ @Instance allocationLocation [optional];
+
+ // A name associated with a ReceivePort used for debugging purposes.
+ //
+ // Provided for instance kinds:
+ // ReceivePort
+ string debugName [optional];
}
```
@@ -2446,6 +2477,7 @@
// Double (suitable for passing to Double.parse())
// Int (suitable for passing to int.parse())
// String (value may be truncated)
+ // StackTrace
string valueAsString [optional];
// The valueAsString for String references may be truncated. If so,
@@ -2658,6 +2690,24 @@
// BoundedType
// TypeParameter
@Instance bound [optional];
+
+ // The port ID for a ReceivePort.
+ //
+ // Provided for instance kinds:
+ // ReceivePort
+ int portId [optional];
+
+ // The stack trace associated with the allocation of a ReceivePort.
+ //
+ // Provided for instance kinds:
+ // ReceivePort
+ @Instance allocationLocation [optional];
+
+ // A name associated with a ReceivePort used for debugging purposes.
+ //
+ // Provided for instance kinds:
+ // ReceivePort
+ string debugName [optional];
}
```
@@ -2742,6 +2792,9 @@
// An instance of the Dart class BoundedType.
BoundedType,
+
+ // An instance of the Dart class ReceivePort.
+ ReceivePort,
}
```
@@ -3184,6 +3237,18 @@
An _Object_ is a persistent object that is owned by some isolate.
+### PortList
+
+```
+class PortList extends Response {
+ @Instance[] ports;
+}
+```
+
+A _PortList_ contains a list of ports associated with some isolate.
+
+See [getPort](#getPort).
+
### ProfileFunction
```
@@ -3855,5 +3920,6 @@
3.38 | Added `isSystemIsolate` property to `@Isolate` and `Isolate`, `isSystemIsolateGroup` property to `@IsolateGroup` and `IsolateGroup`, and properties `systemIsolates` and `systemIsolateGroups` to `VM`.
3.39 | Removed the following deprecated RPCs and objects: `getClientName`, `getWebSocketTarget`, `setClientName`, `requireResumeApproval`, `ClientName`, and `WebSocketTarget`.
3.40 | Added `IsolateFlag` object and `isolateFlags` property to `Isolate`.
+3.41 | Added `PortList` object, `ReceivePort` `InstanceKind`, and `getPorts` RPC.
[discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 40b953c..d8f11c2 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -447,6 +447,7 @@
V(_handleMessage, "_handleMessage") \
V(_instanceOf, "_instanceOf") \
V(_lookupHandler, "_lookupHandler") \
+ V(_lookupOpenPorts, "_lookupOpenPorts") \
V(_name, "_name") \
V(_onData, "_onData") \
V(_rehashObjects, "_rehashObjects") \
diff --git a/sdk/lib/_internal/allowed_experiments.json b/sdk/lib/_internal/allowed_experiments.json
index cda7feb..4644443 100644
--- a/sdk/lib/_internal/allowed_experiments.json
+++ b/sdk/lib/_internal/allowed_experiments.json
@@ -34,6 +34,12 @@
"collection": {
"experimentSet": "nullSafety"
},
+ "connectivity": {
+ "experimentSet": "nullSafety"
+ },
+ "connectivity_platform_interface": {
+ "experimentSet": "nullSafety"
+ },
"convert": {
"experimentSet": "nullSafety"
},
@@ -46,6 +52,12 @@
"dart_internal": {
"experimentSet": "nullSafety"
},
+ "device_info": {
+ "experimentSet": "nullSafety"
+ },
+ "device_info_platform_interface": {
+ "experimentSet": "nullSafety"
+ },
"fake_async": {
"experimentSet": "nullSafety"
},
@@ -109,6 +121,9 @@
"platform": {
"experimentSet": "nullSafety"
},
+ "plugin_platform_interface": {
+ "experimentSet": "nullSafety"
+ },
"pool": {
"experimentSet": "nullSafety"
},
@@ -154,8 +169,32 @@
"typed_data": {
"experimentSet": "nullSafety"
},
+ "url_launcher": {
+ "experimentSet": "nullSafety"
+ },
+ "url_launcher_linux": {
+ "experimentSet": "nullSafety"
+ },
+ "url_launcher_macos": {
+ "experimentSet": "nullSafety"
+ },
+ "url_launcher_platform_interface": {
+ "experimentSet": "nullSafety"
+ },
+ "url_launcher_windows": {
+ "experimentSet": "nullSafety"
+ },
"vector_math": {
"experimentSet": "nullSafety"
+ },
+ "video_player": {
+ "experimentSet": "nullSafety"
+ },
+ "video_player_platform_interface": {
+ "experimentSet": "nullSafety"
+ },
+ "video_player_web": {
+ "experimentSet": "nullSafety"
}
}
}
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
index 52c3266..4a224cd 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
@@ -872,8 +872,15 @@
})()''');
checkNativeNonNull(dynamic variable) {
- if (_nativeNonNullAsserts) {
- return nullCheck(variable);
+ if (_nativeNonNullAsserts && variable == null) {
+ // TODO(srujzs): Add link/patch for instructions to disable in internal
+ // build systems.
+ throw TypeErrorImpl('''
+ Unexpected null value encountered in Dart web platform libraries.
+ This may be a bug in the Dart SDK APIs. If you would like to report a bug
+ or disable this error, you can use the following instructions:
+ https://github.com/dart-lang/sdk/tree/master/sdk/lib/html/doc/NATIVE_NULL_ASSERTIONS.md
+ ''');
}
return variable;
}
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
index 99ca1e2..b6a0325 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
@@ -48,7 +48,10 @@
bool _nativeNonNullAsserts = false;
/// Enables null assertions on native APIs to make sure value returned from the
-/// browser is sound. These apply to dart:html and similar web libraries.
+/// browser is sound.
+///
+/// These apply to dart:html and similar web libraries. Note that these only are
+/// added in sound null-safety only.
void nativeNonNullAsserts(bool enable) {
_nativeNonNullAsserts = enable;
}
diff --git a/sdk/lib/_internal/vm/lib/ffi_patch.dart b/sdk/lib/_internal/vm/lib/ffi_patch.dart
index a04c737..02bc8c7 100644
--- a/sdk/lib/_internal/vm/lib/ffi_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_patch.dart
@@ -39,7 +39,7 @@
int _sizeOf<T extends NativeType>() native "Ffi_sizeOf";
-// Implemented in the method recognizer, bytecode interpreter uses runtime.
+// Implemented in the method recognizer.
Pointer<T> _fromAddress<T extends NativeType>(int ptr) native "Ffi_fromAddress";
// The real implementation of this function (for interface calls) lives in
@@ -92,7 +92,7 @@
"Pointer.fromFunction cannot be called dynamically.");
}
- // Implemented in the method recognizer, bytecode interpreter uses runtime.
+ // Implemented in the method recognizer.
@patch
int get address native "Ffi_address";
@@ -114,10 +114,9 @@
/// calculations. See pkg/vm/lib/transformations/ffi.dart.
@pragma('vm:prefer-inline')
int _abi()
- native "Recognized method: method is directly interpreted by the bytecode interpreter or IR graph is built in the flow graph builder.";
+ native "Recognized method: IR graph is built in the flow graph builder.";
-// The following functions are implemented in the method recognizer, but the
-// bytecode interpreter uses native entries.
+// The following functions are implemented in the method recognizer.
//
// TODO(38172): Since these are not inlined (force optimize), they force
// allocating a Pointer with in elementAt/offsetBy. Allocating these pointers
diff --git a/sdk/lib/_internal/vm/lib/internal_patch.dart b/sdk/lib/_internal/vm/lib/internal_patch.dart
index 812f18f..ad5f5b7 100644
--- a/sdk/lib/_internal/vm/lib/internal_patch.dart
+++ b/sdk/lib/_internal/vm/lib/internal_patch.dart
@@ -163,7 +163,7 @@
// This function can be used to keep an object alive til that point.
//
-// This is implemented by a recognized method, but in bytecode through a native.
+// This is implemented by a recognized method.
@pragma('vm:prefer-inline')
void reachabilityFence(Object object) native "Internal_reachabilityFence";
diff --git a/sdk/lib/_internal/vm/lib/isolate_patch.dart b/sdk/lib/_internal/vm/lib/isolate_patch.dart
index 91a567d..97e90ce 100644
--- a/sdk/lib/_internal/vm/lib/isolate_patch.dart
+++ b/sdk/lib/_internal/vm/lib/isolate_patch.dart
@@ -22,7 +22,8 @@
@patch
class ReceivePort {
@patch
- factory ReceivePort() => new _ReceivePortImpl();
+ factory ReceivePort([String debugName = '']) =>
+ new _ReceivePortImpl(debugName);
@patch
factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort) {
@@ -62,15 +63,16 @@
* event is received.
*/
@patch
- factory RawReceivePort([Function? handler]) {
- _RawReceivePortImpl result = new _RawReceivePortImpl();
+ factory RawReceivePort([Function? handler, String debugName = '']) {
+ _RawReceivePortImpl result = new _RawReceivePortImpl(debugName);
result.handler = handler;
return result;
}
}
class _ReceivePortImpl extends Stream implements ReceivePort {
- _ReceivePortImpl() : this.fromRawReceivePort(new RawReceivePort());
+ _ReceivePortImpl([String debugName = ''])
+ : this.fromRawReceivePort(new RawReceivePort(null, debugName));
_ReceivePortImpl.fromRawReceivePort(this._rawPort)
: _controller = new StreamController(sync: true) {
@@ -128,11 +130,20 @@
@pragma("vm:entry-point")
class _RawReceivePortImpl implements RawReceivePort {
- factory _RawReceivePortImpl() native "RawReceivePortImpl_factory";
+ factory _RawReceivePortImpl(String debugName) {
+ final port = _RawReceivePortImpl._(debugName);
+ _portMap[port._get_id()] = <String, dynamic>{
+ 'port': port,
+ };
+ return port;
+ }
+
+ factory _RawReceivePortImpl._(String debugName)
+ native "RawReceivePortImpl_factory";
close() {
// Close the port and remove it from the handler map.
- _handlerMap.remove(this._closeInternal());
+ _portMap.remove(this._closeInternal());
}
SendPort get sendPort {
@@ -155,10 +166,15 @@
// Called from the VM to retrieve the handler for a message.
@pragma("vm:entry-point", "call")
static _lookupHandler(int id) {
- var result = _handlerMap[id];
+ var result = _portMap[id]?['handler'];
return result;
}
+ @pragma("vm:entry-point", "call")
+ static _lookupOpenPorts() {
+ return _portMap.values.map((e) => e['port']).toList();
+ }
+
// Called from the VM to dispatch to the handler.
@pragma("vm:entry-point", "call")
static void _handleMessage(Function handler, var message) {
@@ -173,22 +189,16 @@
_closeInternal() native "RawReceivePortImpl_closeInternal";
void set handler(Function? value) {
- _handlerMap[this._get_id()] = value;
+ final id = this._get_id();
+ if (!_portMap.containsKey(id)) {
+ _portMap[id] = <String, dynamic>{
+ 'port': this,
+ };
+ }
+ _portMap[id]!['handler'] = value;
}
- // TODO(iposva): Ideally keep this map in the VM.
- // id to handler mapping.
- static _initHandlerMap() {
- // TODO(18511): Workaround bad CheckSmi hoisting.
- var tempMap = new HashMap();
- // Collect feedback that not all keys are Smis.
- tempMap["."] = 1;
- tempMap["."] = 2;
-
- return new HashMap();
- }
-
- static final Map _handlerMap = _initHandlerMap();
+ static final _portMap = <dynamic, Map<String, dynamic>>{};
}
@pragma("vm:entry-point")
diff --git a/sdk/lib/html/doc/NATIVE_NULL_ASSERTIONS.md b/sdk/lib/html/doc/NATIVE_NULL_ASSERTIONS.md
new file mode 100644
index 0000000..eb9e79d
--- /dev/null
+++ b/sdk/lib/html/doc/NATIVE_NULL_ASSERTIONS.md
@@ -0,0 +1,42 @@
+# Native Null Assertions in Dart Dev Compiler and Dart2JS
+
+## Overview
+
+In the Dart web platform libraries, e.g. `dart:html`, there are APIs that depend
+on JS interoperability. With null-safety, the types returned from these interop
+procedures are not null-checked by default. In both DDC and dart2js, there
+exists a flag to turn on checks, or native null assertions, for these instances.
+In DDC, it's called `nativeNonNullAsserts` and in dart2js, it's called
+`--native-null-assertions`.
+
+Specifically, the flag focused on two cases. The first case is checks around
+types returned from APIs that are declared `native`. If the return type here is
+non-nullable, enabling native null assertions will throw an error if a `null`
+value is returned. For example,
+
+`int get foo native;`
+
+will throw an error if `.foo` returns a `null` value. This may happen due to a
+number of reasons, one of which could be browser incompatibility.
+
+The second case is on `JS()` invocations. `JS()` is an internal-only function
+that allows you to inline JavaScript. If the static type of the `JS()`
+invocation is non-nullable, but a `null` value is returned, there will be an
+error thrown if native null assertions are enabled.
+
+The goals with these native null assertions are to ensure the Dart web platform
+libraries are typed correctly and to help achieve sound null-safety.
+
+If you come across an error related to this flag, this may or may not be a bug
+in the Dart web platform libraries. If so, please file a bug at:
+https://github.com/dart-lang/sdk/issues/labels/web-libraries
+
+## Disabling native null assertions
+
+Native null assertions will be turned on by default across different build
+systems. If it is enabled, here's how you can disable it in the following build
+systems:
+
+### build_web_compilers
+
+https://github.com/dart-lang/build/tree/master/docs/native_null_assertions.md
diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart
index 98d2dcf..e5a757f 100644
--- a/sdk/lib/io/secure_socket.dart
+++ b/sdk/lib/io/secure_socket.dart
@@ -785,7 +785,7 @@
_close();
}
- void _closeHandler() {
+ void _closeHandler() async {
if (_status == connectedStatus) {
if (_closedRead) return;
_socketClosedRead = true;
@@ -796,7 +796,7 @@
_close();
}
} else {
- _scheduleFilter();
+ await _scheduleFilter();
}
} else if (_status == handshakeStatus) {
_socketClosedRead = true;
@@ -805,26 +805,23 @@
new HandshakeException('Connection terminated during handshake'),
null);
} else {
- _secureHandshake();
+ await _secureHandshake();
}
}
}
- void _secureHandshake() {
+ Future<void> _secureHandshake() async {
try {
- _secureFilter!.handshake().then((needRetryHandshake) {
- if (needRetryHandshake) {
- // Some certificates have been evaluated, need to rety handshake.
- _secureHandshake();
- } else {
- _filterStatus.writeEmpty = false;
- _readSocket();
- _writeSocket();
- _scheduleFilter();
- }
- }).catchError((e, stackTrace) {
- _reportError(e, stackTrace);
- });
+ bool needRetryHandshake = await _secureFilter!.handshake();
+ if (needRetryHandshake) {
+ // Some certificates have been evaluated, need to retry handshake.
+ await _secureHandshake();
+ } else {
+ _filterStatus.writeEmpty = false;
+ _readSocket();
+ _writeSocket();
+ await _scheduleFilter();
+ }
} catch (e, stackTrace) {
_reportError(e, stackTrace);
}
@@ -885,67 +882,71 @@
}
}
- void _scheduleFilter() {
+ Future<void> _scheduleFilter() async {
_filterPending = true;
- _tryFilter();
+ return _tryFilter();
}
- void _tryFilter() {
+ Future<void> _tryFilter() async {
if (_status == closedStatus) {
return;
}
- if (_filterPending && !_filterActive) {
- _filterActive = true;
- _filterPending = false;
- _pushAllFilterStages().then((status) {
- _filterStatus = status;
- _filterActive = false;
- if (_status == closedStatus) {
- _secureFilter!.destroy();
- _secureFilter = null;
- return;
- }
- _socket.readEventsEnabled = true;
- if (_filterStatus.writeEmpty && _closedWrite && !_socketClosedWrite) {
- // Checks for and handles all cases of partially closed sockets.
- shutdown(SocketDirection.send);
- if (_status == closedStatus) {
- return;
- }
- }
- if (_filterStatus.readEmpty && _socketClosedRead && !_closedRead) {
- if (_status == handshakeStatus) {
- _secureFilter!.handshake();
- if (_status == handshakeStatus) {
- throw new HandshakeException(
- 'Connection terminated during handshake');
- }
- }
- _closeHandler();
- }
+ if (!_filterPending || _filterActive) {
+ return;
+ }
+ _filterActive = true;
+ _filterPending = false;
+
+ try {
+ _filterStatus = await _pushAllFilterStages();
+ _filterActive = false;
+ if (_status == closedStatus) {
+ _secureFilter!.destroy();
+ _secureFilter = null;
+ return;
+ }
+ _socket.readEventsEnabled = true;
+ if (_filterStatus.writeEmpty && _closedWrite && !_socketClosedWrite) {
+ // Checks for and handles all cases of partially closed sockets.
+ shutdown(SocketDirection.send);
if (_status == closedStatus) {
return;
}
- if (_filterStatus.progress) {
- _filterPending = true;
- if (_filterStatus.writeEncryptedNoLongerEmpty) {
- _writeSocket();
- }
- if (_filterStatus.writePlaintextNoLongerFull) {
- _sendWriteEvent();
- }
- if (_filterStatus.readEncryptedNoLongerFull) {
- _readSocket();
- }
- if (_filterStatus.readPlaintextNoLongerEmpty) {
- _scheduleReadEvent();
- }
+ }
+ if (_filterStatus.readEmpty && _socketClosedRead && !_closedRead) {
+ if (_status == handshakeStatus) {
+ _secureFilter!.handshake();
if (_status == handshakeStatus) {
- _secureHandshake();
+ throw new HandshakeException(
+ 'Connection terminated during handshake');
}
}
- _tryFilter();
- }).catchError(_reportError);
+ _closeHandler();
+ }
+ if (_status == closedStatus) {
+ return;
+ }
+ if (_filterStatus.progress) {
+ _filterPending = true;
+ if (_filterStatus.writeEncryptedNoLongerEmpty) {
+ _writeSocket();
+ }
+ if (_filterStatus.writePlaintextNoLongerFull) {
+ _sendWriteEvent();
+ }
+ if (_filterStatus.readEncryptedNoLongerFull) {
+ _readSocket();
+ }
+ if (_filterStatus.readPlaintextNoLongerEmpty) {
+ _scheduleReadEvent();
+ }
+ if (_status == handshakeStatus) {
+ await _secureHandshake();
+ }
+ }
+ return _tryFilter();
+ } catch (e, st) {
+ _reportError(e, st);
}
}
@@ -1024,7 +1025,7 @@
}
}
- Future<_FilterStatus> _pushAllFilterStages() {
+ Future<_FilterStatus> _pushAllFilterStages() async {
bool wasInHandshake = _status != connectedStatus;
List args = new List<dynamic>.filled(2 + bufferCount * 2, null);
args[0] = _secureFilter!._pointer();
@@ -1035,75 +1036,74 @@
args[2 * i + 3] = bufs[i].end;
}
- return _IOService._dispatch(_IOService.sslProcessFilter, args)
- .then((response) {
- if (response.length == 2) {
- if (wasInHandshake) {
- // If we're in handshake, throw a handshake error.
- _reportError(
- new HandshakeException('${response[1]} error ${response[0]}'),
- null);
- } else {
- // If we're connected, throw a TLS error.
- _reportError(
- new TlsException('${response[1]} error ${response[0]}'), null);
- }
+ var response =
+ await _IOService._dispatch(_IOService.sslProcessFilter, args);
+ if (response.length == 2) {
+ if (wasInHandshake) {
+ // If we're in handshake, throw a handshake error.
+ _reportError(
+ new HandshakeException('${response[1]} error ${response[0]}'),
+ null);
+ } else {
+ // If we're connected, throw a TLS error.
+ _reportError(
+ new TlsException('${response[1]} error ${response[0]}'), null);
}
- int start(int index) => response[2 * index];
- int end(int index) => response[2 * index + 1];
+ }
+ int start(int index) => response[2 * index];
+ int end(int index) => response[2 * index + 1];
- _FilterStatus status = new _FilterStatus();
- // Compute writeEmpty as "write plaintext buffer and write encrypted
- // buffer were empty when we started and are empty now".
- status.writeEmpty = bufs[writePlaintextId].isEmpty &&
- start(writeEncryptedId) == end(writeEncryptedId);
- // If we were in handshake when this started, _writeEmpty may be false
- // because the handshake wrote data after we checked.
- if (wasInHandshake) status.writeEmpty = false;
+ _FilterStatus status = new _FilterStatus();
+ // Compute writeEmpty as "write plaintext buffer and write encrypted
+ // buffer were empty when we started and are empty now".
+ status.writeEmpty = bufs[writePlaintextId].isEmpty &&
+ start(writeEncryptedId) == end(writeEncryptedId);
+ // If we were in handshake when this started, _writeEmpty may be false
+ // because the handshake wrote data after we checked.
+ if (wasInHandshake) status.writeEmpty = false;
- // Compute readEmpty as "both read buffers were empty when we started
- // and are empty now".
- status.readEmpty = bufs[readEncryptedId].isEmpty &&
- start(readPlaintextId) == end(readPlaintextId);
+ // Compute readEmpty as "both read buffers were empty when we started
+ // and are empty now".
+ status.readEmpty = bufs[readEncryptedId].isEmpty &&
+ start(readPlaintextId) == end(readPlaintextId);
- _ExternalBuffer buffer = bufs[writePlaintextId];
- int new_start = start(writePlaintextId);
- if (new_start != buffer.start) {
- status.progress = true;
- if (buffer.free == 0) {
- status.writePlaintextNoLongerFull = true;
- }
- buffer.start = new_start;
+ _ExternalBuffer buffer = bufs[writePlaintextId];
+ int new_start = start(writePlaintextId);
+ if (new_start != buffer.start) {
+ status.progress = true;
+ if (buffer.free == 0) {
+ status.writePlaintextNoLongerFull = true;
}
- buffer = bufs[readEncryptedId];
- new_start = start(readEncryptedId);
- if (new_start != buffer.start) {
- status.progress = true;
- if (buffer.free == 0) {
- status.readEncryptedNoLongerFull = true;
- }
- buffer.start = new_start;
+ buffer.start = new_start;
+ }
+ buffer = bufs[readEncryptedId];
+ new_start = start(readEncryptedId);
+ if (new_start != buffer.start) {
+ status.progress = true;
+ if (buffer.free == 0) {
+ status.readEncryptedNoLongerFull = true;
}
- buffer = bufs[writeEncryptedId];
- int new_end = end(writeEncryptedId);
- if (new_end != buffer.end) {
- status.progress = true;
- if (buffer.length == 0) {
- status.writeEncryptedNoLongerEmpty = true;
- }
- buffer.end = new_end;
+ buffer.start = new_start;
+ }
+ buffer = bufs[writeEncryptedId];
+ int new_end = end(writeEncryptedId);
+ if (new_end != buffer.end) {
+ status.progress = true;
+ if (buffer.length == 0) {
+ status.writeEncryptedNoLongerEmpty = true;
}
- buffer = bufs[readPlaintextId];
- new_end = end(readPlaintextId);
- if (new_end != buffer.end) {
- status.progress = true;
- if (buffer.length == 0) {
- status.readPlaintextNoLongerEmpty = true;
- }
- buffer.end = new_end;
+ buffer.end = new_end;
+ }
+ buffer = bufs[readPlaintextId];
+ new_end = end(readPlaintextId);
+ if (new_end != buffer.end) {
+ status.progress = true;
+ if (buffer.length == 0) {
+ status.readPlaintextNoLongerEmpty = true;
}
- return status;
- });
+ buffer.end = new_end;
+ }
+ return status;
}
}
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index 0c5747e..b7650dd 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.dart
@@ -671,9 +671,12 @@
* receive messages. See [Stream.asBroadcastStream] for transforming the port
* to a broadcast stream.
*
+ * The optional `debugName` parameter can be set to associate a name with
+ * this port that can be displayed in tooling.
+ *
* A receive port is closed by canceling its subscription.
*/
- external factory ReceivePort();
+ external factory ReceivePort([String debugName = '']);
/**
* Creates a [ReceivePort] from a [RawReceivePort].
@@ -718,8 +721,12 @@
* A [RawReceivePort] is low level and does not work with [Zone]s. It
* can not be paused. The data-handler must be set before the first
* event is received.
+ *
+ * The optional `debugName` parameter can be set to associate a name with
+ * this port that can be displayed in tooling.
+ *
*/
- external factory RawReceivePort([Function? handler]);
+ external factory RawReceivePort([Function? handler, String debugName = '']);
/**
* Sets the handler that is invoked for every incoming message.
diff --git a/tests/dart2js/native/native_null_assertions/flag_disabled_non_web_test.dart b/tests/dart2js/native/native_null_assertions/flag_disabled_non_web_test.dart
index 7ed8c58..660a546 100644
--- a/tests/dart2js/native/native_null_assertions/flag_disabled_non_web_test.dart
+++ b/tests/dart2js/native/native_null_assertions/flag_disabled_non_web_test.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.
+// Requirements=nnbd-strong
// dart2jsOptions=--no-native-null-assertions
import 'non_web_library_interfaces.dart';
diff --git a/tests/dart2js/native/native_null_assertions/flag_disabled_web_test.dart b/tests/dart2js/native/native_null_assertions/flag_disabled_web_test.dart
index ee0d648..8b7ee4c 100644
--- a/tests/dart2js/native/native_null_assertions/flag_disabled_web_test.dart
+++ b/tests/dart2js/native/native_null_assertions/flag_disabled_web_test.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.
+// Requirements=nnbd-strong
// dart2jsOptions=--no-native-null-assertions
import 'null_assertions_test_lib.dart';
diff --git a/tests/dart2js/native/native_null_assertions/flag_enabled_non_web_test.dart b/tests/dart2js/native/native_null_assertions/flag_enabled_non_web_test.dart
index 61c018b..e923657 100644
--- a/tests/dart2js/native/native_null_assertions/flag_enabled_non_web_test.dart
+++ b/tests/dart2js/native/native_null_assertions/flag_enabled_non_web_test.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.
+// Requirements=nnbd-strong
// dart2jsOptions=--native-null-assertions
import 'non_web_library_interfaces.dart';
diff --git a/tests/dart2js/native/native_null_assertions/flag_enabled_web_test.dart b/tests/dart2js/native/native_null_assertions/flag_enabled_web_test.dart
index 71baddf..2c41d2a 100644
--- a/tests/dart2js/native/native_null_assertions/flag_enabled_web_test.dart
+++ b/tests/dart2js/native/native_null_assertions/flag_enabled_web_test.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.
+// Requirements=nnbd-strong
// dart2jsOptions=--native-null-assertions
import 'null_assertions_test_lib.dart';
diff --git a/tests/ffi/dylib_isolates_test.dart b/tests/ffi/dylib_isolates_test.dart
index 5eb73ef..f790e12 100644
--- a/tests/ffi/dylib_isolates_test.dart
+++ b/tests/ffi/dylib_isolates_test.dart
@@ -7,6 +7,7 @@
// SharedObjects=ffi_test_functions
import 'dart:ffi';
+import 'dart:io';
import 'dart:isolate';
import "package:expect/expect.dart";
@@ -29,7 +30,9 @@
final receivePort = ReceivePort();
Isolate.spawn(secondIsolateMain, receivePort.sendPort);
await receivePort.first;
- Expect.equals(42, getGlobalVar());
+ if (!Platform.isIOS /* Static linking causes different behavior. */) {
+ Expect.equals(42, getGlobalVar());
+ }
}
void secondIsolateMain(SendPort sendPort) {
diff --git a/tests/ffi/prepare_flutter_bundle.dart b/tests/ffi/prepare_flutter_bundle.dart
deleted file mode 100644
index 83a4a42..0000000
--- a/tests/ffi/prepare_flutter_bundle.dart
+++ /dev/null
@@ -1,204 +0,0 @@
-// Copyright (c) 2019, 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 'dart:async';
-import 'dart:io';
-
-import 'package:path/path.dart' as path;
-import 'package:args/args.dart';
-
-main(List<String> args) async {
- if (args.length != 1) {
- print('Usage ${Platform.executable} ${Platform.script} <output-dir>');
- exit(1);
- }
-
- final sdkRoot =
- path.canonicalize(path.join(Platform.script.path, '../../..'));
- final flutterTestsDir = args.single;
-
- print('Using SDK root: $sdkRoot');
- final testFiles = <String>[];
- final failedOrTimedOut = <String>[];
- final filteredTests = <String>[];
- await for (final testFile in listTestFiles(sdkRoot, filteredTests)) {
- final duration = await run(sdkRoot, testFile);
- if (duration != null && duration.inSeconds < 5) {
- testFiles.add(testFile);
- } else {
- failedOrTimedOut.add(testFile);
- }
- }
- testFiles.sort();
- failedOrTimedOut.sort();
- filteredTests.sort();
-
- dumpTestList(testFiles, 'The following tests will be included:');
- dumpTestList(failedOrTimedOut,
- 'The following tests will be excluded due to timeout or test failure:');
- dumpTestList(
- filteredTests,
- 'The following tests were filtered due to using '
- 'dart_api.h/async/DynamicLibrary.{process,executable}/...');
-
- final allFiles = <String>{};
- allFiles.add(path.join(sdkRoot, 'pkg/expect/lib/expect.dart'));
- for (final testFile in testFiles) {
- allFiles.add(testFile);
- await addImportedFilesTo(allFiles, testFile);
- }
-
- await generateCleanDir(flutterTestsDir);
-
- final dartTestsDir = path.join(flutterTestsDir, 'lib/src/generated');
- await generateDartTests(dartTestsDir, allFiles, testFiles);
-
- final ccDir = path.join(flutterTestsDir, 'ios/Classes');
- await generateCLibs(sdkRoot, ccDir, allFiles, testFiles);
-
- print('');
- print('Please copy generated files into FFI flutter test application');
- print(' * $dartTestsDir');
- print(' * $ccDir');
-}
-
-void dumpTestList(List<String> testFiles, String message) {
- if (testFiles.isEmpty) return;
-
- print(message);
- for (final testFile in testFiles) {
- print(' ${path.basename(testFile)}');
- }
-}
-
-final importRegExp = RegExp(r'''^import.*['"](.+)['"].*;''');
-
-Future addImportedFilesTo(Set<String> allFiles, String testFile) async {
- final content = await File(testFile).readAsString();
- for (final line in content.split('\n')) {
- final match = importRegExp.matchAsPrefix(line);
- if (match != null) {
- final filename = match.group(1);
- if (!filename.contains('dart:') &&
- !filename.contains('package:expect') &&
- !filename.contains('package:ffi')) {
- final importedFile = Uri.file(testFile).resolve(filename).toFilePath();
- if (allFiles.add(importedFile)) {
- addImportedFilesTo(allFiles, importedFile);
- }
- }
- }
- }
-}
-
-Future generateCLibs(String sdkRoot, String destDir, Set<String> allFiles,
- List<String> testFiles) async {
- final dir = await generateCleanDir(destDir);
-
- String destinationFile;
-
- final lib1 =
- path.join(sdkRoot, 'runtime/bin/ffi_test/ffi_test_dynamic_library.cc');
- destinationFile =
- path.join(dir.path, path.basename(lib1)).replaceAll('.cc', '.cpp');
- File(destinationFile).writeAsStringSync(File(lib1).readAsStringSync());
-
- final lib2 = path.join(sdkRoot, 'runtime/bin/ffi_test/ffi_test_functions.cc');
- destinationFile =
- path.join(dir.path, path.basename(lib2)).replaceAll('.cc', '.cpp');
- File(destinationFile).writeAsStringSync(File(lib2).readAsStringSync());
-}
-
-String cleanDart(String content) {
- return content.replaceAll('package:expect/expect.dart', 'expect.dart');
-}
-
-Future generateDartTests(
- String destDir, Set<String> allFiles, List<String> testFiles) async {
- final dir = await generateCleanDir(destDir);
-
- final sink = File(path.join(dir.path, 'all.dart')).openWrite();
- sink.writeln('import "dart:async";');
- sink.writeln('');
- for (int i = 0; i < testFiles.length; ++i) {
- sink.writeln('import "${path.basename(testFiles[i])}" as main$i;');
- }
- sink.writeln('');
- sink.writeln('Future invoke(dynamic fun) async {');
- sink.writeln(' if (fun is void Function() || fun is Future Function()) {');
- sink.writeln(' return await fun();');
- sink.writeln(' } else {');
- sink.writeln(' return await fun(<String>[]);');
- sink.writeln(' }');
- sink.writeln('}');
- sink.writeln('');
- sink.writeln('dynamic main() async {');
- for (int i = 0; i < testFiles.length; ++i) {
- sink.writeln(' await invoke(main$i.main);');
- }
- sink.writeln('}');
- await sink.close();
-
- for (final file in allFiles) {
- File(path.join(dir.path, path.basename(file)))
- .writeAsStringSync(cleanDart(File(file).readAsStringSync()));
- }
-
- File(path.join(dir.path, 'dylib_utils.dart')).writeAsStringSync('''
-import 'dart:ffi' as ffi;
-import 'dart:io' show Platform;
-
-ffi.DynamicLibrary dlopenPlatformSpecific(String name, {String path}) {
- return Platform.isAndroid
- ? ffi.DynamicLibrary.open('libffi_tests.so')
- : ffi.DynamicLibrary.process();
-}
-''');
-}
-
-Stream<String> listTestFiles(
- String sdkRoot, List<String> filteredTests) async* {
- await for (final file in Directory(path.join(sdkRoot, 'tests/ffi')).list()) {
- if (file is File && file.path.endsWith('_test.dart')) {
- // These tests are VM specific and cannot necessarily be run on Flutter.
- if (path.basename(file.path).startsWith('vmspecific_')) {
- filteredTests.add(file.path);
- continue;
- }
- // These tests use special features which are hard to test on Flutter.
- final contents = file.readAsStringSync();
- if (contents.contains(RegExp('//# .* compile-time error')) ||
- contents.contains('DynamicLibrary.process') ||
- contents.contains('DynamicLibrary.executable')) {
- filteredTests.add(file.path);
- continue;
- }
- yield file.path;
- }
- }
-}
-
-Future<Duration> run(String sdkRoot, String testFile) async {
- final env = Map<String, String>.from(Platform.environment);
- env['LD_LIBRARY_PATH'] = path.join(sdkRoot, 'out/ReleaseX64');
- final sw = Stopwatch()..start();
- final Process process = await Process.start(
- Platform.executable, <String>[testFile],
- environment: env);
- final timer = Timer(const Duration(seconds: 3), () => process.kill());
- process.stdout.listen((_) {});
- process.stderr.listen((_) {});
- if (await process.exitCode != 0) return null;
- timer.cancel();
- return sw.elapsed;
-}
-
-Future<Directory> generateCleanDir(String dirname) async {
- final directory = Directory(dirname);
- if (await directory.exists()) {
- await directory.delete(recursive: true);
- }
- await directory.create(recursive: true);
- return directory;
-}
diff --git a/tests/ffi/regress_37254_test.dart b/tests/ffi/regress_37254_test.dart
index b4fce7c..ce696af 100644
--- a/tests/ffi/regress_37254_test.dart
+++ b/tests/ffi/regress_37254_test.dart
@@ -238,7 +238,6 @@
}
void main() {
- // Trigger both the runtime entry and the IL in bytecode.
for (int i = 0; i < 100; i++) {
store1();
store2();
diff --git a/tests/ffi/regress_43016_test.dart b/tests/ffi/regress_43016_test.dart
index 8468fcd..f1489e0 100644
--- a/tests/ffi/regress_43016_test.dart
+++ b/tests/ffi/regress_43016_test.dart
@@ -27,7 +27,6 @@
final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
void main() {
- // Trigger both the runtime entry and the IL in bytecode.
for (int i = 0; i < 10000; i++) {
pass_struct(nullptr);
}
diff --git a/tests/ffi_2/dylib_isolates_test.dart b/tests/ffi_2/dylib_isolates_test.dart
index 5eb73ef..f790e12 100644
--- a/tests/ffi_2/dylib_isolates_test.dart
+++ b/tests/ffi_2/dylib_isolates_test.dart
@@ -7,6 +7,7 @@
// SharedObjects=ffi_test_functions
import 'dart:ffi';
+import 'dart:io';
import 'dart:isolate';
import "package:expect/expect.dart";
@@ -29,7 +30,9 @@
final receivePort = ReceivePort();
Isolate.spawn(secondIsolateMain, receivePort.sendPort);
await receivePort.first;
- Expect.equals(42, getGlobalVar());
+ if (!Platform.isIOS /* Static linking causes different behavior. */) {
+ Expect.equals(42, getGlobalVar());
+ }
}
void secondIsolateMain(SendPort sendPort) {
diff --git a/tests/ffi_2/prepare_flutter_bundle.dart b/tests/ffi_2/prepare_flutter_bundle.dart
index 83a4a42..8ff9447 100644
--- a/tests/ffi_2/prepare_flutter_bundle.dart
+++ b/tests/ffi_2/prepare_flutter_bundle.dart
@@ -6,7 +6,9 @@
import 'dart:io';
import 'package:path/path.dart' as path;
-import 'package:args/args.dart';
+
+// TODO(dacoharkes): Migrate script to be nullsafe and generate nullsafe
+// Flutter app.
main(List<String> args) async {
if (args.length != 1) {
@@ -51,16 +53,34 @@
await generateCleanDir(flutterTestsDir);
- final dartTestsDir = path.join(flutterTestsDir, 'lib/src/generated');
+ final dartTestsDirRelative = 'example/lib';
+ final dartTestsDir = path.join(flutterTestsDir, dartTestsDirRelative);
await generateDartTests(dartTestsDir, allFiles, testFiles);
- final ccDir = path.join(flutterTestsDir, 'ios/Classes');
+ final ccDirRelative = 'ios/Classes';
+ final ccDir = path.join(flutterTestsDir, ccDirRelative);
await generateCLibs(sdkRoot, ccDir, allFiles, testFiles);
- print('');
- print('Please copy generated files into FFI flutter test application');
- print(' * $dartTestsDir');
- print(' * $ccDir');
+ print('''
+
+Files generated in:
+ * $dartTestsDir
+ * $ccDir
+
+Generate flutter test application with:
+ flutter create --platforms=android,ios --template=plugin <ffi_test_app_name>
+
+Please copy generated files into FFI flutter test application:
+ cd <ffi_test_app_dir> && cp -r $flutterTestsDir ./
+
+After copying modify the test application:
+ * Modify example/pubspec.yaml to depend on package:ffi.
+ * Modify example/lib/main.dart to invoke all.dart while rendering.
+ * Open example/ios/Runner.xcworkspace in Xcode.
+ * Add the cpp files to Pods/Development Pods/<deep nesting>/ios/Classes
+ to ensure they are statically linked to the app.
+''');
+ // TODO(dacoharkes): Automate these steps. How to automate the XCode step?
}
void dumpTestList(List<String> testFiles, String message) {
@@ -108,6 +128,12 @@
destinationFile =
path.join(dir.path, path.basename(lib2)).replaceAll('.cc', '.cpp');
File(destinationFile).writeAsStringSync(File(lib2).readAsStringSync());
+
+ final lib3 = path.join(
+ sdkRoot, 'runtime/bin/ffi_test/ffi_test_functions_generated.cc');
+ destinationFile =
+ path.join(dir.path, path.basename(lib3)).replaceAll('.cc', '.cpp');
+ File(destinationFile).writeAsStringSync(File(lib3).readAsStringSync());
}
String cleanDart(String content) {
@@ -159,7 +185,8 @@
Stream<String> listTestFiles(
String sdkRoot, List<String> filteredTests) async* {
- await for (final file in Directory(path.join(sdkRoot, 'tests/ffi')).list()) {
+ await for (final file
+ in Directory(path.join(sdkRoot, 'tests/ffi_2')).list()) {
if (file is File && file.path.endsWith('_test.dart')) {
// These tests are VM specific and cannot necessarily be run on Flutter.
if (path.basename(file.path).startsWith('vmspecific_')) {
diff --git a/tests/ffi_2/regress_37254_test.dart b/tests/ffi_2/regress_37254_test.dart
index dcd42b9..6ba796f 100644
--- a/tests/ffi_2/regress_37254_test.dart
+++ b/tests/ffi_2/regress_37254_test.dart
@@ -238,7 +238,6 @@
}
void main() {
- // Trigger both the runtime entry and the IL in bytecode.
for (int i = 0; i < 100; i++) {
store1();
store2();
diff --git a/tests/ffi_2/regress_43016_test.dart b/tests/ffi_2/regress_43016_test.dart
index 1d06b87..b0ebc0c 100644
--- a/tests/ffi_2/regress_43016_test.dart
+++ b/tests/ffi_2/regress_43016_test.dart
@@ -27,7 +27,6 @@
final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
void main() {
- // Trigger both the runtime entry and the IL in bytecode.
for (int i = 0; i < 10000; i++) {
pass_struct(nullptr);
}
diff --git a/tools/VERSION b/tools/VERSION
index 6a2eb32..ce12cbe 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 11
PATCH 0
-PRERELEASE 273
+PRERELEASE 274
PRERELEASE_PATCH 0
\ No newline at end of file