Version 2.0.0-dev.51.0
Merge commit 'c164f923970465e393b18c1eb31c2b46043f464a' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 83e13f6..710c9a7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,22 @@
+## 2.0.0-dev.51.0
+
+### Tool Changes
+
+#### dartfmt
+ * Fixes a runtime error when dart_style is itself run in Dart 2.
+ * Force splitting an empty block as the then body of an if with an else.
+ * Uses the new lowercase Dart 2 constant names.
+
+#### Pub
+
+* The `build` and `serve` commands will now fail and point users to
+ https://webdev.dartlang.org/dart-2
+
+#### dart2js
+
+* `async` functions now start synchronously. This will be the default behavior
+ across all tools. To temporarily opt-out, use the `--no-sync-async` flag.
+
## 2.0.0-dev.50.0
## 2.0.0-dev.49.0
@@ -13,28 +32,6 @@
## 2.0.0-dev.48.0
-### Language
-
-#### Strong Mode
-
-### Core library changes
-
-### Dart VM
-
-### Tool Changes
-
-#### Pub
-
-#### Other Tools
-
-## 2.0.0-dev.49.0
-
-## 2.0.0-dev.47.0
-
-### Tool Changes
-
-## 2.0.0-dev.48.0
-
### Core library changes
* `dart:core`
diff --git a/DEPS b/DEPS
index 163bf8d..b6218f0 100644
--- a/DEPS
+++ b/DEPS
@@ -81,7 +81,7 @@
# minutes later.
#
# For more details, see https://github.com/dart-lang/sdk/issues/30164
- "dart_style_tag": "@1.0.10", # Please see the note above before updating.
+ "dart_style_tag": "@1.0.11", # Please see the note above before updating.
"dartdoc_tag" : "@v0.18.1",
"fixnum_tag": "@0.10.5",
@@ -114,7 +114,7 @@
"ply_rev": "@604b32590ffad5cbb82e4afef1d305512d06ae93",
"pool_tag": "@1.3.4",
"protobuf_tag": "@0.7.1",
- "pub_rev": "@4947e0b3cb3ec77e4e8fe0d3141ce4dc60f43256",
+ "pub_rev": "@2e821bff00c00889afe5200e3a33f280ce942336",
"pub_semver_tag": "@1.3.7",
"quiver_tag": "@5aaa3f58c48608af5b027444d561270b53f15dbf",
"resource_rev":"@af5a5bf65511943398146cf146e466e5f0b95cb9",
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart
index 1e5973c..ec71bf9 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart
@@ -109,12 +109,8 @@
ClassElement classElement =
resolutionMap.elementDeclaredByClassDeclaration(classDecl);
- int relevance = optype.constructorSuggestionsFilter(
+ int relevance = optype.returnValueSuggestionsFilter(
classElement?.type, DART_RELEVANCE_DEFAULT);
- if (relevance == null) {
- return;
- }
-
if (constructorDecl != null) {
// Build a suggestion for explicitly declared constructor
ConstructorElement element = constructorDecl.element;
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart
index 7966324..d22c4f5 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart
@@ -55,11 +55,9 @@
}
}
if (optype.includeConstructorSuggestions) {
- int relevance = optype.constructorSuggestionsFilter(
+ int relevance = optype.returnValueSuggestionsFilter(
element.type, DART_RELEVANCE_DEFAULT);
- if (relevance != null) {
- _addConstructorSuggestions(element, relevance);
- }
+ _addConstructorSuggestions(element, relevance);
}
if (optype.includeReturnValueSuggestions) {
if (element.isEnum) {
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 051a72d..3ba57d8 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -45,6 +45,7 @@
errorCode == CompileTimeErrorCode.INVALID_ANNOTATION ||
errorCode == CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_EXPLICIT ||
errorCode == CompileTimeErrorCode.PART_OF_NON_PART ||
+ errorCode == CompileTimeErrorCode.UNDEFINED_ANNOTATION ||
errorCode ==
CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT ||
errorCode == CompileTimeErrorCode.URI_DOES_NOT_EXIST ||
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 869f385..580e541 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -214,7 +214,8 @@
errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER_AWAIT) {
await _addFix_addAsync();
}
- if (errorCode == CompileTimeErrorCode.INVALID_ANNOTATION) {
+ if (errorCode == CompileTimeErrorCode.INVALID_ANNOTATION ||
+ errorCode == CompileTimeErrorCode.UNDEFINED_ANNOTATION) {
if (node is Annotation) {
Annotation annotation = node;
Identifier name = annotation.name;
diff --git a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
index 6f5f0d9..558129a 100644
--- a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
+++ b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
@@ -43,6 +43,12 @@
*/
bool get isNullExpectedReturnTypeConsideredDynamic => true;
+ /**
+ * Return `true` if contributors should suggest constructors in contexts where
+ * there is no `new` or `const` keyword.
+ */
+ bool get suggestConstructorsWithoutNew => false;
+
bool get usingFastaParser => analyzer.Parser.useFasta;
void addTestSource(String content) {
diff --git a/pkg/analysis_server/test/services/completion/dart/imported_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/imported_reference_contributor_test.dart
index a72473f..8f6efea 100644
--- a/pkg/analysis_server/test/services/completion/dart/imported_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/imported_reference_contributor_test.dart
@@ -529,7 +529,7 @@
assertNotSuggested('a');
assertNotSuggested('main');
assertSuggestClass('A');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
}
assertSuggestClass('Object');
@@ -621,7 +621,7 @@
assertNotSuggested('partT8');
assertSuggestClass('A', elemFile: '/testAB.dart');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
}
assertNotSuggested('_B');
@@ -1194,7 +1194,7 @@
class Z { }''');
await computeSuggestions();
assertSuggestClass('C');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('C');
}
assertNotSuggested('H');
@@ -1580,7 +1580,7 @@
assertNotSuggested('F2');
assertNotSuggested('T2');
assertSuggestClass('A');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
}
assertSuggestFunction('F1', 'dynamic');
@@ -1629,7 +1629,7 @@
assertNotSuggested('F2');
assertNotSuggested('T2');
assertSuggestClass('A');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
}
assertSuggestFunction('F1', 'dynamic');
@@ -1802,7 +1802,7 @@
expect(suggestion.docSummary, 'My class.\nShort description.');
expect(suggestion.docComplete,
'My class.\nShort description.\n\nLonger description.');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
}
}
@@ -1908,7 +1908,7 @@
expect(replacementOffset, completionOffset);
expect(replacementLength, 0);
assertSuggestClass('A');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
}
assertSuggestFunction('F1', '_B');
@@ -2488,7 +2488,7 @@
assertNotSuggested('F2');
assertNotSuggested('T2');
assertSuggestClass('A');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
}
assertSuggestFunction('F1', 'dynamic');
@@ -2629,7 +2629,7 @@
assertSuggestConstructor('C',
elemOffset: -1,
relevance: DART_RELEVANCE_DEFAULT + DART_RELEVANCE_BOOST_SUBTYPE);
- assertNotSuggested('D');
+ assertSuggestConstructor('D', elemOffset: -1);
}
test_InstanceCreationExpression_imported() async {
@@ -2711,7 +2711,7 @@
await computeSuggestions();
expect(replacementOffset, completionOffset);
expect(replacementLength, 0);
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('Object');
assertSuggestConstructor('C1');
} else {
@@ -2995,7 +2995,7 @@
expect(replacementOffset, completionOffset);
expect(replacementLength, 0);
assertSuggestClass('Object');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('Object');
}
// Simulate unresolved imported library,
@@ -3246,7 +3246,7 @@
assertNotSuggested('f');
assertNotSuggested('_g');
assertSuggestClass('bool');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
// TODO(brianwilkerson) Should not suggest constructors for classes that
// cannot be instantiated.
assertSuggestConstructor('bool');
@@ -3494,7 +3494,7 @@
await computeSuggestions();
assertSuggestClass('ClassInLocalContext');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('ClassInLocalContext');
}
// Assert contributor does not include results from 2nd context.
@@ -3876,7 +3876,7 @@
expect(replacementOffset, completionOffset - 1);
expect(replacementLength, 1);
assertSuggestClass('A');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
}
assertNotSuggested('X');
diff --git a/pkg/analysis_server/test/services/completion/dart/local_constructor_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/local_constructor_contributor_test.dart
index e6dfb14..473e297 100644
--- a/pkg/analysis_server/test/services/completion/dart/local_constructor_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/local_constructor_contributor_test.dart
@@ -91,7 +91,7 @@
assertNotSuggested('bar');
assertNotSuggested('hasLength');
assertNotSuggested('identical');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('B');
} else {
assertNotSuggested('B');
@@ -122,7 +122,7 @@
assertNotSuggested('bar');
assertNotSuggested('hasLength');
assertNotSuggested('identical');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('B');
} else {
assertNotSuggested('B');
@@ -154,7 +154,7 @@
assertNotSuggested('bar');
assertNotSuggested('hasLength');
assertNotSuggested('identical');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('B');
} else {
assertNotSuggested('B');
@@ -188,7 +188,7 @@
assertNotSuggested('bar');
assertNotSuggested('hasLength');
assertNotSuggested('identical');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('B');
} else {
assertNotSuggested('B');
@@ -220,7 +220,7 @@
assertNotSuggested('bar');
assertNotSuggested('hasLength');
assertNotSuggested('identical');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('B');
} else {
assertNotSuggested('B');
@@ -251,7 +251,7 @@
assertNotSuggested('bar');
assertNotSuggested('hasLength');
assertNotSuggested('identical');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('B');
} else {
assertNotSuggested('B');
@@ -283,7 +283,7 @@
assertNotSuggested('bar');
assertNotSuggested('hasLength');
assertNotSuggested('identical');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('B');
} else {
assertNotSuggested('B');
@@ -314,7 +314,7 @@
assertNoSuggestions(kind: CompletionSuggestionKind.ARGUMENT_LIST);
assertNotSuggested('hasLength');
assertNotSuggested('identical');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('B');
} else {
assertNotSuggested('B');
@@ -379,7 +379,7 @@
expect(replacementLength, 0);
assertNotSuggested('a');
assertNotSuggested('main');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
} else {
assertNotSuggested('A');
@@ -399,7 +399,7 @@
expect(replacementOffset, completionOffset);
expect(replacementLength, 0);
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
} else {
assertNotSuggested('A');
@@ -428,7 +428,7 @@
expect(replacementOffset, completionOffset);
expect(replacementLength, 0);
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
} else {
assertNotSuggested('A');
@@ -454,7 +454,7 @@
expect(replacementOffset, completionOffset - 3);
expect(replacementLength, 3);
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
} else {
assertNotSuggested('A');
@@ -483,7 +483,7 @@
expect(replacementOffset, completionOffset - 1);
expect(replacementLength, 1);
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
} else {
assertNotSuggested('A');
@@ -508,7 +508,7 @@
expect(replacementLength, 0);
assertNotSuggested('a');
assertNotSuggested('main');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
} else {
assertNotSuggested('A');
@@ -589,7 +589,7 @@
expect(replacementOffset, completionOffset);
expect(replacementLength, 0);
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('X');
assertSuggestConstructor('Z');
} else {
@@ -987,7 +987,7 @@
expect(replacementOffset, completionOffset - 1);
expect(replacementLength, 1);
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('X');
assertSuggestConstructor('Z');
} else {
@@ -1241,7 +1241,7 @@
assertNotSuggested('b');
assertNotSuggested('_c');
assertNotSuggested('a');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
assertSuggestConstructor('X');
} else {
@@ -1518,7 +1518,7 @@
assertNotSuggested('x');
assertNotSuggested('f');
assertNotSuggested('foo');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('C');
} else {
assertNotSuggested('C');
@@ -1568,7 +1568,7 @@
assertNotSuggested('x');
assertNotSuggested('f');
assertNotSuggested('foo');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('C');
} else {
assertNotSuggested('C');
@@ -1758,7 +1758,7 @@
expect(replacementLength, 0);
assertNotSuggested('foo');
assertNotSuggested('a');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
} else {
assertNotSuggested('A');
@@ -1801,7 +1801,7 @@
expect(replacementLength, 0);
assertNotSuggested('A');
assertNotSuggested('F1');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('C');
} else {
assertNotSuggested('C');
@@ -2190,7 +2190,7 @@
assertNotSuggested('b');
assertNotSuggested('_c');
assertNotSuggested('Object');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
} else {
assertNotSuggested('A');
@@ -2209,7 +2209,7 @@
expect(replacementLength, 0);
assertNotSuggested('a');
assertNotSuggested('main');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
} else {
assertNotSuggested('A');
@@ -2228,7 +2228,7 @@
assertNotSuggested('b');
assertNotSuggested('_c');
assertNotSuggested('Object');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
} else {
assertNotSuggested('A');
@@ -2316,7 +2316,7 @@
assertNotSuggested('x');
assertNotSuggested('f');
assertNotSuggested('foo');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('C');
} else {
assertNotSuggested('C');
@@ -2439,7 +2439,7 @@
assertSuggestConstructor('C',
elemOffset: -1,
relevance: DART_RELEVANCE_DEFAULT + DART_RELEVANCE_BOOST_SUBTYPE);
- assertNotSuggested('D');
+ assertSuggestConstructor('D', elemOffset: -1);
}
test_InstanceCreationExpression_assignment_expression_filter2() async {
@@ -2460,7 +2460,7 @@
assertSuggestConstructor('C',
elemOffset: -1,
relevance: DART_RELEVANCE_DEFAULT + DART_RELEVANCE_BOOST_SUBTYPE);
- assertNotSuggested('D');
+ assertSuggestConstructor('D', elemOffset: -1);
}
test_InstanceCreationExpression_imported() async {
@@ -2509,7 +2509,7 @@
assertSuggestConstructor('B',
elemOffset: -1,
relevance: DART_RELEVANCE_DEFAULT + DART_RELEVANCE_BOOST_SUBTYPE);
- assertNotSuggested('C');
+ assertSuggestConstructor('C', elemOffset: -1);
}
test_InstanceCreationExpression_invocationArgument_named() async {
@@ -2527,7 +2527,7 @@
assertSuggestConstructor('B',
elemOffset: -1,
relevance: DART_RELEVANCE_DEFAULT + DART_RELEVANCE_BOOST_SUBTYPE);
- assertNotSuggested('C');
+ assertSuggestConstructor('C', elemOffset: -1);
}
test_InstanceCreationExpression_unimported() async {
@@ -2559,7 +2559,7 @@
assertSuggestConstructor('C',
elemOffset: -1,
relevance: DART_RELEVANCE_DEFAULT + DART_RELEVANCE_BOOST_SUBTYPE);
- assertNotSuggested('D');
+ assertSuggestConstructor('D', elemOffset: -1);
}
test_InstanceCreationExpression_variable_declaration_filter2() async {
@@ -2579,7 +2579,7 @@
assertSuggestConstructor('C',
elemOffset: -1,
relevance: DART_RELEVANCE_DEFAULT + DART_RELEVANCE_BOOST_SUBTYPE);
- assertNotSuggested('D');
+ assertSuggestConstructor('D', elemOffset: -1);
}
test_InterpolationExpression() async {
@@ -2608,7 +2608,7 @@
assertNotSuggested('T2');
assertNotSuggested('F2');
assertNotSuggested('D2');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('C2');
} else {
assertNotSuggested('C2');
@@ -2642,7 +2642,7 @@
assertNotSuggested('T2');
assertNotSuggested('F2');
assertNotSuggested('D2');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('C2');
} else {
assertNotSuggested('C2');
@@ -2728,7 +2728,7 @@
assertNotSuggested('main');
assertNotSuggested('foo');
assertNotSuggested('bar');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
} else {
assertNotSuggested('A');
@@ -2853,7 +2853,7 @@
assertNotSuggested('T2');
assertNotSuggested('F2');
assertNotSuggested('D2');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('C2');
} else {
assertNotSuggested('C2');
@@ -3579,7 +3579,7 @@
expect(replacementOffset, completionOffset - 1);
expect(replacementLength, 1);
assertNotSuggested('A');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('X');
} else {
assertNotSuggested('X');
@@ -3785,7 +3785,7 @@
addTestSource('class A {String g(int x) {var t; switch(x) {case 0: ^}}}');
await computeSuggestions();
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
} else {
assertNotSuggested('A');
@@ -4135,7 +4135,7 @@
assertNotSuggested('X');
assertNotSuggested('_B');
assertNotSuggested('Y');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('C');
} else {
assertNotSuggested('C');
@@ -4171,7 +4171,7 @@
assertNotSuggested('bar2');
assertNotSuggested('_B');
assertNotSuggested('Y');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('C');
} else {
assertNotSuggested('C');
diff --git a/pkg/analysis_server/test/services/completion/dart/local_library_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/local_library_contributor_test.dart
index 0df1a0b..e3d07b2 100644
--- a/pkg/analysis_server/test/services/completion/dart/local_library_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/local_library_contributor_test.dart
@@ -128,8 +128,8 @@
assertSuggestConstructor('C',
elemOffset: -1,
relevance: DART_RELEVANCE_DEFAULT + DART_RELEVANCE_BOOST_SUBTYPE);
- // D is sorted out
- assertNotSuggested('D');
+ // D has the default relevance
+ assertSuggestConstructor('D', elemOffset: -1);
// Suggested by ConstructorContributor
assertNotSuggested('Local');
@@ -179,8 +179,8 @@
assertSuggestConstructor('C',
elemOffset: -1,
relevance: DART_RELEVANCE_DEFAULT + DART_RELEVANCE_BOOST_SUBTYPE);
- // D is sorted out
- assertNotSuggested('D');
+ // D has the default relevance
+ assertSuggestConstructor('D', elemOffset: -1);
// Suggested by ConstructorContributor
assertNotSuggested('Local');
@@ -219,7 +219,7 @@
expect(replacementOffset, completionOffset);
expect(replacementLength, 0);
assertSuggestClass('A');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('A');
}
assertSuggestFunction('af', 'int',
@@ -266,7 +266,7 @@
expect(replacementOffset, completionOffset);
expect(replacementLength, 0);
assertSuggestClass('B');
- if (previewDart2) {
+ if (suggestConstructorsWithoutNew) {
assertSuggestConstructor('B');
}
assertSuggestFunction('bf', 'int',
diff --git a/pkg/analysis_server/test/services/completion/dart/override_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/override_contributor_test.dart
index 9b27990..73bc6b4 100644
--- a/pkg/analysis_server/test/services/completion/dart/override_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/override_contributor_test.dart
@@ -176,6 +176,53 @@
selectionLength: 22);
}
+ @failingTest
+ test_withOverrideAnnotation() async {
+ addTestSource('''
+class A {
+ method() {}
+ int age;
+}
+
+class B extends A {
+ @override
+ ^
+}
+''');
+ await computeSuggestions();
+ _assertOverride('''
+method() {
+ // TODO: implement method
+ return super.method();
+ }''',
+ displayText: 'method() { … }',
+ selectionOffset: 45,
+ selectionLength: 22);
+ }
+
+ @failingTest
+ test_insideBareClass() async {
+ addTestSource('''
+class A {
+ method() {}
+ int age;
+}
+
+class B extends A {
+ ^
+}
+''');
+ await computeSuggestions();
+ _assertOverride('''
+method() {
+ // TODO: implement method
+ return super.method();
+ }''',
+ displayText: 'method() { … }',
+ selectionOffset: 45,
+ selectionLength: 22);
+ }
+
CompletionSuggestion _assertOverride(String completion,
{String displayText, int selectionOffset, int selectionLength}) {
CompletionSuggestion cs = getSuggest(
diff --git a/pkg/analysis_server/test/services/correction/assist_test.dart b/pkg/analysis_server/test/services/correction/assist_test.dart
index 6600839e..72e36b6 100644
--- a/pkg/analysis_server/test/services/correction/assist_test.dart
+++ b/pkg/analysis_server/test/services/correction/assist_test.dart
@@ -38,6 +38,8 @@
String resultCode;
LinkedEditGroup linkedPositionGroup;
+ bool get omitNew => false;
+
/**
* Asserts that there is an [Assist] of the given [kind] at [offset] which
* produces the [expected] code when applied to [testCode].
@@ -3538,7 +3540,7 @@
}
''');
_setCaretLocation();
- if (previewDart2) {
+ if (omitNew) {
await assertHasAssist(DartAssistKind.FLUTTER_WRAP_CENTER, '''
import 'package:flutter/widgets.dart';
class FakeFlutter {
@@ -3595,7 +3597,7 @@
}
''');
_setCaretLocation();
- if (previewDart2) {
+ if (omitNew) {
await assertHasAssist(DartAssistKind.FLUTTER_WRAP_COLUMN, '''
import 'package:flutter/widgets.dart';
@@ -3649,7 +3651,7 @@
}
''');
_setStartEndSelection();
- if (previewDart2) {
+ if (omitNew) {
await assertHasAssist(DartAssistKind.FLUTTER_WRAP_COLUMN, '''
import 'package:flutter/widgets.dart';
@@ -3747,7 +3749,7 @@
}
''');
_setCaretLocation();
- if (previewDart2) {
+ if (omitNew) {
await assertHasAssist(DartAssistKind.FLUTTER_WRAP_PADDING, '''
import 'package:flutter/widgets.dart';
class FakeFlutter {
@@ -3793,7 +3795,7 @@
}
''');
_setStartEndSelection();
- if (previewDart2) {
+ if (omitNew) {
await assertHasAssist(DartAssistKind.FLUTTER_WRAP_ROW, '''
import 'package:flutter/widgets.dart';
@@ -3950,7 +3952,7 @@
}
''');
_setCaretLocation();
- if (previewDart2) {
+ if (omitNew) {
await assertHasAssist(DartAssistKind.FLUTTER_WRAP_GENERIC, '''
import 'package:flutter/widgets.dart';
class FakeFlutter {
@@ -4019,7 +4021,7 @@
}\r
''');
_setCaretLocation();
- if (previewDart2) {
+ if (omitNew) {
await assertHasAssist(DartAssistKind.FLUTTER_WRAP_GENERIC, '''
import 'package:flutter/widgets.dart';
class FakeFlutter {\r
@@ -4079,7 +4081,7 @@
}
''');
_setCaretLocation();
- if (previewDart2) {
+ if (omitNew) {
await assertHasAssist(DartAssistKind.FLUTTER_WRAP_GENERIC, '''
import 'package:flutter/widgets.dart';
class FakeFlutter {
@@ -4115,7 +4117,7 @@
}
''');
_setCaretLocation();
- if (previewDart2) {
+ if (omitNew) {
await assertHasAssist(DartAssistKind.FLUTTER_WRAP_GENERIC, '''
import 'package:flutter/widgets.dart';
class FakeFlutter {
@@ -4148,7 +4150,7 @@
}
''');
_setCaretLocation();
- if (previewDart2) {
+ if (omitNew) {
await assertHasAssist(DartAssistKind.FLUTTER_WRAP_GENERIC, '''
import 'package:flutter/widgets.dart';
class FakeFlutter {
diff --git a/pkg/analyzer/doc/tasks.html b/pkg/analyzer/doc/tasks.html
index 960dc69..e2de682 100644
--- a/pkg/analyzer/doc/tasks.html
+++ b/pkg/analyzer/doc/tasks.html
@@ -344,7 +344,6 @@
TYPE_PROVIDER -> PartiallyResolveUnitReferencesTask
TYPE_PROVIDER -> ResolveInstanceFieldsInUnitTask
TYPE_PROVIDER -> ResolveLibraryTypeNamesTask
- TYPE_PROVIDER -> ResolveTopLevelUnitTypeBoundsTask
TYPE_PROVIDER -> ResolveUnitTask
TYPE_PROVIDER -> ResolveUnitTypeNamesTask
TYPE_PROVIDER -> ResolveVariableReferencesTask
diff --git a/pkg/analyzer/lib/dart/analysis/session.dart b/pkg/analyzer/lib/dart/analysis/session.dart
index 8e58253..a39a2f7 100644
--- a/pkg/analyzer/lib/dart/analysis/session.dart
+++ b/pkg/analyzer/lib/dart/analysis/session.dart
@@ -59,6 +59,12 @@
Future<ParseResult> getParsedAst(String path);
/**
+ * Return information about the results of parsing the file with the given
+ * absolute, normalized [path].
+ */
+ ParseResult getParsedAstSync(String path);
+
+ /**
* Return a future that will complete with information about the results of
* resolving the file with the given absolute, normalized [path].
*/
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index beb7369..b2743a7 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -151,6 +151,7 @@
CompileTimeErrorCode.INTEGER_LITERAL_OUT_OF_RANGE,
CompileTimeErrorCode.INVALID_ANNOTATION,
CompileTimeErrorCode.INVALID_ANNOTATION_FROM_DEFERRED_LIBRARY,
+ CompileTimeErrorCode.INVALID_ANNOTATION_GETTER,
CompileTimeErrorCode.INVALID_CONSTANT,
CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME,
CompileTimeErrorCode.INVALID_FACTORY_NAME_NOT_A_CLASS,
@@ -231,6 +232,7 @@
CompileTimeErrorCode.SUPER_IN_REDIRECTING_CONSTRUCTOR,
CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF,
CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS,
+ CompileTimeErrorCode.UNDEFINED_ANNOTATION,
CompileTimeErrorCode.UNDEFINED_CLASS,
CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER,
CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT,
diff --git a/pkg/analyzer/lib/src/command_line/arguments.dart b/pkg/analyzer/lib/src/command_line/arguments.dart
index c4f50a40..263d250 100644
--- a/pkg/analyzer/lib/src/command_line/arguments.dart
+++ b/pkg/analyzer/lib/src/command_line/arguments.dart
@@ -65,10 +65,8 @@
options.implicitDynamic = !args[noImplicitDynamicFlag];
verbose('$noImplicitDynamicFlag = ${options.implicitDynamic}');
}
- if (args.wasParsed(strongModeFlag)) {
- options.strongMode = args[strongModeFlag];
- verbose('$strongModeFlag = ${options.strongMode}');
- }
+ options.strongMode = args[strongModeFlag];
+ verbose('$strongModeFlag = ${options.strongMode}');
try {
if (args.wasParsed(lintsFlag)) {
options.lint = args[lintsFlag];
@@ -178,8 +176,9 @@
hide: ddc && hide);
parser.addFlag(strongModeFlag,
help: 'Enable strong static checks (https://goo.gl/DqcBsw).',
- defaultsTo: ddc,
- hide: ddc);
+ defaultsTo: true,
+ hide: ddc,
+ negatable: true);
parser.addFlag(declarationCastsFlag,
negatable: true,
help: 'Disable declaration casts in strong mode (https://goo.gl/cTLz40).',
@@ -294,6 +293,9 @@
if (abbreviation != null) {
knownAbbreviations.add(abbreviation);
}
+ if (option.negatable) {
+ knownOptions.add('no-$name');
+ }
});
String optionName(int prefixLength, String argument) {
int equalsOffset = argument.lastIndexOf('=');
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index d48b1d6..8085a6b 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -855,6 +855,21 @@
* resolved unit).
*/
Future<ParseResult> parseFile(String path) async {
+ return parseFileSync(path);
+ }
+
+ /**
+ * Return a [ParseResult] for the file with the given [path].
+ *
+ * The [path] must be absolute and normalized.
+ *
+ * The [path] can be any file - explicitly or implicitly analyzed, or neither.
+ *
+ * The parsing is performed in the method itself, and the result is not
+ * produced through the [results] stream (just because it is not a fully
+ * resolved unit).
+ */
+ ParseResult parseFileSync(String path) {
_throwIfNotAbsolutePath(path);
FileState file = _fileTracker.verifyApiSignature(path);
RecordingErrorListener listener = new RecordingErrorListener();
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index e16375c..b3b5230 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -34,6 +34,8 @@
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/kernel/resynthesize.dart';
+import 'package:analyzer/src/lint/linter.dart';
+import 'package:analyzer/src/lint/linter_visitor.dart';
import 'package:analyzer/src/services/lint.dart';
import 'package:analyzer/src/task/dart.dart';
import 'package:analyzer/src/task/strong/checker.dart';
@@ -353,22 +355,34 @@
ErrorReporter errorReporter = _getErrorReporter(file);
- List<AstVisitor> visitors = <AstVisitor>[];
+ var nodeRegistry = new NodeLintRegistry(_analysisOptions.enableTiming);
+ var visitors = <AstVisitor>[];
for (Linter linter in _analysisOptions.lintRules) {
- AstVisitor visitor = linter.getVisitor();
- if (visitor != null) {
- linter.reporter = errorReporter;
- if (_analysisOptions.enableTiming) {
- visitor = new TimedAstVisitor(visitor, lintRegistry.getTimer(linter));
+ linter.reporter = errorReporter;
+ if (linter is NodeLintRule) {
+ (linter as NodeLintRule).registerNodeProcessors(nodeRegistry);
+ } else {
+ AstVisitor visitor = linter.getVisitor();
+ if (visitor != null) {
+ if (_analysisOptions.enableTiming) {
+ var timer = lintRegistry.getTimer(linter);
+ visitor = new TimedAstVisitor(visitor, timer);
+ }
+ visitors.add(visitor);
}
- visitors.add(visitor);
}
}
- AstVisitor visitor = new ExceptionHandlingDelegatingAstVisitor(
- visitors, ExceptionHandlingDelegatingAstVisitor.logException);
+ // Run lints that handle specific node types.
+ unit.accept(new LinterVisitor(
+ nodeRegistry, ExceptionHandlingDelegatingAstVisitor.logException));
- unit.accept(visitor);
+ // Run visitor based lints.
+ if (visitors.isNotEmpty) {
+ AstVisitor visitor = new ExceptionHandlingDelegatingAstVisitor(
+ visitors, ExceptionHandlingDelegatingAstVisitor.logException);
+ unit.accept(visitor);
+ }
}
void _computePendingMissingRequiredParameters(
diff --git a/pkg/analyzer/lib/src/dart/analysis/session.dart b/pkg/analyzer/lib/src/dart/analysis/session.dart
index caadbdb..37ad32e 100644
--- a/pkg/analyzer/lib/src/dart/analysis/session.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/session.dart
@@ -86,9 +86,14 @@
}
@override
- Future<ParseResult> getParsedAst(String path) {
+ Future<ParseResult> getParsedAst(String path) async {
+ return getParsedAstSync(path);
+ }
+
+ @override
+ ParseResult getParsedAstSync(String path) {
_checkConsistency();
- return _driver.parseFile(path);
+ return _driver.parseFileSync(path);
}
@override
diff --git a/pkg/analyzer/lib/src/dart/ast/token.dart b/pkg/analyzer/lib/src/dart/ast/token.dart
index 09da763..4b0b503 100644
--- a/pkg/analyzer/lib/src/dart/ast/token.dart
+++ b/pkg/analyzer/lib/src/dart/ast/token.dart
@@ -12,6 +12,8 @@
KeywordToken,
SimpleToken,
StringToken,
+ SyntheticBeginToken,
SyntheticKeywordToken,
SyntheticStringToken,
+ SyntheticToken,
TokenClass;
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index c3dba9c..1ee3f0b 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -2768,8 +2768,8 @@
* A function that can be used with instances of this class to log and then
* ignore any exceptions that are thrown by any of the delegates.
*/
- static void logException(AstNode node, AstVisitor visitor, dynamic exception,
- StackTrace stackTrace) {
+ static void logException(
+ AstNode node, Object visitor, dynamic exception, StackTrace stackTrace) {
StringBuffer buffer = new StringBuffer();
buffer.write('Exception while using a ${visitor.runtimeType} to visit a ');
AstNode currentNode = node;
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index 63cfad3..4be6d72 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -1408,6 +1408,17 @@
"changing the import to not be deferred.");
/**
+ * 15 Metadata: Metadata consists of a series of annotations, each of which
+ * begin with the character @, followed by a constant expression that must be
+ * either a reference to a compile-time constant variable, or a call to a
+ * constant constructor.
+ */
+ static const CompileTimeErrorCode INVALID_ANNOTATION_GETTER =
+ const CompileTimeErrorCode(
+ 'INVALID_ANNOTATION_GETTER', "Getters cannot be used as annotations.",
+ correction: "Try using a top-level variable or a field.");
+
+ /**
* 15.31 Identifier Reference: It is a compile-time error if any of the
* identifiers async, await or yield is used as an identifier in a function
* body marked with either async, async* or sync*.
@@ -2399,6 +2410,19 @@
"another typedef.");
/**
+ * 15 Metadata: Metadata consists of a series of annotations, each of which
+ * begin with the character @, followed by a constant expression that must be
+ * either a reference to a compile-time constant variable, or a call to a
+ * constant constructor.
+ */
+ static const CompileTimeErrorCode UNDEFINED_ANNOTATION =
+ const CompileTimeErrorCode(
+ 'UNDEFINED_ANNOTATION', "Undefined name '{0}' used as an annotation.",
+ correction:
+ "Try defining the name or importing it from another library.",
+ isUnresolvedIdentifier: true);
+
+ /**
* 16.12.2 Const: It is a compile-time error if <i>T</i> is not a class
* accessible in the current scope, optionally followed by type arguments.
*/
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index bb67cb9..9c01d75 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -526,8 +526,14 @@
Statement elsePart = popIfNotNull(elseToken);
Statement thenPart = pop();
ParenthesizedExpression condition = pop();
- push(ast.ifStatement(ifToken, condition.leftParenthesis, condition,
- condition.rightParenthesis, thenPart, elseToken, elsePart));
+ push(ast.ifStatement(
+ ifToken,
+ condition.leftParenthesis,
+ condition.expression,
+ condition.rightParenthesis,
+ thenPart,
+ elseToken,
+ elsePart));
}
void handleNoInitializers() {
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 0e14ee2..94c6855 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -953,7 +953,9 @@
AstNode parent = node.parent;
if (parent is Annotation) {
_resolver.errorReporter.reportErrorForNode(
- CompileTimeErrorCode.INVALID_ANNOTATION, parent);
+ CompileTimeErrorCode.UNDEFINED_ANNOTATION,
+ parent,
+ [identifier.name]);
} else {
_resolver.errorReporter.reportErrorForNode(
StaticWarningCode.UNDEFINED_GETTER,
@@ -1148,7 +1150,7 @@
CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME, node);
} else if (parent is Annotation) {
_resolver.errorReporter.reportErrorForNode(
- CompileTimeErrorCode.INVALID_ANNOTATION, parent);
+ CompileTimeErrorCode.UNDEFINED_ANNOTATION, parent, [node.name]);
} else if (element != null) {
_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
@@ -1989,7 +1991,8 @@
}
}
SimpleIdentifier nameNode3 = annotation.constructorName;
- ConstructorElement constructor = null;
+ ConstructorElement constructor;
+ bool undefined = false;
//
// CONST or Class(args)
//
@@ -2004,6 +2007,8 @@
if (element1 is ClassElement) {
constructor = new InterfaceTypeImpl(element1)
.lookUpConstructor(null, _definingLibrary);
+ } else if (element1 == null) {
+ undefined = true;
}
}
//
@@ -2033,6 +2038,9 @@
.lookUpConstructor(nameNode2.name, _definingLibrary);
nameNode2.staticElement = constructor;
}
+ if (element1 == null && element2 == null) {
+ undefined = true;
+ }
}
//
// prefix.Class.CONST or prefix.Class.constructor(args)
@@ -2055,12 +2063,17 @@
constructor = new InterfaceTypeImpl(element2)
.lookUpConstructor(name3, _definingLibrary);
nameNode3.staticElement = constructor;
+ } else if (element2 == null) {
+ undefined = true;
}
}
// we need constructor
if (constructor == null) {
- _resolver.errorReporter.reportErrorForNode(
- CompileTimeErrorCode.INVALID_ANNOTATION, annotation);
+ if (!undefined) {
+ // If the class was not found then we've already reported the error.
+ _resolver.errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.INVALID_ANNOTATION, annotation);
+ }
return;
}
// record element
@@ -2074,7 +2087,7 @@
// accessor should be synthetic
if (!accessorElement.isSynthetic) {
_resolver.errorReporter.reportErrorForNode(
- CompileTimeErrorCode.INVALID_ANNOTATION, annotation);
+ CompileTimeErrorCode.INVALID_ANNOTATION_GETTER, annotation);
return;
}
// variable should be constant
@@ -2082,6 +2095,7 @@
if (!variableElement.isConst) {
_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.INVALID_ANNOTATION, annotation);
+ return;
}
// no arguments
if (annotation.arguments != null) {
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 56d147d..d04d6ad 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -1440,7 +1440,7 @@
@override
bool preserveComments = true;
- bool _strongMode = false;
+ bool _strongMode = true;
/**
* A flag indicating whether strong-mode inference hints should be
@@ -1457,7 +1457,7 @@
bool useFastaParser = false;
@override
- bool previewDart2 = false;
+ bool previewDart2 = true;
@override
bool disableCacheFlushing = false;
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 281110b..f13507a 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -2321,7 +2321,7 @@
if (_inGenerator) {
return;
} else if (_inAsync) {
- if (expectedReturnType.isDynamic) {
+ if (expectedReturnType.isDynamic || expectedReturnType.isVoid) {
return;
}
if (expectedReturnType is InterfaceType &&
@@ -2329,6 +2329,7 @@
DartType futureArgument = expectedReturnType.typeArguments[0];
if (futureArgument.isDynamic ||
futureArgument.isDartCoreNull ||
+ futureArgument.isVoid ||
futureArgument.isObject) {
return;
}
diff --git a/pkg/analyzer/lib/src/lint/linter.dart b/pkg/analyzer/lib/src/lint/linter.dart
index 8f774d5..92e25c4 100644
--- a/pkg/analyzer/lib/src/lint/linter.dart
+++ b/pkg/analyzer/lib/src/lint/linter.dart
@@ -16,6 +16,7 @@
import 'package:analyzer/src/lint/analysis.dart';
import 'package:analyzer/src/lint/config.dart';
import 'package:analyzer/src/lint/io.dart';
+import 'package:analyzer/src/lint/linter_visitor.dart' show NodeLintRegistry;
import 'package:analyzer/src/lint/project.dart';
import 'package:analyzer/src/lint/pub.dart';
import 'package:analyzer/src/lint/registry.dart';
@@ -23,6 +24,8 @@
import 'package:glob/glob.dart';
import 'package:path/path.dart' as p;
+export 'package:analyzer/src/lint/linter_visitor.dart' show NodeLintRegistry;
+
typedef Printer(String msg);
/// Describes a String in valid camel case format.
@@ -319,6 +322,14 @@
int compareTo(Maturity other) => this.ordinal - other.ordinal;
}
+/// [LintRule]s that implement this interface want to process only some types
+/// of AST nodes, and will register their processors in the registry.
+abstract class NodeLintRule {
+ /// This method is invoked to let the [LintRule] register node processors
+ /// in the given [registry].
+ void registerNodeProcessors(NodeLintRegistry registry);
+}
+
class PrintingReporter implements Reporter, Logger {
final Printer _print;
diff --git a/pkg/analyzer/lib/src/lint/linter_visitor.dart b/pkg/analyzer/lib/src/lint/linter_visitor.dart
new file mode 100644
index 0000000..141d3d46
--- /dev/null
+++ b/pkg/analyzer/lib/src/lint/linter_visitor.dart
@@ -0,0 +1,1323 @@
+// Copyright (c) 2018, 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:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/src/lint/linter.dart';
+import 'package:analyzer/src/services/lint.dart';
+
+/// The type of the function that handles exceptions in lints.
+typedef void LintRuleExceptionHandler(
+ AstNode node, LintRule linter, dynamic exception, StackTrace stackTrace);
+
+/// The AST visitor that runs handlers for nodes from the [registry].
+class LinterVisitor extends RecursiveAstVisitor<void> {
+ final NodeLintRegistry registry;
+ final LintRuleExceptionHandler exceptionHandler;
+
+ LinterVisitor(this.registry, this.exceptionHandler);
+
+ @override
+ void visitAsExpression(AsExpression node) {
+ _runSubscriptions(node, registry._forAsExpression);
+ super.visitAsExpression(node);
+ }
+
+ @override
+ void visitAssertInitializer(AssertInitializer node) {
+ _runSubscriptions(node, registry._forAssertInitializer);
+ super.visitAssertInitializer(node);
+ }
+
+ @override
+ void visitAssertStatement(AssertStatement node) {
+ _runSubscriptions(node, registry._forAssertStatement);
+ super.visitAssertStatement(node);
+ }
+
+ @override
+ void visitAssignmentExpression(AssignmentExpression node) {
+ _runSubscriptions(node, registry._forAssignmentExpression);
+ super.visitAssignmentExpression(node);
+ }
+
+ @override
+ void visitAwaitExpression(AwaitExpression node) {
+ _runSubscriptions(node, registry._forAwaitExpression);
+ super.visitAwaitExpression(node);
+ }
+
+ @override
+ void visitBinaryExpression(BinaryExpression node) {
+ _runSubscriptions(node, registry._forBinaryExpression);
+ super.visitBinaryExpression(node);
+ }
+
+ @override
+ void visitBlock(Block node) {
+ _runSubscriptions(node, registry._forBlock);
+ super.visitBlock(node);
+ }
+
+ @override
+ void visitBlockFunctionBody(BlockFunctionBody node) {
+ _runSubscriptions(node, registry._forBlockFunctionBody);
+ super.visitBlockFunctionBody(node);
+ }
+
+ @override
+ void visitBooleanLiteral(BooleanLiteral node) {
+ _runSubscriptions(node, registry._forBooleanLiteral);
+ super.visitBooleanLiteral(node);
+ }
+
+ @override
+ void visitBreakStatement(BreakStatement node) {
+ _runSubscriptions(node, registry._forBreakStatement);
+ super.visitBreakStatement(node);
+ }
+
+ @override
+ void visitCascadeExpression(CascadeExpression node) {
+ _runSubscriptions(node, registry._forCascadeExpression);
+ super.visitCascadeExpression(node);
+ }
+
+ @override
+ void visitCatchClause(CatchClause node) {
+ _runSubscriptions(node, registry._forCatchClause);
+ super.visitCatchClause(node);
+ }
+
+ @override
+ void visitClassDeclaration(ClassDeclaration node) {
+ _runSubscriptions(node, registry._forClassDeclaration);
+ super.visitClassDeclaration(node);
+ }
+
+ @override
+ void visitClassTypeAlias(ClassTypeAlias node) {
+ _runSubscriptions(node, registry._forClassTypeAlias);
+ super.visitClassTypeAlias(node);
+ }
+
+ @override
+ void visitComment(Comment node) {
+ _runSubscriptions(node, registry._forComment);
+ super.visitComment(node);
+ }
+
+ @override
+ void visitCommentReference(CommentReference node) {
+ _runSubscriptions(node, registry._forCommentReference);
+ super.visitCommentReference(node);
+ }
+
+ @override
+ void visitCompilationUnit(CompilationUnit node) {
+ _runSubscriptions(node, registry._forCompilationUnit);
+ super.visitCompilationUnit(node);
+ }
+
+ @override
+ void visitConditionalExpression(ConditionalExpression node) {
+ _runSubscriptions(node, registry._forConditionalExpression);
+ super.visitConditionalExpression(node);
+ }
+
+ @override
+ void visitConfiguration(Configuration node) {
+ _runSubscriptions(node, registry._forConfiguration);
+ super.visitConfiguration(node);
+ }
+
+ @override
+ void visitConstructorDeclaration(ConstructorDeclaration node) {
+ _runSubscriptions(node, registry._forConstructorDeclaration);
+ super.visitConstructorDeclaration(node);
+ }
+
+ @override
+ void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
+ _runSubscriptions(node, registry._forConstructorFieldInitializer);
+ super.visitConstructorFieldInitializer(node);
+ }
+
+ @override
+ void visitConstructorName(ConstructorName node) {
+ _runSubscriptions(node, registry._forConstructorName);
+ super.visitConstructorName(node);
+ }
+
+ @override
+ void visitContinueStatement(ContinueStatement node) {
+ _runSubscriptions(node, registry._forContinueStatement);
+ super.visitContinueStatement(node);
+ }
+
+ @override
+ void visitDeclaredIdentifier(DeclaredIdentifier node) {
+ _runSubscriptions(node, registry._forDeclaredIdentifier);
+ super.visitDeclaredIdentifier(node);
+ }
+
+ @override
+ void visitDefaultFormalParameter(DefaultFormalParameter node) {
+ _runSubscriptions(node, registry._forDefaultFormalParameter);
+ super.visitDefaultFormalParameter(node);
+ }
+
+ @override
+ void visitDoStatement(DoStatement node) {
+ _runSubscriptions(node, registry._forDoStatement);
+ super.visitDoStatement(node);
+ }
+
+ @override
+ void visitDottedName(DottedName node) {
+ _runSubscriptions(node, registry._forDottedName);
+ super.visitDottedName(node);
+ }
+
+ @override
+ void visitDoubleLiteral(DoubleLiteral node) {
+ _runSubscriptions(node, registry._forDoubleLiteral);
+ super.visitDoubleLiteral(node);
+ }
+
+ @override
+ void visitEmptyFunctionBody(EmptyFunctionBody node) {
+ _runSubscriptions(node, registry._forEmptyFunctionBody);
+ super.visitEmptyFunctionBody(node);
+ }
+
+ @override
+ void visitEmptyStatement(EmptyStatement node) {
+ _runSubscriptions(node, registry._forEmptyStatement);
+ super.visitEmptyStatement(node);
+ }
+
+ @override
+ void visitEnumConstantDeclaration(EnumConstantDeclaration node) {
+ _runSubscriptions(node, registry._forEnumConstantDeclaration);
+ super.visitEnumConstantDeclaration(node);
+ }
+
+ @override
+ void visitEnumDeclaration(EnumDeclaration node) {
+ _runSubscriptions(node, registry._forEnumDeclaration);
+ super.visitEnumDeclaration(node);
+ }
+
+ @override
+ void visitExportDirective(ExportDirective node) {
+ _runSubscriptions(node, registry._forExportDirective);
+ super.visitExportDirective(node);
+ }
+
+ @override
+ void visitExpressionFunctionBody(ExpressionFunctionBody node) {
+ _runSubscriptions(node, registry._forExpressionFunctionBody);
+ super.visitExpressionFunctionBody(node);
+ }
+
+ @override
+ void visitExpressionStatement(ExpressionStatement node) {
+ _runSubscriptions(node, registry._forExpressionStatement);
+ super.visitExpressionStatement(node);
+ }
+
+ @override
+ void visitExtendsClause(ExtendsClause node) {
+ _runSubscriptions(node, registry._forExtendsClause);
+ super.visitExtendsClause(node);
+ }
+
+ @override
+ void visitFieldDeclaration(FieldDeclaration node) {
+ _runSubscriptions(node, registry._forFieldDeclaration);
+ super.visitFieldDeclaration(node);
+ }
+
+ @override
+ void visitFieldFormalParameter(FieldFormalParameter node) {
+ _runSubscriptions(node, registry._forFieldFormalParameter);
+ super.visitFieldFormalParameter(node);
+ }
+
+ @override
+ void visitForEachStatement(ForEachStatement node) {
+ _runSubscriptions(node, registry._forForEachStatement);
+ super.visitForEachStatement(node);
+ }
+
+ @override
+ void visitFormalParameterList(FormalParameterList node) {
+ _runSubscriptions(node, registry._forFormalParameterList);
+ super.visitFormalParameterList(node);
+ }
+
+ @override
+ void visitForStatement(ForStatement node) {
+ _runSubscriptions(node, registry._forForStatement);
+ super.visitForStatement(node);
+ }
+
+ @override
+ void visitFunctionDeclaration(FunctionDeclaration node) {
+ _runSubscriptions(node, registry._forFunctionDeclaration);
+ super.visitFunctionDeclaration(node);
+ }
+
+ @override
+ void visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
+ _runSubscriptions(node, registry._forFunctionDeclarationStatement);
+ super.visitFunctionDeclarationStatement(node);
+ }
+
+ @override
+ void visitFunctionExpression(FunctionExpression node) {
+ _runSubscriptions(node, registry._forFunctionExpression);
+ super.visitFunctionExpression(node);
+ }
+
+ @override
+ void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
+ _runSubscriptions(node, registry._forFunctionExpressionInvocation);
+ super.visitFunctionExpressionInvocation(node);
+ }
+
+ @override
+ void visitFunctionTypeAlias(FunctionTypeAlias node) {
+ _runSubscriptions(node, registry._forFunctionTypeAlias);
+ super.visitFunctionTypeAlias(node);
+ }
+
+ @override
+ void visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
+ _runSubscriptions(node, registry._forFunctionTypedFormalParameter);
+ super.visitFunctionTypedFormalParameter(node);
+ }
+
+ @override
+ void visitGenericFunctionType(GenericFunctionType node) {
+ _runSubscriptions(node, registry._forGenericFunctionType);
+ super.visitGenericFunctionType(node);
+ }
+
+ @override
+ void visitGenericTypeAlias(GenericTypeAlias node) {
+ _runSubscriptions(node, registry._forGenericTypeAlias);
+ super.visitGenericTypeAlias(node);
+ }
+
+ @override
+ void visitHideCombinator(HideCombinator node) {
+ _runSubscriptions(node, registry._forHideCombinator);
+ super.visitHideCombinator(node);
+ }
+
+ @override
+ void visitIfStatement(IfStatement node) {
+ _runSubscriptions(node, registry._forIfStatement);
+ super.visitIfStatement(node);
+ }
+
+ @override
+ void visitImplementsClause(ImplementsClause node) {
+ _runSubscriptions(node, registry._forImplementsClause);
+ super.visitImplementsClause(node);
+ }
+
+ @override
+ void visitImportDirective(ImportDirective node) {
+ _runSubscriptions(node, registry._forImportDirective);
+ super.visitImportDirective(node);
+ }
+
+ @override
+ void visitIndexExpression(IndexExpression node) {
+ _runSubscriptions(node, registry._forIndexExpression);
+ super.visitIndexExpression(node);
+ }
+
+ @override
+ void visitInstanceCreationExpression(InstanceCreationExpression node) {
+ _runSubscriptions(node, registry._forInstanceCreationExpression);
+ super.visitInstanceCreationExpression(node);
+ }
+
+ @override
+ void visitIntegerLiteral(IntegerLiteral node) {
+ _runSubscriptions(node, registry._forIntegerLiteral);
+ super.visitIntegerLiteral(node);
+ }
+
+ @override
+ void visitInterpolationExpression(InterpolationExpression node) {
+ _runSubscriptions(node, registry._forInterpolationExpression);
+ super.visitInterpolationExpression(node);
+ }
+
+ @override
+ void visitInterpolationString(InterpolationString node) {
+ _runSubscriptions(node, registry._forInterpolationString);
+ super.visitInterpolationString(node);
+ }
+
+ @override
+ void visitIsExpression(IsExpression node) {
+ _runSubscriptions(node, registry._forIsExpression);
+ super.visitIsExpression(node);
+ }
+
+ @override
+ void visitLabel(Label node) {
+ _runSubscriptions(node, registry._forLabel);
+ super.visitLabel(node);
+ }
+
+ @override
+ void visitLabeledStatement(LabeledStatement node) {
+ _runSubscriptions(node, registry._forLabeledStatement);
+ super.visitLabeledStatement(node);
+ }
+
+ @override
+ void visitLibraryDirective(LibraryDirective node) {
+ _runSubscriptions(node, registry._forLibraryDirective);
+ super.visitLibraryDirective(node);
+ }
+
+ @override
+ void visitLibraryIdentifier(LibraryIdentifier node) {
+ _runSubscriptions(node, registry._forLibraryIdentifier);
+ super.visitLibraryIdentifier(node);
+ }
+
+ @override
+ void visitListLiteral(ListLiteral node) {
+ _runSubscriptions(node, registry._forListLiteral);
+ super.visitListLiteral(node);
+ }
+
+ @override
+ void visitMapLiteral(MapLiteral node) {
+ _runSubscriptions(node, registry._forMapLiteral);
+ super.visitMapLiteral(node);
+ }
+
+ @override
+ void visitMapLiteralEntry(MapLiteralEntry node) {
+ _runSubscriptions(node, registry._forMapLiteralEntry);
+ super.visitMapLiteralEntry(node);
+ }
+
+ @override
+ void visitMethodDeclaration(MethodDeclaration node) {
+ _runSubscriptions(node, registry._forMethodDeclaration);
+ super.visitMethodDeclaration(node);
+ }
+
+ @override
+ void visitMethodInvocation(MethodInvocation node) {
+ _runSubscriptions(node, registry._forMethodInvocation);
+ super.visitMethodInvocation(node);
+ }
+
+ @override
+ void visitNamedExpression(NamedExpression node) {
+ _runSubscriptions(node, registry._forNamedExpression);
+ super.visitNamedExpression(node);
+ }
+
+ @override
+ void visitNullLiteral(NullLiteral node) {
+ _runSubscriptions(node, registry._forNullLiteral);
+ super.visitNullLiteral(node);
+ }
+
+ @override
+ void visitParenthesizedExpression(ParenthesizedExpression node) {
+ _runSubscriptions(node, registry._forParenthesizedExpression);
+ super.visitParenthesizedExpression(node);
+ }
+
+ @override
+ void visitPartDirective(PartDirective node) {
+ _runSubscriptions(node, registry._forPartDirective);
+ super.visitPartDirective(node);
+ }
+
+ @override
+ void visitPartOfDirective(PartOfDirective node) {
+ _runSubscriptions(node, registry._forPartOfDirective);
+ super.visitPartOfDirective(node);
+ }
+
+ @override
+ void visitPostfixExpression(PostfixExpression node) {
+ _runSubscriptions(node, registry._forPostfixExpression);
+ super.visitPostfixExpression(node);
+ }
+
+ @override
+ void visitPrefixedIdentifier(PrefixedIdentifier node) {
+ _runSubscriptions(node, registry._forPrefixedIdentifier);
+ super.visitPrefixedIdentifier(node);
+ }
+
+ @override
+ void visitPrefixExpression(PrefixExpression node) {
+ _runSubscriptions(node, registry._forPrefixExpression);
+ super.visitPrefixExpression(node);
+ }
+
+ @override
+ void visitPropertyAccess(PropertyAccess node) {
+ _runSubscriptions(node, registry._forPropertyAccess);
+ super.visitPropertyAccess(node);
+ }
+
+ @override
+ void visitRedirectingConstructorInvocation(
+ RedirectingConstructorInvocation node) {
+ _runSubscriptions(node, registry._forRedirectingConstructorInvocation);
+ super.visitRedirectingConstructorInvocation(node);
+ }
+
+ @override
+ void visitRethrowExpression(RethrowExpression node) {
+ _runSubscriptions(node, registry._forRethrowExpression);
+ super.visitRethrowExpression(node);
+ }
+
+ @override
+ void visitReturnStatement(ReturnStatement node) {
+ _runSubscriptions(node, registry._forReturnStatement);
+ super.visitReturnStatement(node);
+ }
+
+ @override
+ void visitShowCombinator(ShowCombinator node) {
+ _runSubscriptions(node, registry._forShowCombinator);
+ super.visitShowCombinator(node);
+ }
+
+ @override
+ void visitSimpleFormalParameter(SimpleFormalParameter node) {
+ _runSubscriptions(node, registry._forSimpleFormalParameter);
+ super.visitSimpleFormalParameter(node);
+ }
+
+ @override
+ void visitSimpleIdentifier(SimpleIdentifier node) {
+ _runSubscriptions(node, registry._forSimpleIdentifier);
+ super.visitSimpleIdentifier(node);
+ }
+
+ @override
+ void visitSimpleStringLiteral(SimpleStringLiteral node) {
+ _runSubscriptions(node, registry._forSimpleStringLiteral);
+ super.visitSimpleStringLiteral(node);
+ }
+
+ @override
+ void visitStringInterpolation(StringInterpolation node) {
+ _runSubscriptions(node, registry._forStringInterpolation);
+ super.visitStringInterpolation(node);
+ }
+
+ @override
+ void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
+ _runSubscriptions(node, registry._forSuperConstructorInvocation);
+ super.visitSuperConstructorInvocation(node);
+ }
+
+ @override
+ void visitSuperExpression(SuperExpression node) {
+ _runSubscriptions(node, registry._forSuperExpression);
+ super.visitSuperExpression(node);
+ }
+
+ @override
+ void visitSwitchCase(SwitchCase node) {
+ _runSubscriptions(node, registry._forSwitchCase);
+ super.visitSwitchCase(node);
+ }
+
+ @override
+ void visitSwitchDefault(SwitchDefault node) {
+ _runSubscriptions(node, registry._forSwitchDefault);
+ super.visitSwitchDefault(node);
+ }
+
+ @override
+ void visitSwitchStatement(SwitchStatement node) {
+ _runSubscriptions(node, registry._forSwitchStatement);
+ super.visitSwitchStatement(node);
+ }
+
+ @override
+ void visitSymbolLiteral(SymbolLiteral node) {
+ _runSubscriptions(node, registry._forSymbolLiteral);
+ super.visitSymbolLiteral(node);
+ }
+
+ @override
+ void visitThisExpression(ThisExpression node) {
+ _runSubscriptions(node, registry._forThisExpression);
+ super.visitThisExpression(node);
+ }
+
+ @override
+ void visitThrowExpression(ThrowExpression node) {
+ _runSubscriptions(node, registry._forThrowExpression);
+ super.visitThrowExpression(node);
+ }
+
+ @override
+ void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
+ _runSubscriptions(node, registry._forTopLevelVariableDeclaration);
+ super.visitTopLevelVariableDeclaration(node);
+ }
+
+ @override
+ void visitTryStatement(TryStatement node) {
+ _runSubscriptions(node, registry._forTryStatement);
+ super.visitTryStatement(node);
+ }
+
+ @override
+ void visitTypeArgumentList(TypeArgumentList node) {
+ _runSubscriptions(node, registry._forTypeArgumentList);
+ super.visitTypeArgumentList(node);
+ }
+
+ @override
+ void visitTypeName(TypeName node) {
+ _runSubscriptions(node, registry._forTypeName);
+ super.visitTypeName(node);
+ }
+
+ @override
+ void visitTypeParameter(TypeParameter node) {
+ _runSubscriptions(node, registry._forTypeParameter);
+ super.visitTypeParameter(node);
+ }
+
+ @override
+ void visitTypeParameterList(TypeParameterList node) {
+ _runSubscriptions(node, registry._forTypeParameterList);
+ super.visitTypeParameterList(node);
+ }
+
+ @override
+ void visitVariableDeclaration(VariableDeclaration node) {
+ _runSubscriptions(node, registry._forVariableDeclaration);
+ super.visitVariableDeclaration(node);
+ }
+
+ @override
+ void visitVariableDeclarationList(VariableDeclarationList node) {
+ _runSubscriptions(node, registry._forVariableDeclarationList);
+ super.visitVariableDeclarationList(node);
+ }
+
+ @override
+ void visitVariableDeclarationStatement(VariableDeclarationStatement node) {
+ _runSubscriptions(node, registry._forVariableDeclarationStatement);
+ super.visitVariableDeclarationStatement(node);
+ }
+
+ @override
+ void visitWhileStatement(WhileStatement node) {
+ _runSubscriptions(node, registry._forWhileStatement);
+ super.visitWhileStatement(node);
+ }
+
+ @override
+ void visitWithClause(WithClause node) {
+ _runSubscriptions(node, registry._forWithClause);
+ super.visitWithClause(node);
+ }
+
+ @override
+ void visitYieldStatement(YieldStatement node) {
+ _runSubscriptions(node, registry._forYieldStatement);
+ super.visitYieldStatement(node);
+ }
+
+ void _runSubscriptions<T extends AstNode>(
+ T node, List<_Subscription<T>> subscriptions) {
+ for (int i = 0; i < subscriptions.length; i++) {
+ var subscription = subscriptions[i];
+ var timer = subscription.timer;
+ timer?.start();
+ try {
+ node.accept(subscription.visitor);
+ } catch (exception, stackTrace) {
+ exceptionHandler(node, subscription.linter, exception, stackTrace);
+ }
+ timer?.stop();
+ }
+ }
+}
+
+/// The container to register visitors for separate AST node types.
+class NodeLintRegistry {
+ final bool enableTiming;
+ final List<_Subscription<AsExpression>> _forAsExpression = [];
+ final List<_Subscription<AssertInitializer>> _forAssertInitializer = [];
+ final List<_Subscription<AssertStatement>> _forAssertStatement = [];
+ final List<_Subscription<AssignmentExpression>> _forAssignmentExpression = [];
+ final List<_Subscription<AwaitExpression>> _forAwaitExpression = [];
+ final List<_Subscription<BinaryExpression>> _forBinaryExpression = [];
+ final List<_Subscription<Block>> _forBlock = [];
+ final List<_Subscription<BlockFunctionBody>> _forBlockFunctionBody = [];
+ final List<_Subscription<BooleanLiteral>> _forBooleanLiteral = [];
+ final List<_Subscription<BreakStatement>> _forBreakStatement = [];
+ final List<_Subscription<CascadeExpression>> _forCascadeExpression = [];
+ final List<_Subscription<CatchClause>> _forCatchClause = [];
+ final List<_Subscription<ClassDeclaration>> _forClassDeclaration = [];
+ final List<_Subscription<ClassTypeAlias>> _forClassTypeAlias = [];
+ final List<_Subscription<Comment>> _forComment = [];
+ final List<_Subscription<CommentReference>> _forCommentReference = [];
+ final List<_Subscription<CompilationUnit>> _forCompilationUnit = [];
+ final List<_Subscription<ConditionalExpression>> _forConditionalExpression =
+ [];
+ final List<_Subscription<Configuration>> _forConfiguration = [];
+ final List<_Subscription<ConstructorDeclaration>> _forConstructorDeclaration =
+ [];
+ final List<_Subscription<ConstructorFieldInitializer>>
+ _forConstructorFieldInitializer = [];
+ final List<_Subscription<ConstructorName>> _forConstructorName = [];
+ final List<_Subscription<ContinueStatement>> _forContinueStatement = [];
+ final List<_Subscription<DeclaredIdentifier>> _forDeclaredIdentifier = [];
+ final List<_Subscription<DefaultFormalParameter>> _forDefaultFormalParameter =
+ [];
+ final List<_Subscription<DoStatement>> _forDoStatement = [];
+ final List<_Subscription<DottedName>> _forDottedName = [];
+ final List<_Subscription<DoubleLiteral>> _forDoubleLiteral = [];
+ final List<_Subscription<EmptyFunctionBody>> _forEmptyFunctionBody = [];
+ final List<_Subscription<EmptyStatement>> _forEmptyStatement = [];
+ final List<_Subscription<EnumConstantDeclaration>>
+ _forEnumConstantDeclaration = [];
+ final List<_Subscription<EnumDeclaration>> _forEnumDeclaration = [];
+ final List<_Subscription<ExportDirective>> _forExportDirective = [];
+ final List<_Subscription<ExpressionFunctionBody>> _forExpressionFunctionBody =
+ [];
+ final List<_Subscription<ExpressionStatement>> _forExpressionStatement = [];
+ final List<_Subscription<ExtendsClause>> _forExtendsClause = [];
+ final List<_Subscription<FieldDeclaration>> _forFieldDeclaration = [];
+ final List<_Subscription<FieldFormalParameter>> _forFieldFormalParameter = [];
+ final List<_Subscription<ForEachStatement>> _forForEachStatement = [];
+ final List<_Subscription<FormalParameterList>> _forFormalParameterList = [];
+ final List<_Subscription<ForStatement>> _forForStatement = [];
+ final List<_Subscription<FunctionDeclaration>> _forFunctionDeclaration = [];
+ final List<_Subscription<FunctionDeclarationStatement>>
+ _forFunctionDeclarationStatement = [];
+ final List<_Subscription<FunctionExpression>> _forFunctionExpression = [];
+ final List<_Subscription<FunctionExpressionInvocation>>
+ _forFunctionExpressionInvocation = [];
+ final List<_Subscription<FunctionTypeAlias>> _forFunctionTypeAlias = [];
+ final List<_Subscription<FunctionTypedFormalParameter>>
+ _forFunctionTypedFormalParameter = [];
+ final List<_Subscription<GenericFunctionType>> _forGenericFunctionType = [];
+ final List<_Subscription<GenericTypeAlias>> _forGenericTypeAlias = [];
+ final List<_Subscription<HideCombinator>> _forHideCombinator = [];
+ final List<_Subscription<IfStatement>> _forIfStatement = [];
+ final List<_Subscription<ImplementsClause>> _forImplementsClause = [];
+ final List<_Subscription<ImportDirective>> _forImportDirective = [];
+ final List<_Subscription<IndexExpression>> _forIndexExpression = [];
+ final List<_Subscription<InstanceCreationExpression>>
+ _forInstanceCreationExpression = [];
+ final List<_Subscription<IntegerLiteral>> _forIntegerLiteral = [];
+ final List<_Subscription<InterpolationExpression>>
+ _forInterpolationExpression = [];
+ final List<_Subscription<InterpolationString>> _forInterpolationString = [];
+ final List<_Subscription<IsExpression>> _forIsExpression = [];
+ final List<_Subscription<Label>> _forLabel = [];
+ final List<_Subscription<LabeledStatement>> _forLabeledStatement = [];
+ final List<_Subscription<LibraryDirective>> _forLibraryDirective = [];
+ final List<_Subscription<LibraryIdentifier>> _forLibraryIdentifier = [];
+ final List<_Subscription<ListLiteral>> _forListLiteral = [];
+ final List<_Subscription<MapLiteral>> _forMapLiteral = [];
+ final List<_Subscription<MapLiteralEntry>> _forMapLiteralEntry = [];
+ final List<_Subscription<MethodDeclaration>> _forMethodDeclaration = [];
+ final List<_Subscription<MethodInvocation>> _forMethodInvocation = [];
+ final List<_Subscription<NamedExpression>> _forNamedExpression = [];
+ final List<_Subscription<NullLiteral>> _forNullLiteral = [];
+ final List<_Subscription<ParenthesizedExpression>>
+ _forParenthesizedExpression = [];
+ final List<_Subscription<PartDirective>> _forPartDirective = [];
+ final List<_Subscription<PartOfDirective>> _forPartOfDirective = [];
+ final List<_Subscription<PostfixExpression>> _forPostfixExpression = [];
+ final List<_Subscription<PrefixedIdentifier>> _forPrefixedIdentifier = [];
+ final List<_Subscription<PrefixExpression>> _forPrefixExpression = [];
+ final List<_Subscription<PropertyAccess>> _forPropertyAccess = [];
+ final List<_Subscription<RedirectingConstructorInvocation>>
+ _forRedirectingConstructorInvocation = [];
+ final List<_Subscription<RethrowExpression>> _forRethrowExpression = [];
+ final List<_Subscription<ReturnStatement>> _forReturnStatement = [];
+ final List<_Subscription<ShowCombinator>> _forShowCombinator = [];
+ final List<_Subscription<SimpleFormalParameter>> _forSimpleFormalParameter =
+ [];
+ final List<_Subscription<SimpleIdentifier>> _forSimpleIdentifier = [];
+ final List<_Subscription<SimpleStringLiteral>> _forSimpleStringLiteral = [];
+ final List<_Subscription<StringInterpolation>> _forStringInterpolation = [];
+ final List<_Subscription<SuperConstructorInvocation>>
+ _forSuperConstructorInvocation = [];
+ final List<_Subscription<SuperExpression>> _forSuperExpression = [];
+ final List<_Subscription<SwitchCase>> _forSwitchCase = [];
+ final List<_Subscription<SwitchDefault>> _forSwitchDefault = [];
+ final List<_Subscription<SwitchStatement>> _forSwitchStatement = [];
+ final List<_Subscription<SymbolLiteral>> _forSymbolLiteral = [];
+ final List<_Subscription<ThisExpression>> _forThisExpression = [];
+ final List<_Subscription<ThrowExpression>> _forThrowExpression = [];
+ final List<_Subscription<TopLevelVariableDeclaration>>
+ _forTopLevelVariableDeclaration = [];
+ final List<_Subscription<TryStatement>> _forTryStatement = [];
+ final List<_Subscription<TypeArgumentList>> _forTypeArgumentList = [];
+ final List<_Subscription<TypeName>> _forTypeName = [];
+ final List<_Subscription<TypeParameter>> _forTypeParameter = [];
+ final List<_Subscription<TypeParameterList>> _forTypeParameterList = [];
+ final List<_Subscription<VariableDeclaration>> _forVariableDeclaration = [];
+ final List<_Subscription<VariableDeclarationList>>
+ _forVariableDeclarationList = [];
+ final List<_Subscription<VariableDeclarationStatement>>
+ _forVariableDeclarationStatement = [];
+ final List<_Subscription<WhileStatement>> _forWhileStatement = [];
+ final List<_Subscription<WithClause>> _forWithClause = [];
+ final List<_Subscription<YieldStatement>> _forYieldStatement = [];
+
+ NodeLintRegistry(this.enableTiming);
+
+ void addAsExpression(LintRule linter, AstVisitor visitor) {
+ _forAsExpression.add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addAssertInitializer(LintRule linter, AstVisitor visitor) {
+ _forAssertInitializer
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addAssertStatement(LintRule linter, AstVisitor visitor) {
+ _forAssertStatement
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addAssignmentExpression(LintRule linter, AstVisitor visitor) {
+ _forAssignmentExpression
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addAwaitExpression(LintRule linter, AstVisitor visitor) {
+ _forAwaitExpression
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addBinaryExpression(LintRule linter, AstVisitor visitor) {
+ _forBinaryExpression
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addBlock(LintRule linter, AstVisitor visitor) {
+ _forBlock.add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addBlockFunctionBody(LintRule linter, AstVisitor visitor) {
+ _forBlockFunctionBody
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addBooleanLiteral(LintRule linter, AstVisitor visitor) {
+ _forBooleanLiteral
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addBreakStatement(LintRule linter, AstVisitor visitor) {
+ _forBreakStatement
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addCascadeExpression(LintRule linter, AstVisitor visitor) {
+ _forCascadeExpression
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addCatchClause(LintRule linter, AstVisitor visitor) {
+ _forCatchClause.add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addClassDeclaration(LintRule linter, AstVisitor visitor) {
+ _forClassDeclaration
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addClassTypeAlias(LintRule linter, AstVisitor visitor) {
+ _forClassTypeAlias
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addComment(LintRule linter, AstVisitor visitor) {
+ _forComment.add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addCommentReference(LintRule linter, AstVisitor visitor) {
+ _forCommentReference
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addCompilationUnit(LintRule linter, AstVisitor visitor) {
+ _forCompilationUnit
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addConditionalExpression(LintRule linter, AstVisitor visitor) {
+ _forConditionalExpression
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addConfiguration(LintRule linter, AstVisitor visitor) {
+ _forConfiguration
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addConstructorDeclaration(LintRule linter, AstVisitor visitor) {
+ _forConstructorDeclaration
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addConstructorFieldInitializer(LintRule linter, AstVisitor visitor) {
+ _forConstructorFieldInitializer
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addConstructorName(LintRule linter, AstVisitor visitor) {
+ _forConstructorName
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addContinueStatement(LintRule linter, AstVisitor visitor) {
+ _forContinueStatement
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addDeclaredIdentifier(LintRule linter, AstVisitor visitor) {
+ _forDeclaredIdentifier
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addDefaultFormalParameter(LintRule linter, AstVisitor visitor) {
+ _forDefaultFormalParameter
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addDoStatement(LintRule linter, AstVisitor visitor) {
+ _forDoStatement.add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addDottedName(LintRule linter, AstVisitor visitor) {
+ _forDottedName.add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addDoubleLiteral(LintRule linter, AstVisitor visitor) {
+ _forDoubleLiteral
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addEmptyFunctionBody(LintRule linter, AstVisitor visitor) {
+ _forEmptyFunctionBody
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addEmptyStatement(LintRule linter, AstVisitor visitor) {
+ _forEmptyStatement
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addEnumConstantDeclaration(LintRule linter, AstVisitor visitor) {
+ _forEnumConstantDeclaration
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addEnumDeclaration(LintRule linter, AstVisitor visitor) {
+ _forEnumDeclaration
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addExportDirective(LintRule linter, AstVisitor visitor) {
+ _forExportDirective
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addExpressionFunctionBody(LintRule linter, AstVisitor visitor) {
+ _forExpressionFunctionBody
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addExpressionStatement(LintRule linter, AstVisitor visitor) {
+ _forExpressionStatement
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addExtendsClause(LintRule linter, AstVisitor visitor) {
+ _forExtendsClause
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addFieldDeclaration(LintRule linter, AstVisitor visitor) {
+ _forFieldDeclaration
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addFieldFormalParameter(LintRule linter, AstVisitor visitor) {
+ _forFieldFormalParameter
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addForEachStatement(LintRule linter, AstVisitor visitor) {
+ _forForEachStatement
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addFormalParameterList(LintRule linter, AstVisitor visitor) {
+ _forFormalParameterList
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addForStatement(LintRule linter, AstVisitor visitor) {
+ _forForStatement.add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addFunctionDeclaration(LintRule linter, AstVisitor visitor) {
+ _forFunctionDeclaration
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addFunctionDeclarationStatement(LintRule linter, AstVisitor visitor) {
+ _forFunctionDeclarationStatement
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addFunctionExpression(LintRule linter, AstVisitor visitor) {
+ _forFunctionExpression
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addFunctionExpressionInvocation(LintRule linter, AstVisitor visitor) {
+ _forFunctionExpressionInvocation
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addFunctionTypeAlias(LintRule linter, AstVisitor visitor) {
+ _forFunctionTypeAlias
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addFunctionTypedFormalParameter(LintRule linter, AstVisitor visitor) {
+ _forFunctionTypedFormalParameter
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addGenericFunctionType(LintRule linter, AstVisitor visitor) {
+ _forGenericFunctionType
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addGenericTypeAlias(LintRule linter, AstVisitor visitor) {
+ _forGenericTypeAlias
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addHideCombinator(LintRule linter, AstVisitor visitor) {
+ _forHideCombinator
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addIfStatement(LintRule linter, AstVisitor visitor) {
+ _forIfStatement.add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addImplementsClause(LintRule linter, AstVisitor visitor) {
+ _forImplementsClause
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addImportDirective(LintRule linter, AstVisitor visitor) {
+ _forImportDirective
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addIndexExpression(LintRule linter, AstVisitor visitor) {
+ _forIndexExpression
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addInstanceCreationExpression(LintRule linter, AstVisitor visitor) {
+ _forInstanceCreationExpression
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addIntegerLiteral(LintRule linter, AstVisitor visitor) {
+ _forIntegerLiteral
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addInterpolationExpression(LintRule linter, AstVisitor visitor) {
+ _forInterpolationExpression
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addInterpolationString(LintRule linter, AstVisitor visitor) {
+ _forInterpolationString
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addIsExpression(LintRule linter, AstVisitor visitor) {
+ _forIsExpression.add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addLabel(LintRule linter, AstVisitor visitor) {
+ _forLabel.add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addLabeledStatement(LintRule linter, AstVisitor visitor) {
+ _forLabeledStatement
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addLibraryDirective(LintRule linter, AstVisitor visitor) {
+ _forLibraryDirective
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addLibraryIdentifier(LintRule linter, AstVisitor visitor) {
+ _forLibraryIdentifier
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addListLiteral(LintRule linter, AstVisitor visitor) {
+ _forListLiteral.add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addMapLiteral(LintRule linter, AstVisitor visitor) {
+ _forMapLiteral.add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addMapLiteralEntry(LintRule linter, AstVisitor visitor) {
+ _forMapLiteralEntry
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addMethodDeclaration(LintRule linter, AstVisitor visitor) {
+ _forMethodDeclaration
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addMethodInvocation(LintRule linter, AstVisitor visitor) {
+ _forMethodInvocation
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addNamedExpression(LintRule linter, AstVisitor visitor) {
+ _forNamedExpression
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addNullLiteral(LintRule linter, AstVisitor visitor) {
+ _forNullLiteral.add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addParenthesizedExpression(LintRule linter, AstVisitor visitor) {
+ _forParenthesizedExpression
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addPartDirective(LintRule linter, AstVisitor visitor) {
+ _forPartDirective
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addPartOfDirective(LintRule linter, AstVisitor visitor) {
+ _forPartOfDirective
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addPostfixExpression(LintRule linter, AstVisitor visitor) {
+ _forPostfixExpression
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addPrefixedIdentifier(LintRule linter, AstVisitor visitor) {
+ _forPrefixedIdentifier
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addPrefixExpression(LintRule linter, AstVisitor visitor) {
+ _forPrefixExpression
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addPropertyAccess(LintRule linter, AstVisitor visitor) {
+ _forPropertyAccess
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addRedirectingConstructorInvocation(
+ LintRule linter, AstVisitor visitor) {
+ _forRedirectingConstructorInvocation
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addRethrowExpression(LintRule linter, AstVisitor visitor) {
+ _forRethrowExpression
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addReturnStatement(LintRule linter, AstVisitor visitor) {
+ _forReturnStatement
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addShowCombinator(LintRule linter, AstVisitor visitor) {
+ _forShowCombinator
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addSimpleFormalParameter(LintRule linter, AstVisitor visitor) {
+ _forSimpleFormalParameter
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addSimpleIdentifier(LintRule linter, AstVisitor visitor) {
+ _forSimpleIdentifier
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addSimpleStringLiteral(LintRule linter, AstVisitor visitor) {
+ _forSimpleStringLiteral
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addStringInterpolation(LintRule linter, AstVisitor visitor) {
+ _forStringInterpolation
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addSuperConstructorInvocation(LintRule linter, AstVisitor visitor) {
+ _forSuperConstructorInvocation
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addSuperExpression(LintRule linter, AstVisitor visitor) {
+ _forSuperExpression
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addSwitchCase(LintRule linter, AstVisitor visitor) {
+ _forSwitchCase.add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addSwitchDefault(LintRule linter, AstVisitor visitor) {
+ _forSwitchDefault
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addSwitchStatement(LintRule linter, AstVisitor visitor) {
+ _forSwitchStatement
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addSymbolLiteral(LintRule linter, AstVisitor visitor) {
+ _forSymbolLiteral
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addThisExpression(LintRule linter, AstVisitor visitor) {
+ _forThisExpression
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addThrowExpression(LintRule linter, AstVisitor visitor) {
+ _forThrowExpression
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addTopLevelVariableDeclaration(LintRule linter, AstVisitor visitor) {
+ _forTopLevelVariableDeclaration
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addTryStatement(LintRule linter, AstVisitor visitor) {
+ _forTryStatement.add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addTypeArgumentList(LintRule linter, AstVisitor visitor) {
+ _forTypeArgumentList
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addTypeName(LintRule linter, AstVisitor visitor) {
+ _forTypeName.add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addTypeParameter(LintRule linter, AstVisitor visitor) {
+ _forTypeParameter
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addTypeParameterList(LintRule linter, AstVisitor visitor) {
+ _forTypeParameterList
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addVariableDeclaration(LintRule linter, AstVisitor visitor) {
+ _forVariableDeclaration
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addVariableDeclarationList(LintRule linter, AstVisitor visitor) {
+ _forVariableDeclarationList
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addVariableDeclarationStatement(LintRule linter, AstVisitor visitor) {
+ _forVariableDeclarationStatement
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addWhileStatement(LintRule linter, AstVisitor visitor) {
+ _forWhileStatement
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addWithClause(LintRule linter, AstVisitor visitor) {
+ _forWithClause.add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ void addYieldStatement(LintRule linter, AstVisitor visitor) {
+ _forYieldStatement
+ .add(new _Subscription(linter, visitor, _getTimer(linter)));
+ }
+
+ /// Get the timer associated with the given [linter].
+ Stopwatch _getTimer(LintRule linter) {
+ if (enableTiming) {
+ return lintRegistry.getTimer(linter);
+ } else {
+ return null;
+ }
+ }
+}
+
+/// A single subscription for a node type, by the specified [linter].
+class _Subscription<T> {
+ final LintRule linter;
+ final AstVisitor visitor;
+ final Stopwatch timer;
+
+ _Subscription(this.linter, this.visitor, this.timer);
+}
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index fd3b106..d83a9bc 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -4890,11 +4890,6 @@
static const String UNIT_INPUT = 'UNIT_INPUT';
/**
- * The name of the [TYPE_PROVIDER] input.
- */
- static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
-
- /**
* The task descriptor describing this kind of task.
*/
static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
@@ -4921,7 +4916,6 @@
LibraryElement library = getRequiredInput(LIBRARY_INPUT);
CompilationUnit unit = getRequiredInput(UNIT_INPUT);
CompilationUnitElement unitElement = unit.element;
- TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
//
// Resolve TypeName nodes.
//
@@ -4954,8 +4948,7 @@
'dependOnAllExportedSources':
IMPORTED_LIBRARIES.of(unit.library).toMapOf(EXPORT_SOURCE_CLOSURE),
LIBRARY_INPUT: LIBRARY_ELEMENT4.of(unit.library),
- UNIT_INPUT: RESOLVED_UNIT3.of(unit),
- TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
+ UNIT_INPUT: RESOLVED_UNIT3.of(unit)
};
}
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart
index 740f671..9832e8c 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart
@@ -1383,20 +1383,6 @@
@override
@failingTest
- test_invalidAnnotation_getter() async {
- // Expected 1 errors of type CompileTimeErrorCode.INVALID_ANNOTATION, found 0
- await super.test_invalidAnnotation_getter();
- }
-
- @override
- @failingTest
- test_invalidAnnotation_importWithPrefix_getter() async {
- // Bad state: No reference information for V at 27
- await super.test_invalidAnnotation_importWithPrefix_getter();
- }
-
- @override
- @failingTest
test_invalidAnnotation_importWithPrefix_notConstantVariable() async {
// Bad state: No reference information for V at 27
await super.test_invalidAnnotation_importWithPrefix_notConstantVariable();
@@ -1431,31 +1417,6 @@
@override
@failingTest
- test_invalidAnnotation_unresolved_identifier() {
- return super.test_invalidAnnotation_unresolved_identifier();
- }
-
- @override
- @failingTest
- test_invalidAnnotation_unresolved_invocation() async {
- // Bad state: No reference information for Unresolved at 1
- await super.test_invalidAnnotation_unresolved_invocation();
- }
-
- @override
- @failingTest
- test_invalidAnnotation_unresolved_prefixedIdentifier() {
- return super.test_invalidAnnotation_unresolved_prefixedIdentifier();
- }
-
- @override
- @failingTest
- test_invalidAnnotation_useLibraryScope() {
- return super.test_invalidAnnotation_useLibraryScope();
- }
-
- @override
- @failingTest
test_invalidAnnotationFromDeferredLibrary() async {
// Bad state: No reference information for v at 51
await super.test_invalidAnnotationFromDeferredLibrary();
@@ -1477,6 +1438,20 @@
@override
@failingTest
+ test_invalidAnnotationGetter_getter() async {
+ // Expected 1 errors of type CompileTimeErrorCode.INVALID_ANNOTATION, found 0
+ await super.test_invalidAnnotationGetter_getter();
+ }
+
+ @override
+ @failingTest
+ test_invalidAnnotationGetter_importWithPrefix_getter() async {
+ // Bad state: No reference information for V at 27
+ await super.test_invalidAnnotationGetter_importWithPrefix_getter();
+ }
+
+ @override
+ @failingTest
@FastaProblem('https://github.com/dart-lang/sdk/issues/31001')
test_invalidConstructorName_notEnclosingClassName_defined() async {
return super.test_invalidConstructorName_notEnclosingClassName_defined();
@@ -3004,6 +2979,31 @@
@override
@failingTest
+ test_undefinedAnnotation_unresolved_identifier() {
+ return super.test_undefinedAnnotation_unresolved_identifier();
+ }
+
+ @override
+ @failingTest
+ test_undefinedAnnotation_unresolved_invocation() async {
+ // Bad state: No reference information for Unresolved at 1
+ await super.test_undefinedAnnotation_unresolved_invocation();
+ }
+
+ @override
+ @failingTest
+ test_undefinedAnnotation_unresolved_prefixedIdentifier() {
+ return super.test_undefinedAnnotation_unresolved_prefixedIdentifier();
+ }
+
+ @override
+ @failingTest
+ test_undefinedAnnotation_useLibraryScope() {
+ return super.test_undefinedAnnotation_useLibraryScope();
+ }
+
+ @override
+ @failingTest
test_undefinedClass_const() async {
// Bad state: No type information for A at 21
await super.test_undefinedClass_const();
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
index 1a09f69..9eac8d1 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
@@ -3330,31 +3330,6 @@
assertErrors(source, [CompileTimeErrorCode.INTEGER_LITERAL_OUT_OF_RANGE]);
}
- test_invalidAnnotation_getter() async {
- Source source = addSource(r'''
-get V => 0;
-@V
-main() {
-}''');
- await computeAnalysisResult(source);
- assertErrors(source, [CompileTimeErrorCode.INVALID_ANNOTATION]);
- verify([source]);
- }
-
- test_invalidAnnotation_importWithPrefix_getter() async {
- addNamedSource("/lib.dart", r'''
-library lib;
-get V => 0;''');
- Source source = addSource(r'''
-import 'lib.dart' as p;
-@p.V
-main() {
-}''');
- await computeAnalysisResult(source);
- assertErrors(source, [CompileTimeErrorCode.INVALID_ANNOTATION]);
- verify([source]);
- }
-
test_invalidAnnotation_importWithPrefix_notConstantVariable() async {
addNamedSource("/lib.dart", r'''
library lib;
@@ -3418,44 +3393,6 @@
verify([source]);
}
- test_invalidAnnotation_unresolved_identifier() async {
- Source source = addSource(r'''
-@unresolved
-main() {
-}''');
- await computeAnalysisResult(source);
- assertErrors(source, [CompileTimeErrorCode.INVALID_ANNOTATION]);
- }
-
- test_invalidAnnotation_unresolved_invocation() async {
- Source source = addSource(r'''
-@Unresolved()
-main() {
-}''');
- await computeAnalysisResult(source);
- assertErrors(source, [CompileTimeErrorCode.INVALID_ANNOTATION]);
- }
-
- test_invalidAnnotation_unresolved_prefixedIdentifier() async {
- Source source = addSource(r'''
-import 'dart:math' as p;
-@p.unresolved
-main() {
-}''');
- await computeAnalysisResult(source);
- assertErrors(source, [CompileTimeErrorCode.INVALID_ANNOTATION]);
- }
-
- test_invalidAnnotation_useLibraryScope() async {
- Source source = addSource(r'''
-@foo
-class A {
- static const foo = null;
-}''');
- await computeAnalysisResult(source);
- assertErrors(source, [CompileTimeErrorCode.INVALID_ANNOTATION]);
- }
-
test_invalidAnnotationFromDeferredLibrary() async {
// See test_invalidAnnotation_notConstantVariable
await resolveWithErrors(<String>[
@@ -3502,6 +3439,31 @@
]);
}
+ test_invalidAnnotationGetter_getter() async {
+ Source source = addSource(r'''
+get V => 0;
+@V
+main() {
+}''');
+ await computeAnalysisResult(source);
+ assertErrors(source, [CompileTimeErrorCode.INVALID_ANNOTATION_GETTER]);
+ verify([source]);
+ }
+
+ test_invalidAnnotationGetter_importWithPrefix_getter() async {
+ addNamedSource("/lib.dart", r'''
+library lib;
+get V => 0;''');
+ Source source = addSource(r'''
+import 'lib.dart' as p;
+@p.V
+main() {
+}''');
+ await computeAnalysisResult(source);
+ assertErrors(source, [CompileTimeErrorCode.INVALID_ANNOTATION_GETTER]);
+ verify([source]);
+ }
+
test_invalidConstructorName_notEnclosingClassName_defined() async {
Source source = addSource(r'''
class A {
@@ -6777,6 +6739,44 @@
verify([source]);
}
+ test_undefinedAnnotation_unresolved_identifier() async {
+ Source source = addSource(r'''
+@unresolved
+main() {
+}''');
+ await computeAnalysisResult(source);
+ assertErrors(source, [CompileTimeErrorCode.UNDEFINED_ANNOTATION]);
+ }
+
+ test_undefinedAnnotation_unresolved_invocation() async {
+ Source source = addSource(r'''
+@Unresolved()
+main() {
+}''');
+ await computeAnalysisResult(source);
+ assertErrors(source, [CompileTimeErrorCode.UNDEFINED_ANNOTATION]);
+ }
+
+ test_undefinedAnnotation_unresolved_prefixedIdentifier() async {
+ Source source = addSource(r'''
+import 'dart:math' as p;
+@p.unresolved
+main() {
+}''');
+ await computeAnalysisResult(source);
+ assertErrors(source, [CompileTimeErrorCode.UNDEFINED_ANNOTATION]);
+ }
+
+ test_undefinedAnnotation_useLibraryScope() async {
+ Source source = addSource(r'''
+@foo
+class A {
+ static const foo = null;
+}''');
+ await computeAnalysisResult(source);
+ assertErrors(source, [CompileTimeErrorCode.UNDEFINED_ANNOTATION]);
+ }
+
test_undefinedClass_const() async {
Source source = addSource(r'''
f() {
diff --git a/pkg/analyzer/test/generated/hint_code_test.dart b/pkg/analyzer/test/generated/hint_code_test.dart
index 03c52e1..f93161b1 100644
--- a/pkg/analyzer/test/generated/hint_code_test.dart
+++ b/pkg/analyzer/test/generated/hint_code_test.dart
@@ -1096,10 +1096,14 @@
class A extends Function {}
''');
await computeAnalysisResult(source);
- assertErrors(source, [
- HintCode.DEPRECATED_EXTENDS_FUNCTION,
- StaticWarningCode.FUNCTION_WITHOUT_CALL
- ]);
+ if (analysisOptions.strongMode) {
+ assertErrors(source, [HintCode.DEPRECATED_EXTENDS_FUNCTION]);
+ } else {
+ assertErrors(source, [
+ HintCode.DEPRECATED_EXTENDS_FUNCTION,
+ StaticWarningCode.FUNCTION_WITHOUT_CALL
+ ]);
+ }
verify([source]);
}
@@ -1121,10 +1125,14 @@
class A extends Object with Function {}
''');
await computeAnalysisResult(source);
- assertErrors(source, [
- HintCode.DEPRECATED_MIXIN_FUNCTION,
- StaticWarningCode.FUNCTION_WITHOUT_CALL
- ]);
+ if (analysisOptions.strongMode) {
+ assertErrors(source, [HintCode.DEPRECATED_MIXIN_FUNCTION]);
+ } else {
+ assertErrors(source, [
+ HintCode.DEPRECATED_MIXIN_FUNCTION,
+ StaticWarningCode.FUNCTION_WITHOUT_CALL
+ ]);
+ }
verify([source]);
}
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index b47a19e..3120bb0 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -1059,10 +1059,11 @@
}
@override
- Expression parsePrimaryExpression(String code) {
- createParser(code);
+ Expression parsePrimaryExpression(String code,
+ {int expectedEndOffset, List<ExpectedError> errors}) {
+ createParser(code, expectedEndOffset: expectedEndOffset);
Expression result = _parserProxy.parsePrimaryExpression();
- assertNoErrors();
+ assertErrors(codes: null, errors: errors);
return result;
}
@@ -1378,22 +1379,6 @@
@override
@failingTest
- void test_expressionList_multiple_start() {
- // TODO(brianwilkerson) Wrong errors:
- // Expected 1 errors of type ParserErrorCode.MISSING_IDENTIFIER, found 0
- super.test_expressionList_multiple_start();
- }
-
- @override
- @failingTest
- void test_functionExpression_named() {
- // TODO(brianwilkerson) Unhandled compile-time error:
- // A function expression can't have a name.
- super.test_functionExpression_named();
- }
-
- @override
- @failingTest
void test_incompleteTypeArguments_field() {
// TODO(brianwilkerson) reportUnrecoverableErrorWithToken
super.test_incompleteTypeArguments_field();
@@ -1401,26 +1386,12 @@
@override
@failingTest
- void test_isExpression_noType() {
- // TODO(brianwilkerson) reportUnrecoverableErrorWithToken
- super.test_isExpression_noType();
- }
-
- @override
- @failingTest
void test_missingIdentifier_afterAnnotation() {
// TODO(brianwilkerson) reportUnrecoverableErrorWithToken
super.test_missingIdentifier_afterAnnotation();
}
@override
- @failingTest
- void test_primaryExpression_argumentDefinitionTest() {
- // TODO(brianwilkerson) reportUnrecoverableErrorWithToken
- super.test_primaryExpression_argumentDefinitionTest();
- }
-
- @override
void test_relationalExpression_missing_LHS_RHS() {
parseExpression("is", codes: [
ParserErrorCode.EXPECTED_TYPE_NAME,
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 94c4d91..83855d0 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -218,7 +218,8 @@
Identifier parsePrefixedIdentifier(String code);
- Expression parsePrimaryExpression(String code);
+ Expression parsePrimaryExpression(String code,
+ {int expectedEndOffset, List<ExpectedError> errors});
Expression parseRelationalExpression(String code);
@@ -524,6 +525,38 @@
expect(variable.name, isNotNull);
}
+ void test_parseClassMember_field_nameKeyword() {
+ createParser('var for;');
+ ClassMember member = parser.parseClassMember('C');
+ expect(member, isNotNull);
+ listener.assertErrors(usingFastaParser
+ ? [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 3)]
+ : [
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 3),
+ expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 4, 3)
+ ]);
+ }
+
+ void test_parseClassMember_field_nameMissing() {
+ createParser('var ;');
+ ClassMember member = parser.parseClassMember('C');
+ expect(member, isNotNull);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 1)]);
+ }
+
+ void test_parseClassMember_field_nameMissing2() {
+ createParser('var "";');
+ ClassMember member = parser.parseClassMember('C');
+ expect(member, isNotNull);
+ listener.assertErrors(usingFastaParser
+ ? [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 2)]
+ : [
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 2),
+ expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 4, 2)
+ ]);
+ }
+
void test_parseClassMember_field_namedOperator() {
createParser('var operator;');
ClassMember member = parser.parseClassMember('C');
@@ -3024,8 +3057,7 @@
errors: usingFastaParser
? [
expectedError(ParserErrorCode.MISSING_IDENTIFIER, 15, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 15, 1),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 15, 1),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 17, 4),
expectedError(ParserErrorCode.MISSING_IDENTIFIER, 22, 1),
expectedError(ParserErrorCode.EXPECTED_TOKEN, 22, 1)
]
@@ -3946,6 +3978,18 @@
]);
}
+ void test_invalidConstructorName_star() {
+ createParser("C.*();");
+ ClassMember member = parser.parseClassMember('C');
+ expectNotNullIfNoErrors(member);
+ listener.assertErrors(usingFastaParser
+ ? [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 2, 1)]
+ : [
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 2, 1),
+ expectedError(ParserErrorCode.MISSING_KEYWORD_OPERATOR, 2, 1)
+ ]);
+ }
+
void test_invalidHexEscape_invalidDigit() {
StringLiteral literal = parseExpression("'\\x0 a'",
errors: [expectedError(ParserErrorCode.INVALID_HEX_ESCAPE, 1, 3)]);
@@ -10139,9 +10183,14 @@
}
@override
- Expression parsePrimaryExpression(String code) {
+ Expression parsePrimaryExpression(String code,
+ {int expectedEndOffset, List<ExpectedError> errors}) {
createParser(code);
- return parser.parsePrimaryExpression();
+ var expression = parser.parsePrimaryExpression();
+ if (errors != null) {
+ listener.assertErrors(errors);
+ }
+ return expression;
}
@override
@@ -10776,13 +10825,21 @@
void test_expressionList_multiple_start() {
List<Expression> result = parseExpressionList('1, 2, 3,');
expectNotNullIfNoErrors(result);
- listener.assertErrors(
- [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 8, 0)]);
- expect(result, hasLength(4));
- Expression syntheticExpression = result[3];
- EngineTestCase.assertInstanceOf((obj) => obj is SimpleIdentifier,
- SimpleIdentifier, syntheticExpression);
- expect(syntheticExpression.isSynthetic, isTrue);
+ // The fasta parser does not use parseExpressionList when parsing for loops
+ // and instead parseExpressionList is mapped to parseExpression('[$code]')
+ // which allows and ignores an optional trailing comma.
+ if (usingFastaParser) {
+ listener.assertNoErrors();
+ expect(result, hasLength(3));
+ } else {
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 8, 0)]);
+ expect(result, hasLength(4));
+ Expression syntheticExpression = result[3];
+ EngineTestCase.assertInstanceOf((obj) => obj is SimpleIdentifier,
+ SimpleIdentifier, syntheticExpression);
+ expect(syntheticExpression.isSynthetic, isTrue);
+ }
}
void test_functionExpression_in_ConstructorFieldInitializer() {
@@ -10806,7 +10863,11 @@
}
void test_functionExpression_named() {
- parseExpression("m(f() => 0);", codes: [ParserErrorCode.EXPECTED_TOKEN]);
+ parseExpression("m(f() => 0);", expectedEndOffset: 11, codes: [
+ usingFastaParser
+ ? ParserErrorCode.NAMED_FUNCTION_EXPRESSION
+ : ParserErrorCode.EXPECTED_TOKEN
+ ]);
}
void test_ifStatement_noElse_statement() {
@@ -11408,11 +11469,18 @@
void test_isExpression_noType() {
CompilationUnit unit = parseCompilationUnit(
"class Bar<T extends Foo> {m(x){if (x is ) return;if (x is !)}}",
- codes: [
- ParserErrorCode.EXPECTED_TYPE_NAME,
- ParserErrorCode.EXPECTED_TYPE_NAME,
- ParserErrorCode.MISSING_STATEMENT
- ]);
+ codes: usingFastaParser
+ ? [
+ ParserErrorCode.EXPECTED_TYPE_NAME,
+ ParserErrorCode.EXPECTED_TYPE_NAME,
+ ParserErrorCode.MISSING_IDENTIFIER,
+ ParserErrorCode.EXPECTED_TOKEN,
+ ]
+ : [
+ ParserErrorCode.EXPECTED_TYPE_NAME,
+ ParserErrorCode.EXPECTED_TYPE_NAME,
+ ParserErrorCode.MISSING_STATEMENT
+ ]);
ClassDeclaration declaration = unit.declarations[0] as ClassDeclaration;
MethodDeclaration method = declaration.members[0] as MethodDeclaration;
BlockFunctionBody body = method.body as BlockFunctionBody;
@@ -11424,8 +11492,15 @@
TypeAnnotation type = expression.type;
expect(type, isNotNull);
expect(type is TypeName && type.name.isSynthetic, isTrue);
- EngineTestCase.assertInstanceOf((obj) => obj is EmptyStatement,
- EmptyStatement, ifStatement.thenStatement);
+ if (usingFastaParser) {
+ ExpressionStatement thenStatement = ifStatement.thenStatement;
+ expect(thenStatement.semicolon.isSynthetic, isTrue);
+ SimpleIdentifier simpleId = thenStatement.expression;
+ expect(simpleId.isSynthetic, isTrue);
+ } else {
+ EngineTestCase.assertInstanceOf((obj) => obj is EmptyStatement,
+ EmptyStatement, ifStatement.thenStatement);
+ }
}
void test_keywordInPlaceOfIdentifier() {
@@ -11738,11 +11813,13 @@
}
void test_primaryExpression_argumentDefinitionTest() {
- Expression expression = parsePrimaryExpression('?a');
+ SimpleIdentifier expression = parsePrimaryExpression('?a',
+ expectedEndOffset: 0,
+ errors: usingFastaParser
+ ? [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 0, 1)]
+ : [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 0, 1)]);
expectNotNullIfNoErrors(expression);
- listener
- .assertErrors([expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 0, 1)]);
- expect(expression, new isInstanceOf<SimpleIdentifier>());
+ expect(expression.isSynthetic, usingFastaParser);
}
void test_propertyAccess_missing_LHS_RHS() {
@@ -13846,6 +13923,23 @@
expect(creation.argumentList, isNotNull);
}
+ void test_parseInstanceCreation_noKeyword_varInit() {
+ enableOptionalNewAndConst = true;
+ createParser('''
+class C<T, S> {}
+void main() {final c = C<int, int Function(String)>();}
+''');
+ CompilationUnit unit = parser.parseCompilationUnit2();
+ expect(unit, isNotNull);
+ FunctionDeclaration f = unit.declarations[1];
+ BlockFunctionBody body = f.functionExpression.body;
+ VariableDeclarationStatement statement = body.block.statements[0];
+ VariableDeclaration variable = statement.variables.variables[0];
+ MethodInvocation creation = variable.initializer;
+ expect(creation.methodName.name, 'C');
+ expect(creation.typeArguments.toSource(), '<int, int Function(String)>');
+ }
+
void test_parseLibraryIdentifier_invalid() {
parseCompilationUnit('library <myLibId>;',
errors: usingFastaParser
diff --git a/pkg/analyzer/test/generated/static_warning_code_test.dart b/pkg/analyzer/test/generated/static_warning_code_test.dart
index f908337..a78274e 100644
--- a/pkg/analyzer/test/generated/static_warning_code_test.dart
+++ b/pkg/analyzer/test/generated/static_warning_code_test.dart
@@ -1467,7 +1467,11 @@
class A implements Function {
}''');
await computeAnalysisResult(source);
- assertErrors(source, [StaticWarningCode.FUNCTION_WITHOUT_CALL]);
+ if (analysisOptions.strongMode) {
+ assertNoErrors(source);
+ } else {
+ assertErrors(source, [StaticWarningCode.FUNCTION_WITHOUT_CALL]);
+ }
verify([source]);
}
@@ -1476,7 +1480,11 @@
class M {}
class A = Object with M implements Function;''');
await computeAnalysisResult(source);
- assertErrors(source, [StaticWarningCode.FUNCTION_WITHOUT_CALL]);
+ if (analysisOptions.strongMode) {
+ assertNoErrors(source);
+ } else {
+ assertErrors(source, [StaticWarningCode.FUNCTION_WITHOUT_CALL]);
+ }
verify([source]);
}
@@ -1487,7 +1495,11 @@
class B extends A {
}''');
await computeAnalysisResult(source);
- assertErrors(source, [StaticWarningCode.FUNCTION_WITHOUT_CALL]);
+ if (analysisOptions.strongMode) {
+ assertNoErrors(source);
+ } else {
+ assertErrors(source, [StaticWarningCode.FUNCTION_WITHOUT_CALL]);
+ }
verify([source]);
}
@@ -1497,7 +1509,11 @@
class M {}
class B = A with M;''');
await computeAnalysisResult(source);
- assertErrors(source, [StaticWarningCode.FUNCTION_WITHOUT_CALL]);
+ if (analysisOptions.strongMode) {
+ assertNoErrors(source);
+ } else {
+ assertErrors(source, [StaticWarningCode.FUNCTION_WITHOUT_CALL]);
+ }
verify([source]);
}
@@ -1508,7 +1524,11 @@
class B implements A {
}''');
await computeAnalysisResult(source);
- assertErrors(source, [StaticWarningCode.FUNCTION_WITHOUT_CALL]);
+ if (analysisOptions.strongMode) {
+ assertNoErrors(source);
+ } else {
+ assertErrors(source, [StaticWarningCode.FUNCTION_WITHOUT_CALL]);
+ }
verify([source]);
}
@@ -1518,7 +1538,11 @@
class M {}
class B = Object with M implements A;''');
await computeAnalysisResult(source);
- assertErrors(source, [StaticWarningCode.FUNCTION_WITHOUT_CALL]);
+ if (analysisOptions.strongMode) {
+ assertNoErrors(source);
+ } else {
+ assertErrors(source, [StaticWarningCode.FUNCTION_WITHOUT_CALL]);
+ }
verify([source]);
}
@@ -1527,7 +1551,11 @@
abstract class A implements Function {}
class B extends Object with A {}''');
await computeAnalysisResult(source);
- assertErrors(source, [StaticWarningCode.FUNCTION_WITHOUT_CALL]);
+ if (analysisOptions.strongMode) {
+ assertNoErrors(source);
+ } else {
+ assertErrors(source, [StaticWarningCode.FUNCTION_WITHOUT_CALL]);
+ }
verify([source]);
}
@@ -1536,7 +1564,11 @@
abstract class A implements Function {}
class B = Object with A;''');
await computeAnalysisResult(source);
- assertErrors(source, [StaticWarningCode.FUNCTION_WITHOUT_CALL]);
+ if (analysisOptions.strongMode) {
+ assertNoErrors(source);
+ } else {
+ assertErrors(source, [StaticWarningCode.FUNCTION_WITHOUT_CALL]);
+ }
verify([source]);
}
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index ab5f6b6..99871a4 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -2261,6 +2261,39 @@
expect(clazz.name.name, 'A2');
}
+ test_parseFileSync_notAbsolutePath() async {
+ try {
+ driver.parseFileSync('not_absolute.dart');
+ fail('ArgumentError expected.');
+ } on ArgumentError {}
+ }
+
+ test_parseFileSync_notDart() {
+ var p = _p('/test/bin/a.txt');
+ provider.newFile(p, 'class A {}');
+
+ ParseResult parseResult = driver.parseFileSync(p);
+ expect(parseResult, isNotNull);
+ expect(driver.knownFiles, contains(p));
+ }
+
+ test_parseFileSync_shouldRefresh() async {
+ var p = _p('/test/bin/a.dart');
+
+ provider.newFile(p, 'class A {}');
+ driver.addFile(p);
+
+ // Get the result, so force the file reading.
+ await driver.getResult(p);
+
+ // Update the file.
+ provider.newFile(p, 'class A2 {}');
+
+ ParseResult parseResult = driver.parseFileSync(p);
+ var clazz = parseResult.unit.declarations[0] as ClassDeclaration;
+ expect(clazz.name.name, 'A2');
+ }
+
test_part_getErrors_afterLibrary() async {
var a = _p('/test/lib/a.dart');
var b = _p('/test/lib/b.dart');
diff --git a/pkg/analyzer/test/src/dart/analysis/session_test.dart b/pkg/analyzer/test/src/dart/analysis/session_test.dart
index f49208d..8f8a4f4 100644
--- a/pkg/analyzer/test/src/dart/analysis/session_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/session_test.dart
@@ -210,6 +210,11 @@
Future<ParseResult> parseFile(String path) async {
return parseResult;
}
+
+ @override
+ ParseResult parseFileSync(String path) {
+ return parseResult;
+ }
}
class _SourceMock implements Source {
diff --git a/pkg/analyzer/test/src/summary/expr_builder_test.dart b/pkg/analyzer/test/src/summary/expr_builder_test.dart
index 7382339..0dedca8 100644
--- a/pkg/analyzer/test/src/summary/expr_builder_test.dart
+++ b/pkg/analyzer/test/src/summary/expr_builder_test.dart
@@ -4,6 +4,7 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/summary/expr_builder.dart';
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary/resynthesize.dart';
@@ -446,6 +447,9 @@
}
void test_pushLocalFunctionReference_nested() {
+ prepareAnalysisContext(new AnalysisOptionsImpl()
+ ..previewDart2 = false
+ ..strongMode = false);
var expr =
checkSimpleExpression('(x) => (y) => x + y') as FunctionExpression;
var outerFunctionElement = expr.element;
@@ -467,6 +471,9 @@
}
void test_pushLocalFunctionReference_paramReference() {
+ prepareAnalysisContext(new AnalysisOptionsImpl()
+ ..previewDart2 = false
+ ..strongMode = false);
var expr = checkSimpleExpression('(x, y) => x + y') as FunctionExpression;
var localFunctionElement = expr.element;
var xElement = localFunctionElement.parameters[0];
diff --git a/pkg/analyzer/test/src/task/dart_test.dart b/pkg/analyzer/test/src/task/dart_test.dart
index d6e3c01..51d6bb6 100644
--- a/pkg/analyzer/test/src/task/dart_test.dart
+++ b/pkg/analyzer/test/src/task/dart_test.dart
@@ -3757,8 +3757,13 @@
// validate
CompilationUnit unit = outputs[RESOLVED_UNIT4];
ClassDeclaration nodeB = unit.declarations[1];
- _assertTypeParameterBound(
- nodeB.typeParameters.typeParameters[0], 'A<dynamic>', 'A');
+ if (context.analysisOptions.strongMode) {
+ _assertTypeParameterBound(
+ nodeB.typeParameters.typeParameters[0], 'A<num>', 'A');
+ } else {
+ _assertTypeParameterBound(
+ nodeB.typeParameters.typeParameters[0], 'A<dynamic>', 'A');
+ }
}
test_perform_outputs() {
diff --git a/pkg/analyzer/test/src/task/options_test.dart b/pkg/analyzer/test/src/task/options_test.dart
index 186ab04..bd2a25f 100644
--- a/pkg/analyzer/test/src/task/options_test.dart
+++ b/pkg/analyzer/test/src/task/options_test.dart
@@ -52,7 +52,9 @@
optionsProvider.getOptionsFromString(source);
test_configure_bad_options_contents() {
- (analysisOptions as AnalysisOptionsImpl).previewDart2 = false;
+ (analysisOptions as AnalysisOptionsImpl)
+ ..previewDart2 = false
+ ..strongMode = false;
configureContext('''
analyzer:
strong-mode:true # misformatted
@@ -156,7 +158,9 @@
}
test_configure_strong_mode_bad_value() {
- (analysisOptions as AnalysisOptionsImpl).previewDart2 = false;
+ (analysisOptions as AnalysisOptionsImpl)
+ ..previewDart2 = false
+ ..strongMode = false;
configureContext('''
analyzer:
strong-mode: foo
diff --git a/pkg/analyzer/tool/task_dependency_graph/tasks.dot b/pkg/analyzer/tool/task_dependency_graph/tasks.dot
index a691f61..a812143 100644
--- a/pkg/analyzer/tool/task_dependency_graph/tasks.dot
+++ b/pkg/analyzer/tool/task_dependency_graph/tasks.dot
@@ -339,7 +339,6 @@
TYPE_PROVIDER -> PartiallyResolveUnitReferencesTask
TYPE_PROVIDER -> ResolveInstanceFieldsInUnitTask
TYPE_PROVIDER -> ResolveLibraryTypeNamesTask
- TYPE_PROVIDER -> ResolveTopLevelUnitTypeBoundsTask
TYPE_PROVIDER -> ResolveUnitTask
TYPE_PROVIDER -> ResolveUnitTypeNamesTask
TYPE_PROVIDER -> ResolveVariableReferencesTask
diff --git a/pkg/analyzer_cli/lib/src/context_cache.dart b/pkg/analyzer_cli/lib/src/context_cache.dart
index 7c82294..9f07d92 100644
--- a/pkg/analyzer_cli/lib/src/context_cache.dart
+++ b/pkg/analyzer_cli/lib/src/context_cache.dart
@@ -95,13 +95,11 @@
contextOptions.hint = !clOptions.disableHints;
contextOptions.generateImplicitErrors = clOptions.showPackageWarnings;
contextOptions.generateSdkErrors = clOptions.showSdkWarnings;
- if (clOptions.previewDart2 != null) {
- contextOptions.previewDart2 = clOptions.previewDart2;
- }
+ contextOptions.previewDart2 = clOptions.previewDart2;
+ contextOptions.strongMode = clOptions.strongMode;
if (clOptions.useCFE) {
contextOptions.useFastaParser = true;
}
-
return contextOptions;
}
diff --git a/pkg/analyzer_cli/lib/src/options.dart b/pkg/analyzer_cli/lib/src/options.dart
index 5136abf..071b3a4 100644
--- a/pkg/analyzer_cli/lib/src/options.dart
+++ b/pkg/analyzer_cli/lib/src/options.dart
@@ -189,8 +189,7 @@
machineFormat = args['format'] == 'machine',
perfReport = args['x-perf-report'],
useCFE = args['use-cfe'],
- previewDart2 =
- args.wasParsed('preview-dart-2') ? args['preview-dart-2'] : null,
+ previewDart2 = args['preview-dart-2'],
batchMode = args['batch'],
showPackageWarnings = args['show-package-warnings'] ||
args['package-warnings'] ||
@@ -515,7 +514,10 @@
negatable: false,
hide: hide)
..addFlag('preview-dart-2',
- help: 'Enable the Dart 2.0 preview.', hide: hide);
+ help: 'Enable the Dart 2.0 preview.',
+ defaultsTo: true,
+ hide: hide,
+ negatable: true);
try {
if (args.contains('--$ignoreUnrecognizedFlagsFlag')) {
diff --git a/pkg/analyzer_cli/test/options_test.dart b/pkg/analyzer_cli/test/options_test.dart
index bdde061..86ff443 100644
--- a/pkg/analyzer_cli/test/options_test.dart
+++ b/pkg/analyzer_cli/test/options_test.dart
@@ -72,10 +72,10 @@
expect(options.showSdkWarnings, isFalse);
expect(options.sourceFiles, equals(['foo.dart']));
expect(options.warningsAreFatal, isFalse);
- expect(options.strongMode, isFalse);
+ expect(options.strongMode, isTrue);
expect(options.lintsAreFatal, isFalse);
expect(options.useCFE, isFalse);
- expect(options.previewDart2, null);
+ expect(options.previewDart2, isTrue);
});
test('batch', () {
diff --git a/pkg/analyzer_plugin/lib/src/protocol/protocol_internal.dart b/pkg/analyzer_plugin/lib/src/protocol/protocol_internal.dart
index 5778af8..ba03cb8 100644
--- a/pkg/analyzer_plugin/lib/src/protocol/protocol_internal.dart
+++ b/pkg/analyzer_plugin/lib/src/protocol/protocol_internal.dart
@@ -277,11 +277,9 @@
if (json is int) {
return json;
} else if (json is String) {
- int value = int.tryParse(json);
- if (value == null) {
+ return int.parse(json, onError: (String value) {
throw mismatch(jsonPath, 'int', json);
- }
- return value;
+ });
}
throw mismatch(jsonPath, 'int', json);
}
diff --git a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
index e0728a5..9759e18 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
@@ -1288,17 +1288,6 @@
});
} else {
int offset = next.offset;
- Token comment = next.beginToken.precedingComments;
- while (comment != null) {
- int commentOffset = comment.offset;
- if (commentOffset ==
- lineInfo.getOffsetOfLine(
- lineInfo.getLocation(commentOffset).lineNumber - 1)) {
- offset = commentOffset;
- break;
- }
- comment = comment.next;
- }
addInsertion(offset, (EditBuilder builder) {
builder.write("import '");
builder.write(uri);
diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
index 8579f0e..018c068 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
@@ -543,7 +543,10 @@
// If the current token is synthetic, then check the previous token
// because it may have been dropped from the parse tree
Token previous = node.findPrevious(token);
- if (offset < previous.end) {
+ if (previous == null) {
+ // support dangling expression completion, where previous may be null.
+ return false;
+ } else if (offset < previous.end) {
return true;
} else if (offset == previous.end) {
return token.type.isKeyword || previous.type == TokenType.IDENTIFIER;
diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
index 15f7284..a7a52c0 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
@@ -27,15 +27,6 @@
bool includeConstructorSuggestions = false;
/**
- * If [includeConstructorSuggestions] is set to true, then this function may
- * be set to a non-default function to filter out potential suggestions (null)
- * based on their static [DartType], or change the relative relevance by
- * returning a higher or lower relevance.
- */
- SuggestionsFilter constructorSuggestionsFilter =
- (DartType _, int relevance) => relevance;
-
- /**
* Indicates whether type names should be suggested.
*/
bool includeTypeNameSuggestions = false;
@@ -210,20 +201,6 @@
return;
}
- constructorSuggestionsFilter = (DartType dartType, int relevance) {
- if (dartType != null) {
- if (dartType == _requiredType) {
- return relevance + DART_RELEVANCE_BOOST_TYPE;
- } else if (dartType.isSubtypeOf(_requiredType)) {
- return relevance + DART_RELEVANCE_BOOST_SUBTYPE;
- }
- if (target.containingNode is InstanceCreationExpression) {
- return null;
- }
- }
- return relevance;
- };
-
returnValueSuggestionsFilter = (DartType dartType, int relevance) {
if (dartType != null) {
if (dartType == _requiredType) {
diff --git a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
index 4cc4c03..a849278 100644
--- a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
@@ -240,8 +240,8 @@
import 'foo.dart';
''', ['package:aaa/a1.dart'], '''
-import 'package:aaa/a1.dart';
// comment a2
+import 'package:aaa/a1.dart';
import 'package:aaa/a2.dart';
import 'foo.dart';
diff --git a/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart b/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart
index e48e3ea..f89d484 100644
--- a/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart
@@ -16,15 +16,23 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(OpTypeTest);
+ defineReflectiveTests(OpTypeDart1OnlyTest);
+ defineReflectiveTests(OpTypeDart1Test);
});
}
-@reflectiveTest
-class OpTypeTest extends AbstractContextTest {
+/// Common test methods to Dart1/Dart2 versions of OpType tests.
+class OpTypeTestCommon extends AbstractContextTest {
String testpath;
int completionOffset;
OpType visitor;
+ @override
+ void setUp() {
+ super.setUp();
+ testpath = provider.convertPath('/completionTest.dart');
+ }
+
void addTestSource(String content) {
completionOffset = content.indexOf('^');
expect(completionOffset, isNot(equals(-1)), reason: 'missing ^');
@@ -72,13 +80,26 @@
expect(visitor.isPrefixed, prefixed, reason: 'prefixed');
expect(visitor.suggestKind, kind, reason: 'suggestion kind');
}
+}
+
+/// Execute the tests that work on both.
+@reflectiveTest
+class OpTypeDart1Test extends OpTypeTest {
+ @override
+ bool get enablePreviewDart2 => false;
@override
- void setUp() {
- super.setUp();
- testpath = provider.convertPath('/completionTest.dart');
- }
+ bool get enableStrongMode => false;
+}
+@reflectiveTest
+// TODO: determine if tests here need to be fixed for Dart2.
+class OpTypeDart1OnlyTest extends OpTypeTestCommon {
+ @override
+ bool get enablePreviewDart2 => false;
+
+ @override
+ bool get enableStrongMode => false;
test_Annotation() async {
// SimpleIdentifier Annotation MethodDeclaration ClassDeclaration
addTestSource('class C { @A^ }');
@@ -98,90 +119,6 @@
typeNames: true);
}
- test_ArgumentList_constructor_named_resolved_1_0() async {
- // ArgumentList InstanceCreationExpression ExpressionStatement Block
- addTestSource(
- 'main() { new A.b(^); }'
- 'class A{ A.b({one, two}) {} }',
- );
- await assertOpType(namedArgs: true);
- }
-
- test_ArgumentList_constructor_named_resolved_1_1() async {
- // ArgumentList InstanceCreationExpression ExpressionStatement Block
- addTestSource(
- 'main() { new A.b(o^); }'
- 'class A { A.b({one, two}) {} }',
- );
- await assertOpType(namedArgs: true);
- }
-
- test_ArgumentList_constructor_resolved_1_0() async {
- // ArgumentList InstanceCreationExpression ExpressionStatement Block
- addTestSource(
- 'main() { new A(^); }'
- 'class A{ A({one, two}) {} }',
- );
- await assertOpType(namedArgs: true);
- }
-
- test_ArgumentList_constructor_resolved_1_1() async {
- // ArgumentList InstanceCreationExpression ExpressionStatement Block
- addTestSource(
- 'main() { new A(o^); }'
- 'class A { A({one, two}) {} }',
- );
- await assertOpType(namedArgs: true);
- }
-
- test_ArgumentList_factory_named_resolved_1_0() async {
- // ArgumentList InstanceCreationExpression ExpressionStatement Block
- addTestSource(
- 'main() { new A.b(^); }'
- 'class A{ factory A.b({one, two}) {} }',
- );
- await assertOpType(namedArgs: true);
- }
-
- test_ArgumentList_factory_named_resolved_1_1() async {
- // ArgumentList InstanceCreationExpression ExpressionStatement Block
- addTestSource(
- 'main() { new A.b(o^); }'
- 'class A { factory A.b({one, two}) {} }',
- );
- await assertOpType(namedArgs: true);
- }
-
- test_ArgumentList_factory_resolved_1_0() async {
- // ArgumentList InstanceCreationExpression ExpressionStatement Block
- addTestSource(
- 'main() { new A(^); }'
- 'class A{ factory A({one, two}) {} }',
- );
- await assertOpType(namedArgs: true);
- }
-
- test_ArgumentList_factory_resolved_1_1() async {
- // ArgumentList InstanceCreationExpression ExpressionStatement Block
- addTestSource(
- 'main() { new A(o^); }'
- 'class A { factory A({one, two}) {} }',
- );
- await assertOpType(namedArgs: true);
- }
-
- test_ArgumentList_method_resolved_1_0() async {
- // ArgumentList MethodInvocation ExpressionStatement Block
- addTestSource('main() { foo(^);} foo({one, two}) {}');
- await assertOpType(namedArgs: true);
- }
-
- test_ArgumentList_method_resolved_1_1() async {
- // ArgumentList MethodInvocation ExpressionStatement Block
- addTestSource('main() { foo(o^);} foo({one, two}) {}');
- await assertOpType(namedArgs: true);
- }
-
test_ArgumentList_namedParam() async {
// SimpleIdentifier NamedExpression ArgumentList MethodInvocation
// ExpressionStatement
@@ -207,18 +144,6 @@
constructors: previewDart2, returnValue: true, typeNames: true);
}
- test_ArgumentList_resolved_2_0() async {
- // ArgumentList MethodInvocation ExpressionStatement Block
- addTestSource('void main() {int.parse("16", ^)}');
- await assertOpType(namedArgs: true);
- }
-
- test_AsExpression() async {
- // SimpleIdentifier TypeName AsExpression
- addTestSource('class A {var b; X _c; foo() {var a; (a as ^).foo();}');
- await assertOpType(typeNames: true);
- }
-
test_AsIdentifier() async {
addTestSource('class A {var asdf; foo() {as^}');
await assertOpType(
@@ -228,11 +153,6 @@
voidReturn: true);
}
- test_AsIdentifier2() async {
- addTestSource('class A {var asdf; foo() {A as^}');
- await assertOpType();
- }
-
test_Assert() async {
addTestSource('main() {assert(^)}');
await assertOpType(
@@ -245,13 +165,6 @@
constructors: previewDart2, returnValue: true, typeNames: true);
}
- test_AssignmentExpression_name() async {
- // SimpleIdentifier VariableDeclaration VariableDeclarationList
- // VariableDeclarationStatement Block
- addTestSource('class A {} main() {int a; int ^b = 1;}');
- await assertOpType(varNames: true);
- }
-
test_AssignmentExpression_RHS() async {
// SimpleIdentifier VariableDeclaration VariableDeclarationList
// VariableDeclarationStatement Block
@@ -418,34 +331,6 @@
voidReturn: true);
}
- test_Block_catch_1a() async {
- // '}' Block BlockFunctionBody FunctionExpression
- addTestSource('main() {try {} ^}');
- // Only return 'on', 'catch', and 'finally' keywords
- await assertOpType();
- }
-
- test_Block_catch_1b() async {
- // [ExpressionStatement 'c'] Block BlockFunctionBody
- addTestSource('main() {try {} c^}');
- // Only return 'on', 'catch', and 'finally' keywords
- await assertOpType();
- }
-
- test_Block_catch_1c() async {
- // [EmptyStatement] Block BlockFunctionBody FunctionExpression
- addTestSource('main() {try {} ^;}');
- // Only return 'on', 'catch', and 'finally' keywords
- await assertOpType();
- }
-
- test_Block_catch_1d() async {
- // [VariableDeclarationStatement 'Foo foo'] Block BlockFunctionBody
- addTestSource('main() {try {} ^ Foo foo;}');
- // Only return 'on', 'catch', and 'finally' keywords
- await assertOpType();
- }
-
test_Block_catch_2a() async {
// '}' Block BlockFunctionBody FunctionExpression
addTestSource('main() {try {} catch () {} ^}');
@@ -526,9 +411,8 @@
voidReturn: true);
}
- test_Block_empty() async {
- // Block BlockFunctionBody MethodDeclaration ClassDeclaration
- addTestSource('class A extends E implements I with M {a() {^}}');
+ test_Block_identifier_partial() async {
+ addTestSource('class X {a() {var f; {var x;} D^ var r;} void b() { }}');
await assertOpType(
constructors: previewDart2,
returnValue: true,
@@ -536,33 +420,9 @@
voidReturn: true);
}
- test_Block_final() async {
- addTestSource('main() {final ^}');
- await assertOpType(typeNames: true);
- }
-
- test_Block_final2() async {
- addTestSource('main() {final S^ v;}');
- await assertOpType(typeNames: true);
- }
-
- test_Block_final3() async {
- addTestSource('main() {final ^ v;}');
- await assertOpType(typeNames: true);
- }
-
- test_Block_final_final() async {
- addTestSource('main() {final ^ final S x;}');
- await assertOpType(typeNames: true);
- }
-
- test_Block_final_final2() async {
- addTestSource('main() {final S^ final S x;}');
- await assertOpType(typeNames: true);
- }
-
- test_Block_identifier_partial() async {
- addTestSource('class X {a() {var f; {var x;} D^ var r;} void b() { }}');
+ test_Block_empty() async {
+ // Block BlockFunctionBody MethodDeclaration ClassDeclaration
+ addTestSource('class A extends E implements I with M {a() {^}}');
await assertOpType(
constructors: previewDart2,
returnValue: true,
@@ -590,21 +450,6 @@
voidReturn: true);
}
- test_Break_after_label() async {
- addTestSource('main() { foo: while (true) { break foo ^ ; } }');
- await assertOpType(/* No valid completions */);
- }
-
- test_Break_before_label() async {
- addTestSource('main() { foo: while (true) { break ^ foo; } }');
- await assertOpType(statementLabel: true);
- }
-
- test_Break_no_label() async {
- addTestSource('main() { foo: while (true) { break ^; } }');
- await assertOpType(statementLabel: true);
- }
-
test_CascadeExpression_selector1() async {
// PropertyAccess CascadeExpression ExpressionStatement Block
addTestSource('''
@@ -649,6 +494,740 @@
voidReturn: true);
}
+ test_CatchClause_typed() async {
+ // Block CatchClause TryStatement
+ addTestSource('class A {a() {try{var x;} on E catch (e) {^}}}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true);
+ }
+
+ test_CatchClause_untyped() async {
+ // Block CatchClause TryStatement
+ addTestSource('class A {a() {try{var x;} catch (e, s) {^}}}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true);
+ }
+
+ test_CommentReference() async {
+ // SimpleIdentifier CommentReference Comment MethodDeclaration
+ addTestSource('class A {/** [^] */ mth() {}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true,
+ kind: CompletionSuggestionKind.IDENTIFIER);
+ }
+
+ test_ConditionalExpression_elseExpression() async {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addTestSource('class C {foo(){var f; {var x;} return a ? T1 : T^}}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_ConditionalExpression_elseExpression_empty() async {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addTestSource('class C {foo(){var f; {var x;} return a ? T1 : ^}}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_ConditionalExpression_partial_thenExpression() async {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addTestSource('class C {foo(){var f; {var x;} return a ? T^}}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_ConditionalExpression_partial_thenExpression_empty() async {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addTestSource('class C {foo(){var f; {var x;} return a ? ^}}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_ConditionalExpression_thenExpression() async {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addTestSource('class C {foo(){var f; {var x;} return a ? T^ : c}}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_DefaultFormalParameter_named_expression() async {
+ // DefaultFormalParameter FormalParameterList MethodDeclaration
+ addTestSource('class A {a(blat: ^) { }}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_DoStatement() async {
+ // SimpleIdentifier DoStatement Block
+ addTestSource('main() {do{} while(^x);}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_ExpressionFunctionBody() async {
+ // SimpleIdentifier ExpressionFunctionBody FunctionExpression
+ addTestSource('m(){[1].forEach((x)=>^x);}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_ExpressionStatement() async {
+ // ExpressionStatement Block BlockFunctionBody
+ addTestSource('n(){f(3);^}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true);
+ }
+
+ test_ForEachStatement() async {
+ // SimpleIdentifier ForEachStatement Block
+ addTestSource('main() {for(z in ^zs) {}}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_ForEachStatement_body_typed() async {
+ // Block ForEachStatement
+ addTestSource('main(args) {for (int foo in bar) {^}}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true);
+ }
+
+ test_ForEachStatement_body_untyped() async {
+ // Block ForEachStatement
+ addTestSource('main(args) {for (foo in bar) {^}}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true);
+ }
+
+ test_ForEachStatement_iterable() async {
+ // SimpleIdentifier ForEachStatement Block
+ addTestSource('main(args) {for (int foo in ^) {}}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_FormalParameter_partialType() async {
+ // FormalParameterList MethodDeclaration
+ addTestSource('class A {a(b.^ f) { }}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ prefixed: true);
+ }
+
+ test_FormalParameter_partialType2() async {
+ // FormalParameterList MethodDeclaration
+ addTestSource('class A {a(b.z^ f) { }}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ prefixed: true);
+ }
+
+ test_FormalParameter_partialType3() async {
+ // FormalParameterList MethodDeclaration
+ addTestSource('class A {a(b.^) { }}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ prefixed: true);
+ }
+
+ test_ForStatement_condition() async {
+ // SimpleIdentifier ForStatement
+ addTestSource('main() {for (int index = 0; i^)}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_ForStatement_updaters() async {
+ // SimpleIdentifier ForStatement
+ addTestSource('main() {for (int index = 0; index < 10; i^)}');
+ // TODO (danrubel) may want to exclude methods/functions with void return
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true);
+ }
+
+ test_ForStatement_updaters_prefix_expression() async {
+ // SimpleIdentifier PrefixExpression ForStatement
+ addTestSource('main() {for (int index = 0; index < 10; ++i^)}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_IfStatement() async {
+ // EmptyStatement IfStatement Block BlockFunctionBody
+ addTestSource('main(){var a; if (true) ^}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true);
+ }
+
+ test_IfStatement_condition() async {
+ // SimpleIdentifier IfStatement Block BlockFunctionBody
+ addTestSource('main(){var a; if (^)}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_IfStatement_empty() async {
+ // SimpleIdentifier PrefixIdentifier IfStatement
+ addTestSource('class A {foo() {A a; if (^) something}}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_IfStatement_invocation() async {
+ // SimpleIdentifier PrefixIdentifier IfStatement
+ addTestSource('main() {var a; if (a.^) something}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ prefixed: true);
+ }
+
+ test_IndexExpression() async {
+ addTestSource('class C {foo(){var f; {var x;} f[^]}}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_IndexExpression2() async {
+ addTestSource('class C {foo(){var f; {var x;} f[T^]}}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_InstanceCreationExpression_keyword() async {
+ // InstanceCreationExpression ExpressionStatement Block
+ addTestSource('class C {foo(){var f; {var x;} new^ }}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true);
+ }
+
+ test_InstanceCreationExpression_keyword2() async {
+ // InstanceCreationExpression ExpressionStatement Block
+ addTestSource('class C {foo(){var f; {var x;} new^ C();}}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true);
+ }
+
+ test_InterpolationExpression() async {
+ // SimpleIdentifier InterpolationExpression StringInterpolation
+ addTestSource('main() {String name; print("hello \$^");}');
+ await assertOpType(constructors: previewDart2, returnValue: true);
+ }
+
+ test_InterpolationExpression_block() async {
+ // SimpleIdentifier InterpolationExpression StringInterpolation
+ addTestSource('main() {String name; print("hello \${n^}");}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_InterpolationExpression_prefix_selector() async {
+ // SimpleIdentifier PrefixedIdentifier InterpolationExpression
+ addTestSource('main() {String name; print("hello \${name.^}");}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ prefixed: true);
+ }
+
+ test_InterpolationExpression_prefix_target() async {
+ // SimpleIdentifier PrefixedIdentifier InterpolationExpression
+ addTestSource('main() {String name; print("hello \${nam^e.length}");}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_IsExpression_target() async {
+ // IfStatement Block BlockFunctionBody
+ addTestSource('main(){var a; if (^ is A)}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_Literal_list() async {
+ // ']' ListLiteral ArgumentList MethodInvocation
+ addTestSource('main() {var Some; print([^]);}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_Literal_list2() async {
+ // SimpleIdentifier ListLiteral ArgumentList MethodInvocation
+ addTestSource('main() {var Some; print([S^]);}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_MapLiteralEntry() async {
+ // MapLiteralEntry MapLiteral VariableDeclaration
+ addTestSource('foo = {^');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_MapLiteralEntry1() async {
+ // MapLiteralEntry MapLiteral VariableDeclaration
+ addTestSource('foo = {T^');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_MapLiteralEntry2() async {
+ // SimpleIdentifier MapLiteralEntry MapLiteral VariableDeclaration
+ addTestSource('foo = {7:T^};');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_MethodInvocation_no_semicolon() async {
+ // MethodInvocation ExpressionStatement Block
+ addTestSource('''
+ class A implements I {
+ // no semicolon between completion point and next statement
+ set _s2(I x) {x.^ m(null);}
+ }''');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true,
+ prefixed: true);
+ }
+
+ test_PostfixExpression() async {
+ // SimpleIdentifier PostfixExpression ForStatement
+ addTestSource('int x = 0; main() {ax+^+;}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_PrefixedIdentifier_class_const() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement Block
+ addTestSource('main() {A.^}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true,
+ prefixed: true);
+ }
+
+ test_PrefixedIdentifier_class_imported() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addTestSource('main() {A a; a.^}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true,
+ prefixed: true);
+ }
+
+ test_PrefixedIdentifier_prefix() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addTestSource('class X {foo(){A^.bar}}');
+ await assertOpType(
+ constructors: previewDart2,
+ typeNames: true,
+ returnValue: true,
+ voidReturn: true);
+ }
+
+ test_PropertyAccess_expression() async {
+ // SimpleIdentifier MethodInvocation PropertyAccess ExpressionStatement
+ addTestSource('class A {a() {"hello".to^String().length}}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true,
+ prefixed: true);
+ }
+
+ test_PropertyAccess_selector() async {
+ // SimpleIdentifier PropertyAccess ExpressionStatement Block
+ addTestSource('class A {a() {"hello".length.^}}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true,
+ prefixed: true);
+ }
+
+ test_ReturnStatement() async {
+ // ReturnStatement Block
+ addTestSource('f() { var vvv = 42; return ^ }');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_SwitchCase_between() async {
+ // SwitchCase SwitchStatement Block
+ addTestSource('main() {switch(k) {case 1: ^ case 2: return}}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true);
+ }
+
+ test_SwitchCase_expression1() async {
+ // SimpleIdentifier SwitchCase SwitchStatement
+ addTestSource('''m() {switch (x) {case ^D: return;}}''');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_SwitchCase_expression2() async {
+ // SimpleIdentifier SwitchCase SwitchStatement
+ addTestSource('''m() {switch (x) {case ^}}''');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_SwitchDefault_between() async {
+ // SwitchDefault SwitchStatement Block
+ addTestSource('main() {switch(k) {case 1: ^ default: return;}}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true);
+ }
+
+ test_SwitchStatement_body_end() async {
+ // Token('}') SwitchStatement Block
+ addTestSource('main() {switch(k) {case 1:^}}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true);
+ }
+
+ test_SwitchStatement_body_end2() async {
+ addTestSource('main() {switch(k) {case 1:as^}}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true);
+ }
+
+ test_SwitchStatement_expression1() async {
+ // SimpleIdentifier SwitchStatement Block
+ addTestSource('main() {switch(^k) {case 1:{}}}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_SwitchStatement_expression2() async {
+ // SimpleIdentifier SwitchStatement Block
+ addTestSource('main() {switch(k^) {case 1:{}}}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_SwitchStatement_expression_empty() async {
+ // SimpleIdentifier SwitchStatement Block
+ addTestSource('main() {switch(^) {case 1:{}}}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_ThisExpression_block() async {
+ // MethodInvocation ExpressionStatement Block
+ addTestSource('''
+ class A implements I {
+ // no semicolon between completion point and next statement
+ set s1(I x) {} set _s2(I x) {this.^ m(null);}
+ }''');
+ // TODO(brianwilkerson) We should not be adding constructors here.
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ voidReturn: true,
+ prefixed: true);
+ }
+
+ test_ThisExpression_constructor() async {
+ // SimpleIdentifier PropertyAccess ExpressionStatement
+ addTestSource('''
+ class A implements I {
+ A() {this.^}
+ }''');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ voidReturn: true,
+ prefixed: true);
+ }
+
+ test_ThrowExpression() async {
+ // SimpleIdentifier ThrowExpression ExpressionStatement
+ addTestSource('main() {throw ^;}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_VariableDeclarationStatement_afterSemicolon() async {
+ // VariableDeclarationStatement Block BlockFunctionBody
+ addTestSource('class A {var a; x() {var b;^}}');
+ await assertOpType(
+ constructors: previewDart2,
+ returnValue: true,
+ typeNames: true,
+ voidReturn: true);
+ }
+
+ test_VariableDeclarationStatement_RHS() async {
+ // SimpleIdentifier VariableDeclaration VariableDeclarationList
+ // VariableDeclarationStatement
+ addTestSource('class C {bar(){var f; {var x;} var e = ^}}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_VariableDeclarationStatement_RHS_missing_semicolon() async {
+ // VariableDeclaration VariableDeclarationList
+ // VariableDeclarationStatement
+ addTestSource('class C {bar(){var f; {var x;} var e = ^ var g}}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_WhileStatement() async {
+ // SimpleIdentifier WhileStatement Block
+ addTestSource('mth() { while (b^) {} }}');
+ await assertOpType(
+ constructors: previewDart2, returnValue: true, typeNames: true);
+ }
+
+ test_WithClause() async {
+ // WithClause ClassDeclaration
+ addTestSource('class x extends Object with ^\n{}');
+ await assertOpType(constructors: previewDart2, typeNames: true);
+ }
+}
+
+@reflectiveTest
+class OpTypeTest extends OpTypeTestCommon {
+ test_ArgumentList_constructor_named_resolved_1_0() async {
+ // ArgumentList InstanceCreationExpression ExpressionStatement Block
+ addTestSource(
+ 'main() { new A.b(^); }'
+ 'class A{ A.b({one, two}) {} }',
+ );
+ await assertOpType(namedArgs: true);
+ }
+
+ test_ArgumentList_constructor_named_resolved_1_1() async {
+ // ArgumentList InstanceCreationExpression ExpressionStatement Block
+ addTestSource(
+ 'main() { new A.b(o^); }'
+ 'class A { A.b({one, two}) {} }',
+ );
+ await assertOpType(namedArgs: true);
+ }
+
+ test_ArgumentList_constructor_resolved_1_0() async {
+ // ArgumentList InstanceCreationExpression ExpressionStatement Block
+ addTestSource(
+ 'main() { new A(^); }'
+ 'class A{ A({one, two}) {} }',
+ );
+ await assertOpType(namedArgs: true);
+ }
+
+ test_ArgumentList_constructor_resolved_1_1() async {
+ // ArgumentList InstanceCreationExpression ExpressionStatement Block
+ addTestSource(
+ 'main() { new A(o^); }'
+ 'class A { A({one, two}) {} }',
+ );
+ await assertOpType(namedArgs: true);
+ }
+
+ test_ArgumentList_factory_named_resolved_1_0() async {
+ // ArgumentList InstanceCreationExpression ExpressionStatement Block
+ addTestSource(
+ 'main() { new A.b(^); }'
+ 'class A{ factory A.b({one, two}) {} }',
+ );
+ await assertOpType(namedArgs: true);
+ }
+
+ test_ArgumentList_factory_named_resolved_1_1() async {
+ // ArgumentList InstanceCreationExpression ExpressionStatement Block
+ addTestSource(
+ 'main() { new A.b(o^); }'
+ 'class A { factory A.b({one, two}) {} }',
+ );
+ await assertOpType(namedArgs: true);
+ }
+
+ test_ArgumentList_factory_resolved_1_0() async {
+ // ArgumentList InstanceCreationExpression ExpressionStatement Block
+ addTestSource(
+ 'main() { new A(^); }'
+ 'class A{ factory A({one, two}) {} }',
+ );
+ await assertOpType(namedArgs: true);
+ }
+
+ test_ArgumentList_factory_resolved_1_1() async {
+ // ArgumentList InstanceCreationExpression ExpressionStatement Block
+ addTestSource(
+ 'main() { new A(o^); }'
+ 'class A { factory A({one, two}) {} }',
+ );
+ await assertOpType(namedArgs: true);
+ }
+
+ test_ArgumentList_method_resolved_1_0() async {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addTestSource('main() { foo(^);} foo({one, two}) {}');
+ await assertOpType(namedArgs: true);
+ }
+
+ test_ArgumentList_method_resolved_1_1() async {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addTestSource('main() { foo(o^);} foo({one, two}) {}');
+ await assertOpType(namedArgs: true);
+ }
+
+ test_ArgumentList_resolved_2_0() async {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addTestSource('void main() {int.parse("16", ^)}');
+ await assertOpType(namedArgs: true);
+ }
+
+ test_AsExpression() async {
+ // SimpleIdentifier TypeName AsExpression
+ addTestSource('class A {var b; X _c; foo() {var a; (a as ^).foo();}');
+ await assertOpType(typeNames: true);
+ }
+
+ test_AsIdentifier2() async {
+ addTestSource('class A {var asdf; foo() {A as^}');
+ await assertOpType();
+ }
+
+ test_AssignmentExpression_name() async {
+ // SimpleIdentifier VariableDeclaration VariableDeclarationList
+ // VariableDeclarationStatement Block
+ addTestSource('class A {} main() {int a; int ^b = 1;}');
+ await assertOpType(varNames: true);
+ }
+
+ test_Block_catch_1a() async {
+ // '}' Block BlockFunctionBody FunctionExpression
+ addTestSource('main() {try {} ^}');
+ // Only return 'on', 'catch', and 'finally' keywords
+ await assertOpType();
+ }
+
+ test_Block_catch_1b() async {
+ // [ExpressionStatement 'c'] Block BlockFunctionBody
+ addTestSource('main() {try {} c^}');
+ // Only return 'on', 'catch', and 'finally' keywords
+ await assertOpType();
+ }
+
+ test_Block_catch_1c() async {
+ // [EmptyStatement] Block BlockFunctionBody FunctionExpression
+ addTestSource('main() {try {} ^;}');
+ // Only return 'on', 'catch', and 'finally' keywords
+ await assertOpType();
+ }
+
+ test_Block_catch_1d() async {
+ // [VariableDeclarationStatement 'Foo foo'] Block BlockFunctionBody
+ addTestSource('main() {try {} ^ Foo foo;}');
+ // Only return 'on', 'catch', and 'finally' keywords
+ await assertOpType();
+ }
+
+ test_Block_final() async {
+ addTestSource('main() {final ^}');
+ await assertOpType(typeNames: true);
+ }
+
+ test_Block_final2() async {
+ addTestSource('main() {final S^ v;}');
+ await assertOpType(typeNames: true);
+ }
+
+ test_Block_final3() async {
+ addTestSource('main() {final ^ v;}');
+ await assertOpType(typeNames: true);
+ }
+
+ test_Block_final_final() async {
+ addTestSource('main() {final ^ final S x;}');
+ await assertOpType(typeNames: true);
+ }
+
+ test_Block_final_final2() async {
+ addTestSource('main() {final S^ final S x;}');
+ await assertOpType(typeNames: true);
+ }
+
+ test_Break_after_label() async {
+ addTestSource('main() { foo: while (true) { break foo ^ ; } }');
+ await assertOpType(/* No valid completions */);
+ }
+
+ test_Break_before_label() async {
+ addTestSource('main() { foo: while (true) { break ^ foo; } }');
+ await assertOpType(statementLabel: true);
+ }
+
+ test_Break_no_label() async {
+ addTestSource('main() { foo: while (true) { break ^; } }');
+ await assertOpType(statementLabel: true);
+ }
+
test_catch_4a1() async {
addTestSource('main() {try {} ^ on SomeException {}}');
await assertOpType();
@@ -701,26 +1280,6 @@
await assertOpType(typeNames: true);
}
- test_CatchClause_typed() async {
- // Block CatchClause TryStatement
- addTestSource('class A {a() {try{var x;} on E catch (e) {^}}}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true);
- }
-
- test_CatchClause_untyped() async {
- // Block CatchClause TryStatement
- addTestSource('class A {a() {try{var x;} catch (e, s) {^}}}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true);
- }
-
test_ClassDeclaration_body() async {
// ClassDeclaration CompilationUnit
addTestSource('@deprecated class A {^}');
@@ -750,52 +1309,6 @@
await assertOpType();
}
- test_CommentReference() async {
- // SimpleIdentifier CommentReference Comment MethodDeclaration
- addTestSource('class A {/** [^] */ mth() {}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true,
- kind: CompletionSuggestionKind.IDENTIFIER);
- }
-
- test_ConditionalExpression_elseExpression() async {
- // SimpleIdentifier ConditionalExpression ReturnStatement
- addTestSource('class C {foo(){var f; {var x;} return a ? T1 : T^}}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_ConditionalExpression_elseExpression_empty() async {
- // SimpleIdentifier ConditionalExpression ReturnStatement
- addTestSource('class C {foo(){var f; {var x;} return a ? T1 : ^}}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_ConditionalExpression_partial_thenExpression() async {
- // SimpleIdentifier ConditionalExpression ReturnStatement
- addTestSource('class C {foo(){var f; {var x;} return a ? T^}}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_ConditionalExpression_partial_thenExpression_empty() async {
- // SimpleIdentifier ConditionalExpression ReturnStatement
- addTestSource('class C {foo(){var f; {var x;} return a ? ^}}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_ConditionalExpression_thenExpression() async {
- // SimpleIdentifier ConditionalExpression ReturnStatement
- addTestSource('class C {foo(){var f; {var x;} return a ? T^ : c}}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
test_ConstructorName() async {
// SimpleIdentifier PrefixedIdentifier TypeName ConstructorName
// InstanceCreationExpression
@@ -839,42 +1352,11 @@
await assertOpType(statementLabel: true, caseLabel: true);
}
- test_DefaultFormalParameter_named_expression() async {
- // DefaultFormalParameter FormalParameterList MethodDeclaration
- addTestSource('class A {a(blat: ^) { }}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_DoStatement() async {
- // SimpleIdentifier DoStatement Block
- addTestSource('main() {do{} while(^x);}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
test_DoubleLiteral() async {
addTestSource('main() { print(1.2^); }');
await assertOpType();
}
- test_ExpressionFunctionBody() async {
- // SimpleIdentifier ExpressionFunctionBody FunctionExpression
- addTestSource('m(){[1].forEach((x)=>^x);}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_ExpressionStatement() async {
- // ExpressionStatement Block BlockFunctionBody
- addTestSource('n(){f(3);^}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true);
- }
-
test_ExpressionStatement_name() async {
// ExpressionStatement Block BlockFunctionBody MethodDeclaration
addTestSource('class C {a() {C ^}}');
@@ -919,40 +1401,6 @@
await assertOpType();
}
- test_ForEachStatement() async {
- // SimpleIdentifier ForEachStatement Block
- addTestSource('main() {for(z in ^zs) {}}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_ForEachStatement_body_typed() async {
- // Block ForEachStatement
- addTestSource('main(args) {for (int foo in bar) {^}}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true);
- }
-
- test_ForEachStatement_body_untyped() async {
- // Block ForEachStatement
- addTestSource('main(args) {for (foo in bar) {^}}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true);
- }
-
- test_ForEachStatement_iterable() async {
- // SimpleIdentifier ForEachStatement Block
- addTestSource('main(args) {for (int foo in ^) {}}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
test_ForEachStatement_loopVariable() async {
// SimpleIdentifier ForEachStatement Block
addTestSource('main(args) {for (^ in args) {}}');
@@ -983,49 +1431,12 @@
await assertOpType(typeNames: true);
}
- test_FormalParameter_partialType() async {
- // FormalParameterList MethodDeclaration
- addTestSource('class A {a(b.^ f) { }}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- prefixed: true);
- }
-
- test_FormalParameter_partialType2() async {
- // FormalParameterList MethodDeclaration
- addTestSource('class A {a(b.z^ f) { }}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- prefixed: true);
- }
-
- test_FormalParameter_partialType3() async {
- // FormalParameterList MethodDeclaration
- addTestSource('class A {a(b.^) { }}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- prefixed: true);
- }
-
test_FormalParameterList() async {
// FormalParameterList MethodDeclaration
addTestSource('class A {a(^) { }}');
await assertOpType(typeNames: true);
}
- test_ForStatement_condition() async {
- // SimpleIdentifier ForStatement
- addTestSource('main() {for (int index = 0; i^)}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
test_ForStatement_initializer() async {
// SimpleIdentifier ForStatement
addTestSource('main() {List a; for (^)}');
@@ -1048,24 +1459,6 @@
await assertOpType(varNames: true);
}
- test_ForStatement_updaters() async {
- // SimpleIdentifier ForStatement
- addTestSource('main() {for (int index = 0; index < 10; i^)}');
- // TODO (danrubel) may want to exclude methods/functions with void return
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true);
- }
-
- test_ForStatement_updaters_prefix_expression() async {
- // SimpleIdentifier PrefixExpression ForStatement
- addTestSource('main() {for (int index = 0; index < 10; ++i^)}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
test_FunctionDeclaration1() async {
// SimpleIdentifier FunctionDeclaration CompilationUnit
addTestSource('const ^Fara();');
@@ -1233,40 +1626,6 @@
await assertOpType(typeNames: true);
}
- test_IfStatement() async {
- // EmptyStatement IfStatement Block BlockFunctionBody
- addTestSource('main(){var a; if (true) ^}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true);
- }
-
- test_IfStatement_condition() async {
- // SimpleIdentifier IfStatement Block BlockFunctionBody
- addTestSource('main(){var a; if (^)}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_IfStatement_empty() async {
- // SimpleIdentifier PrefixIdentifier IfStatement
- addTestSource('class A {foo() {A a; if (^) something}}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_IfStatement_invocation() async {
- // SimpleIdentifier PrefixIdentifier IfStatement
- addTestSource('main() {var a; if (a.^) something}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- prefixed: true);
- }
-
test_ImplementsClause() async {
// ImplementsClause ClassDeclaration
addTestSource('class x implements ^\n{}');
@@ -1281,44 +1640,12 @@
await assertOpType();
}
- test_IndexExpression() async {
- addTestSource('class C {foo(){var f; {var x;} f[^]}}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_IndexExpression2() async {
- addTestSource('class C {foo(){var f; {var x;} f[T^]}}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
test_InstanceCreationExpression() async {
// SimpleIdentifier TypeName ConstructorName InstanceCreationExpression
addTestSource('class C {foo(){var f; {var x;} new ^}}');
await assertOpType(constructors: true);
}
- test_InstanceCreationExpression_keyword() async {
- // InstanceCreationExpression ExpressionStatement Block
- addTestSource('class C {foo(){var f; {var x;} new^ }}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true);
- }
-
- test_InstanceCreationExpression_keyword2() async {
- // InstanceCreationExpression ExpressionStatement Block
- addTestSource('class C {foo(){var f; {var x;} new^ C();}}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true);
- }
-
test_InstanceCreationExpression_trailingStmt() async {
// SimpleIdentifier TypeName ConstructorName InstanceCreationExpression
addTestSource('class C {foo(){var f; {var x;} new ^ int x = 7;}}');
@@ -1335,96 +1662,24 @@
await assertOpType();
}
- test_InterpolationExpression() async {
- // SimpleIdentifier InterpolationExpression StringInterpolation
- addTestSource('main() {String name; print("hello \$^");}');
- await assertOpType(constructors: previewDart2, returnValue: true);
- }
-
- test_InterpolationExpression_block() async {
- // SimpleIdentifier InterpolationExpression StringInterpolation
- addTestSource('main() {String name; print("hello \${n^}");}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_InterpolationExpression_prefix_selector() async {
- // SimpleIdentifier PrefixedIdentifier InterpolationExpression
- addTestSource('main() {String name; print("hello \${name.^}");}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- prefixed: true);
- }
-
- test_InterpolationExpression_prefix_target() async {
- // SimpleIdentifier PrefixedIdentifier InterpolationExpression
- addTestSource('main() {String name; print("hello \${nam^e.length}");}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
test_IsExpression() async {
// SimpleIdentifier TypeName IsExpression IfStatement
addTestSource('main() {var x; if (x is ^) { }}');
await assertOpType(typeNames: true);
}
- test_IsExpression_target() async {
- // IfStatement Block BlockFunctionBody
- addTestSource('main(){var a; if (^ is A)}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
test_IsExpression_type_partial() async {
// SimpleIdentifier TypeName IsExpression IfStatement
addTestSource('main(){var a; if (a is Obj^)}');
await assertOpType(typeNames: true);
}
- test_Literal_list() async {
- // ']' ListLiteral ArgumentList MethodInvocation
- addTestSource('main() {var Some; print([^]);}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_Literal_list2() async {
- // SimpleIdentifier ListLiteral ArgumentList MethodInvocation
- addTestSource('main() {var Some; print([S^]);}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
test_Literal_string() async {
// SimpleStringLiteral ExpressionStatement Block
addTestSource('class A {a() {"hel^lo"}}');
await assertOpType();
}
- test_MapLiteralEntry() async {
- // MapLiteralEntry MapLiteral VariableDeclaration
- addTestSource('foo = {^');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_MapLiteralEntry1() async {
- // MapLiteralEntry MapLiteral VariableDeclaration
- addTestSource('foo = {T^');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_MapLiteralEntry2() async {
- // SimpleIdentifier MapLiteralEntry MapLiteral VariableDeclaration
- addTestSource('foo = {7:T^};');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
test_MethodDeclaration1() async {
// SimpleIdentifier MethodDeclaration ClassDeclaration
addTestSource('class Bar {const ^Fara();}');
@@ -1584,71 +1839,6 @@
await assertOpType(typeNames: true);
}
- test_MethodInvocation_no_semicolon() async {
- // MethodInvocation ExpressionStatement Block
- addTestSource('''
- class A implements I {
- // no semicolon between completion point and next statement
- set _s2(I x) {x.^ m(null);}
- }''');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true,
- prefixed: true);
- }
-
- test_PostfixExpression() async {
- // SimpleIdentifier PostfixExpression ForStatement
- addTestSource('int x = 0; main() {ax+^+;}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_PrefixedIdentifier_class_const() async {
- // SimpleIdentifier PrefixedIdentifier ExpressionStatement Block
- addTestSource('main() {A.^}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true,
- prefixed: true);
- }
-
- test_PrefixedIdentifier_class_imported() async {
- // SimpleIdentifier PrefixedIdentifier ExpressionStatement
- addTestSource('main() {A a; a.^}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true,
- prefixed: true);
- }
-
- test_PrefixedIdentifier_prefix() async {
- // SimpleIdentifier PrefixedIdentifier ExpressionStatement
- addTestSource('class X {foo(){A^.bar}}');
- await assertOpType(
- constructors: previewDart2,
- typeNames: true,
- returnValue: true,
- voidReturn: true);
- }
-
- test_PropertyAccess_expression() async {
- // SimpleIdentifier MethodInvocation PropertyAccess ExpressionStatement
- addTestSource('class A {a() {"hello".to^String().length}}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true,
- prefixed: true);
- }
-
test_PropertyAccess_noTarget() async {
// SimpleIdentifier PropertyAccess ExpressionStatement
addTestSource('main() {.^}');
@@ -1667,24 +1857,6 @@
await assertOpType();
}
- test_PropertyAccess_selector() async {
- // SimpleIdentifier PropertyAccess ExpressionStatement Block
- addTestSource('class A {a() {"hello".length.^}}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true,
- prefixed: true);
- }
-
- test_ReturnStatement() async {
- // ReturnStatement Block
- addTestSource('f() { var vvv = 42; return ^ }');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
test_SimpleFormalParameter_closure() async {
// SimpleIdentifier SimpleFormalParameter FormalParameterList
addTestSource('mth() { PNGS.sort((String a, Str^) => a.compareTo(b)); }');
@@ -1745,120 +1917,18 @@
await assertOpType();
}
- test_SwitchCase_between() async {
- // SwitchCase SwitchStatement Block
- addTestSource('main() {switch(k) {case 1: ^ case 2: return}}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true);
- }
-
- test_SwitchCase_expression1() async {
- // SimpleIdentifier SwitchCase SwitchStatement
- addTestSource('''m() {switch (x) {case ^D: return;}}''');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_SwitchCase_expression2() async {
- // SimpleIdentifier SwitchCase SwitchStatement
- addTestSource('''m() {switch (x) {case ^}}''');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
test_SwitchDefault_before() async {
// SwitchDefault SwitchStatement Block
addTestSource('main() {switch(k) { ^ default: return;}}');
await assertOpType();
}
- test_SwitchDefault_between() async {
- // SwitchDefault SwitchStatement Block
- addTestSource('main() {switch(k) {case 1: ^ default: return;}}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true);
- }
-
test_SwitchStatement_body_empty() async {
// Token('}') SwitchStatement Block
addTestSource('main() {switch(k) {^}}');
await assertOpType();
}
- test_SwitchStatement_body_end() async {
- // Token('}') SwitchStatement Block
- addTestSource('main() {switch(k) {case 1:^}}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true);
- }
-
- test_SwitchStatement_body_end2() async {
- addTestSource('main() {switch(k) {case 1:as^}}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true);
- }
-
- test_SwitchStatement_expression1() async {
- // SimpleIdentifier SwitchStatement Block
- addTestSource('main() {switch(^k) {case 1:{}}}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_SwitchStatement_expression2() async {
- // SimpleIdentifier SwitchStatement Block
- addTestSource('main() {switch(k^) {case 1:{}}}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_SwitchStatement_expression_empty() async {
- // SimpleIdentifier SwitchStatement Block
- addTestSource('main() {switch(^) {case 1:{}}}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_ThisExpression_block() async {
- // MethodInvocation ExpressionStatement Block
- addTestSource('''
- class A implements I {
- // no semicolon between completion point and next statement
- set s1(I x) {} set _s2(I x) {this.^ m(null);}
- }''');
- // TODO(brianwilkerson) We should not be adding constructors here.
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- voidReturn: true,
- prefixed: true);
- }
-
- test_ThisExpression_constructor() async {
- // SimpleIdentifier PropertyAccess ExpressionStatement
- addTestSource('''
- class A implements I {
- A() {this.^}
- }''');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- voidReturn: true,
- prefixed: true);
- }
-
test_ThisExpression_constructor_param() async {
// SimpleIdentifier FieldFormalParameter FormalParameterList
addTestSource('''
@@ -1895,13 +1965,6 @@
await assertOpType(typeNames: true);
}
- test_ThrowExpression() async {
- // SimpleIdentifier ThrowExpression ExpressionStatement
- addTestSource('main() {throw ^;}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
test_TopLevelVariableDeclaration_typed_name() async {
// SimpleIdentifier VariableDeclaration VariableDeclarationList
// TopLevelVariableDeclaration
@@ -1977,43 +2040,4 @@
addTestSource('main() {final ^}');
await assertOpType(typeNames: true);
}
-
- test_VariableDeclarationStatement_afterSemicolon() async {
- // VariableDeclarationStatement Block BlockFunctionBody
- addTestSource('class A {var a; x() {var b;^}}');
- await assertOpType(
- constructors: previewDart2,
- returnValue: true,
- typeNames: true,
- voidReturn: true);
- }
-
- test_VariableDeclarationStatement_RHS() async {
- // SimpleIdentifier VariableDeclaration VariableDeclarationList
- // VariableDeclarationStatement
- addTestSource('class C {bar(){var f; {var x;} var e = ^}}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_VariableDeclarationStatement_RHS_missing_semicolon() async {
- // VariableDeclaration VariableDeclarationList
- // VariableDeclarationStatement
- addTestSource('class C {bar(){var f; {var x;} var e = ^ var g}}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_WhileStatement() async {
- // SimpleIdentifier WhileStatement Block
- addTestSource('mth() { while (b^) {} }}');
- await assertOpType(
- constructors: previewDart2, returnValue: true, typeNames: true);
- }
-
- test_WithClause() async {
- // WithClause ClassDeclaration
- addTestSource('class x extends Object with ^\n{}');
- await assertOpType(typeNames: true);
- }
}
diff --git a/pkg/analyzer_plugin/test/support/abstract_context.dart b/pkg/analyzer_plugin/test/support/abstract_context.dart
index 844b487..d5fc4db 100644
--- a/pkg/analyzer_plugin/test/support/abstract_context.dart
+++ b/pkg/analyzer_plugin/test/support/abstract_context.dart
@@ -62,7 +62,12 @@
/**
* Return `true` if strong mode should be enabled for this test.
*/
- bool get enableStrongMode => false;
+ bool get enableStrongMode => true;
+
+ /**
+ * Return `true` if previewDart2 should be enabled for this test.
+ */
+ bool get enablePreviewDart2 => true;
bool get previewDart2 => driver.analysisOptions.previewDart2;
@@ -132,7 +137,8 @@
PerformanceLog log = new PerformanceLog(_logBuffer);
AnalysisDriverScheduler scheduler = new AnalysisDriverScheduler(log);
AnalysisOptionsImpl options = new AnalysisOptionsImpl()
- ..strongMode = enableStrongMode;
+ ..strongMode = enableStrongMode
+ ..previewDart2 = enablePreviewDart2;
_driver = new AnalysisDriver(
scheduler,
log,
diff --git a/pkg/analyzer_plugin/test/utilities/completion/completion_target_test.dart b/pkg/analyzer_plugin/test/utilities/completion/completion_target_test.dart
new file mode 100644
index 0000000..3894c12
--- /dev/null
+++ b/pkg/analyzer_plugin/test/utilities/completion/completion_target_test.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2018, 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:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/standard_ast_factory.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/token.dart'
+ show SyntheticBeginToken, SyntheticToken;
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer_plugin/src/utilities/completion/completion_target.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(CompletionTargetTest);
+ });
+}
+
+@reflectiveTest
+class CompletionTargetTest {
+ test_danglingExpressionCompletionIsValid() {
+ // Test that users can parse dangling expressions of dart and autocomplete
+ // them without crash/with the correct offset information.
+ final snippet = wrapForCompliance(parseDanglingDart('identifier'));
+ final completionTarget =
+ // ignore: deprecated_member_use
+ new CompletionTarget.forOffset(null, 1, entryPoint: snippet);
+ expect(completionTarget.offset, 1);
+ final replacementRange = completionTarget.computeReplacementRange(1);
+ expect(replacementRange.offset, 0);
+ expect(replacementRange.length, 'identifier'.length);
+ }
+
+ /// Parse a dangling expression (no parent node). The angular plugin, for
+ /// instance, does this.
+ Expression parseDanglingDart(String code) {
+ final reader = new CharSequenceReader(code);
+ final scanner = new Scanner(null, reader, null);
+ return new Parser(null, null).parseExpression(scanner.tokenize());
+ }
+
+ Expression wrapForCompliance(Expression expression) {
+ // TODO(mfairhurst) This should be performed for clients or the need should
+ // be dropped. It's a fairly valid invariant that all autocompletion target
+ // expressions should have parents, and one we can enforce via synthetics.
+ // But clients should not be doing this ideally.
+ return astFactory.parenthesizedExpression(
+ new SyntheticBeginToken(TokenType.OPEN_PAREN, expression.offset)
+ ..next = expression.beginToken,
+ expression,
+ new SyntheticToken(TokenType.CLOSE_PAREN, expression.end));
+ }
+}
diff --git a/pkg/analyzer_plugin/test/utilities/completion/test_all.dart b/pkg/analyzer_plugin/test/utilities/completion/test_all.dart
index 5f06b3a..cdc642d 100644
--- a/pkg/analyzer_plugin/test/utilities/completion/test_all.dart
+++ b/pkg/analyzer_plugin/test/utilities/completion/test_all.dart
@@ -7,10 +7,12 @@
import 'inherited_reference_contributor_test.dart'
as inherited_reference_contributor_test;
import 'type_member_contributor_test.dart' as type_member_contributor_test;
+import 'completion_target_test.dart' as completion_target_test;
main() {
defineReflectiveSuite(() {
inherited_reference_contributor_test.main();
type_member_contributor_test.main();
+ completion_target_test.main();
}, name: 'subscriptions');
}
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 199973f..152ac6c 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -67,6 +67,9 @@
static const String verbose = '--verbose';
static const String version = '--version';
+ /// Flag for a combination of flags for 'production' mode.
+ static const String benchmarkingProduction = '--benchmarking-production';
+
static const String conditionalDirectives = '--conditional-directives';
// The syntax-only level of support for generic methods is included in the
@@ -92,11 +95,19 @@
// https://gist.github.com/eernstg/4353d7b4f669745bed3a5423e04a453c.
static const String genericMethodSyntax = '--generic-method-syntax';
- // Starts `async` functions synchronously.
+ // Deprecated. This flag is no longer in use for dart2js, but we are keeping
+ // it around for a while longer until all other tools deprecate the same flag.
//
- // This is the Dart 2.0 behavior. This flag is only used during the migration.
+ // It was used to start `async` functions synchronously, but now dart2js
+ // switched on this behavior by default.
+ // TODO(sigmund): delete once this is on by default on all of our tools.
static const String syncAsync = '--sync-async';
+ // Starts `async` functions asynchronously.
+ //
+ // This is the old Dart 1.0 behavior. Only used during the migration.
+ static const String noSyncAsync = '--no-sync-async';
+
// Initializing-formal access is enabled by default and cannot be disabled.
// For backward compatibility the option is still accepted, but it is ignored.
static const String initializingFormalAccess = '--initializing-formal-access';
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index 04c300e..3dc07e6 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -879,6 +879,11 @@
ClassEntity get jsInvocationMirrorClass =>
_jsInvocationMirrorClass ??= _findHelperClass('JSInvocationMirror');
+ MemberEntity _invocationTypeArgumentGetter;
+ MemberEntity get invocationTypeArgumentGetter =>
+ _invocationTypeArgumentGetter ??=
+ _findClassMember(jsInvocationMirrorClass, 'typeArguments');
+
/// Interface used to determine if an object has the JavaScript
/// indexing behavior. The interface is only visible to specific libraries.
ClassEntity _jsIndexingBehaviorInterface;
diff --git a/pkg/compiler/lib/src/constants/evaluation.dart b/pkg/compiler/lib/src/constants/evaluation.dart
index 92dca21..b647d48 100644
--- a/pkg/compiler/lib/src/constants/evaluation.dart
+++ b/pkg/compiler/lib/src/constants/evaluation.dart
@@ -42,6 +42,9 @@
DartType substByContext(
covariant DartType base, covariant InterfaceType target);
+ /// Returns [type] in the context of the [enclosingConstructedType].
+ DartType getTypeInContext(DartType type);
+
void reportWarning(
ConstantExpression expression, MessageKind kind, Map arguments);
@@ -127,6 +130,47 @@
reporter.reportWarningMessage(_spannable, kind, arguments);
}
}
+
+ @override
+ DartType getTypeInContext(DartType type) {
+ // Running example for comments:
+ //
+ // class A<T> {
+ // final T t;
+ // const A(dynamic t) : this.t = t; // implicitly `t as A.T`
+ // }
+ // class B<S> extends A<S> {
+ // const B(dynamic s) : super(s);
+ // }
+ // main() => const B<num>(0);
+ //
+ // We visit `t as A.T` while evaluating `const B<num>(0)`.
+
+ // The `as` type is `A.T`.
+ DartType typeInContext = type;
+
+ // The enclosing type is `B<num>`.
+ DartType enclosingType = enclosingConstructedType;
+ if (enclosingType != null) {
+ ClassEntity contextClass;
+ type.forEachTypeVariable((TypeVariableType type) {
+ if (type.element.typeDeclaration is ClassEntity) {
+ // We find `A` from `A.T`. Since we don't have nested classes, class
+ // based type variables can only come from the same class.
+ contextClass = type.element.typeDeclaration;
+ }
+ });
+ if (contextClass != null) {
+ // The enclosing type `B<num>` as an instance of `A` is `A<num>`.
+ enclosingType = types.asInstanceOf(enclosingType, contextClass);
+ }
+ // `A.T` in the context of the enclosing type `A<num>` is `num`.
+ typeInContext = enclosingType != null
+ ? substByContext(typeInContext, enclosingType)
+ : typeInContext;
+ }
+ return typeInContext;
+ }
}
/// The normalized arguments passed to a const constructor computed from the
diff --git a/pkg/compiler/lib/src/constants/expressions.dart b/pkg/compiler/lib/src/constants/expressions.dart
index b86d8e7..b590b23 100644
--- a/pkg/compiler/lib/src/constants/expressions.dart
+++ b/pkg/compiler/lib/src/constants/expressions.dart
@@ -11,6 +11,7 @@
import '../elements/operators.dart';
import '../elements/types.dart';
import '../universe/call_structure.dart' show CallStructure;
+import '../util/util.dart';
import 'constructors.dart';
import 'evaluation.dart';
import 'values.dart';
@@ -45,6 +46,7 @@
POSITIONAL_REFERENCE,
NAMED_REFERENCE,
ASSERT,
+ INSTANTIATION,
}
/// An expression that is a compile-time constant.
@@ -868,30 +870,9 @@
DartType expressionType =
expressionValue.getType(environment.commonElements);
- // The `as` type is `A.T`.
- DartType typeInContext = type;
+ // The `as` type `A.T` in the context of `B<num>` is `num`.
+ DartType typeInContext = environment.getTypeInContext(type);
- // The enclosing type is `B<num>`.
- DartType enclosingType = environment.enclosingConstructedType;
- if (enclosingType != null) {
- ClassEntity contextClass;
- type.forEachTypeVariable((TypeVariableType type) {
- if (type.element.typeDeclaration is ClassEntity) {
- // We find `A` from `A.T`. Since we don't have nested classes, class
- // based type variables can only come from the same class.
- contextClass = type.element.typeDeclaration;
- }
- });
- if (contextClass != null) {
- // The enclosing type `B<num>` as an instance of `A` is `A<num>`.
- enclosingType =
- environment.types.asInstanceOf(enclosingType, contextClass);
- }
- // `A.T` in the context of the enclosing type `A<num>` is `num`.
- typeInContext = enclosingType != null
- ? environment.substByContext(typeInContext, enclosingType)
- : typeInContext;
- }
// Check that the expression type, `int`, is a subtype of the type in
// context, `num`.
if (!constantSystem.isSubtype(
@@ -2154,6 +2135,57 @@
}
}
+class InstantiationConstantExpression extends ConstantExpression {
+ final List<DartType> typeArguments;
+ final ConstantExpression expression;
+
+ InstantiationConstantExpression(this.typeArguments, this.expression);
+
+ ConstantExpressionKind get kind => ConstantExpressionKind.INSTANTIATION;
+
+ @override
+ void _createStructuredText(StringBuffer sb) {
+ sb.write('Instantiation(typeArguments=$typeArguments,expression=');
+ expression._createStructuredText(sb);
+ sb.write(')');
+ }
+
+ @override
+ ConstantValue evaluate(
+ EvaluationEnvironment environment, ConstantSystem constantSystem) {
+ List<DartType> typeArgumentsInContext =
+ typeArguments.map(environment.getTypeInContext).toList();
+ return new InstantiationConstantValue(typeArgumentsInContext,
+ expression.evaluate(environment, constantSystem));
+ }
+
+ @override
+ int _computeHashCode() {
+ return Hashing.objectHash(expression, Hashing.listHash(typeArguments));
+ }
+
+ ConstantExpression apply(NormalizedArguments arguments) {
+ return new InstantiationConstantExpression(
+ typeArguments, expression.apply(arguments));
+ }
+
+ @override
+ bool _equals(InstantiationConstantExpression other) {
+ return equalElements(typeArguments, other.typeArguments) &&
+ expression == other.expression;
+ }
+
+ @override
+ accept(ConstantExpressionVisitor visitor, [context]) {
+ return visitor.visitInstantiation(this, context);
+ }
+
+ @override
+ bool get isPotential {
+ return expression.isPotential;
+ }
+}
+
abstract class ConstantExpressionVisitor<R, A> {
const ConstantExpressionVisitor();
@@ -2189,6 +2221,7 @@
StringFromEnvironmentConstantExpression exp, A context);
R visitDeferred(DeferredConstantExpression exp, A context);
R visitAssert(AssertConstantExpression exp, A context);
+ R visitInstantiation(InstantiationConstantExpression exp, A context);
R visitPositional(PositionalArgumentReference exp, A context);
R visitNamed(NamedArgumentReference exp, A context);
@@ -2480,5 +2513,14 @@
sb.write(')');
}
+ @override
+ void visitInstantiation(InstantiationConstantExpression exp, [_]) {
+ sb.write('<');
+ sb.write(exp.typeArguments.join(', '));
+ sb.write('>(');
+ visit(exp.expression);
+ sb.write(')');
+ }
+
String toString() => sb.toString();
}
diff --git a/pkg/compiler/lib/src/constants/values.dart b/pkg/compiler/lib/src/constants/values.dart
index 9fd6a9b..abf5d5a 100644
--- a/pkg/compiler/lib/src/constants/values.dart
+++ b/pkg/compiler/lib/src/constants/values.dart
@@ -9,7 +9,7 @@
import '../elements/entities.dart';
import '../elements/types.dart';
import '../deferred_load.dart' show OutputUnit;
-import '../util/util.dart' show Hashing;
+import '../util/util.dart';
enum ConstantValueKind {
FUNCTION,
@@ -50,6 +50,8 @@
R visitDeferredGlobal(
covariant DeferredGlobalConstantValue constant, covariant A arg);
R visitNonConstant(covariant NonConstantValue constant, covariant A arg);
+ R visitInstantiation(
+ covariant InstantiationConstantValue constant, covariant A arg);
}
abstract class ConstantValue {
@@ -131,7 +133,7 @@
List<ConstantValue> getDependencies() => const <ConstantValue>[];
- DartType getType(CommonElements types) => type;
+ FunctionType getType(CommonElements types) => type;
int get hashCode => (17 * element.hashCode) & 0x7fffffff;
@@ -775,7 +777,7 @@
import == other.import;
}
- get hashCode => (referenced.hashCode * 17 + import.hashCode) & 0x3fffffff;
+ int get hashCode => (referenced.hashCode * 17 + import.hashCode) & 0x3fffffff;
List<ConstantValue> getDependencies() => <ConstantValue>[referenced];
@@ -792,6 +794,45 @@
}
}
+class InstantiationConstantValue extends ConstantValue {
+ final List<DartType> typeArguments;
+ final FunctionConstantValue function;
+
+ InstantiationConstantValue(this.typeArguments, this.function);
+
+ bool operator ==(other) {
+ if (identical(this, other)) return true;
+ return other is InstantiationConstantValue &&
+ function == other.function &&
+ equalElements(typeArguments, other.typeArguments);
+ }
+
+ @override
+ int get hashCode {
+ return Hashing.objectHash(function, Hashing.listHash(typeArguments));
+ }
+
+ List<ConstantValue> getDependencies() => <ConstantValue>[function];
+
+ accept(ConstantValueVisitor visitor, arg) =>
+ visitor.visitInstantiation(this, arg);
+
+ DartType getType(CommonElements types) {
+ FunctionType type = function.getType(types);
+ return type.instantiate(typeArguments);
+ }
+
+ ConstantValueKind get kind => ConstantValueKind.DEFERRED;
+
+ String toDartText() =>
+ '<${typeArguments.join(', ')}>(${function.toDartText()})';
+
+ String toStructuredText() {
+ return 'InstantiationConstant($typeArguments,'
+ '${function.toStructuredText()})';
+ }
+}
+
/// A reference to a constant in another output unit.
///
/// Used for referring to deferred constants that appear as initializers of
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index b73c362..de73841 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -317,7 +317,8 @@
new OptionHandler(Flags.allowMockCompilation, ignoreOption),
new OptionHandler(Flags.fastStartup, passThrough),
new OptionHandler(Flags.genericMethodSyntax, ignoreOption),
- new OptionHandler(Flags.syncAsync, passThrough),
+ new OptionHandler(Flags.syncAsync, ignoreOption),
+ new OptionHandler(Flags.noSyncAsync, passThrough),
new OptionHandler(Flags.initializingFormalAccess, ignoreOption),
new OptionHandler(Flags.minify, passThrough),
new OptionHandler(Flags.preserveUris, ignoreOption),
@@ -361,6 +362,7 @@
new OptionHandler(Flags.strongMode, setStrongMode),
new OptionHandler(Flags.previewDart2, setStrongMode),
new OptionHandler(Flags.omitImplicitChecks, passThrough),
+ new OptionHandler(Flags.benchmarkingProduction, passThrough),
// TODO(floitsch): remove conditional directives flag.
// We don't provide the info-message yet, since we haven't publicly
diff --git a/pkg/compiler/lib/src/js_backend/constant_emitter.dart b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
index 064aa93..c218a40 100644
--- a/pkg/compiler/lib/src/js_backend/constant_emitter.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
@@ -333,6 +333,14 @@
return instantiation;
}
+ @override
+ jsAst.Expression visitInstantiation(InstantiationConstantValue constant,
+ [_]) {
+ // TODO(sigmund, sra): add a runtime representation for constant
+ // instantiations. See issue 32774.
+ return constantReferenceGenerator(constant.function);
+ }
+
String stripComments(String rawJavaScript) {
return rawJavaScript.replaceAll(COMMENT_RE, '');
}
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 5a6a574c..00393c0 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -1880,6 +1880,11 @@
}
@override
+ void visitInstantiation(InstantiationConstantValue constant, [_]) {
+ _visit(constant.function);
+ }
+
+ @override
void visitNull(NullConstantValue constant, [_]) {
add('null');
}
@@ -2081,6 +2086,11 @@
}
@override
+ int visitInstantiation(InstantiationConstantValue constant, [_]) {
+ return _visit(constant.function);
+ }
+
+ @override
int visitInt(IntConstantValue constant, [_]) {
return _hashInt(constant.intValue);
}
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index 9c3dd7b..cb5a5f1 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -890,14 +890,19 @@
if (function is FunctionEntity) {
Name instanceName;
bool isCallTarget;
+ bool isNoSuchMethod;
if (function.isInstanceMember) {
isCallTarget = worldBuilder.closurizedMembers.contains(function);
instanceName = function.memberName;
+ isNoSuchMethod = instanceName.text == Identifiers.noSuchMethod_;
} else {
isCallTarget = worldBuilder.closurizedStatics.contains(function);
+ isNoSuchMethod = false;
}
node = new MethodNode(function, function.parameterStructure,
- isCallTarget: isCallTarget, instanceName: instanceName);
+ isCallTarget: isCallTarget,
+ instanceName: instanceName,
+ isNoSuchMethod: isNoSuchMethod);
} else {
ParameterStructure parameterStructure = new ParameterStructure.fromType(
elementEnvironment.getLocalFunctionType(function));
@@ -1019,6 +1024,7 @@
genericInstanceMethods.forEach(processEntity);
worldBuilder.genericLocalFunctions.forEach(processEntity);
worldBuilder.closurizedStatics.forEach(processEntity);
+ worldBuilder.userNoSuchMethods.forEach(processEntity);
});
}
@@ -1294,13 +1300,15 @@
final ParameterStructure parameterStructure;
final bool isCallTarget;
final Name instanceName;
+ final bool isNoSuchMethod;
MethodNode(this.function, this.parameterStructure,
- {this.isCallTarget, this.instanceName});
+ {this.isCallTarget, this.instanceName, this.isNoSuchMethod: false});
Entity get entity => function;
bool selectorApplies(Selector selector) {
+ if (isNoSuchMethod) return true;
return (isCallTarget && selector.isClosureCall ||
instanceName == selector.memberName) &&
selector.callStructure.signatureApplies(parameterStructure);
@@ -1517,6 +1525,15 @@
localFunctionsUsingTypeVariableLiterals
.forEach(potentiallyNeedTypeArguments);
+ if (resolutionWorldBuilder.isMemberUsed(
+ closedWorld.commonElements.invocationTypeArgumentGetter)) {
+ // If `Invocation.typeArguments` is live, mark all user-defined
+ // implementations of `noSuchMethod` as needing type arguments.
+ for (MemberEntity member in resolutionWorldBuilder.userNoSuchMethods) {
+ potentiallyNeedTypeArguments(member);
+ }
+ }
+
Set<Selector> selectorsNeedingTypeArguments = new Set<Selector>();
typeVariableTests
.forEachAppliedSelector((Selector selector, Set<Entity> targets) {
diff --git a/pkg/compiler/lib/src/js_emitter/constant_ordering.dart b/pkg/compiler/lib/src/js_emitter/constant_ordering.dart
index a1ee6ab..fcd705d 100644
--- a/pkg/compiler/lib/src/js_emitter/constant_ordering.dart
+++ b/pkg/compiler/lib/src/js_emitter/constant_ordering.dart
@@ -240,6 +240,13 @@
if (r != 0) return r;
return a.unit.compareTo(b.unit);
}
+
+ int visitInstantiation(
+ InstantiationConstantValue a, InstantiationConstantValue b) {
+ int r = compareValues(a.function, b.function);
+ if (r != 0) return r;
+ return compareLists(compareDartTypes, a.typeArguments, b.typeArguments);
+ }
}
class _KindVisitor implements ConstantValueVisitor<int, Null> {
@@ -259,7 +266,8 @@
static const int SYNTHETIC = 12;
static const int DEFERRED = 13;
static const int DEFERRED_GLOBAL = 14;
- static const int NONCONSTANT = 13;
+ static const int NONCONSTANT = 15;
+ static const int INSTANTIATION = 16;
static int kind(ConstantValue constant) =>
constant.accept(const _KindVisitor(), null);
@@ -279,6 +287,7 @@
int visitSynthetic(SyntheticConstantValue a, _) => SYNTHETIC;
int visitDeferred(DeferredConstantValue a, _) => DEFERRED;
int visitDeferredGlobal(DeferredGlobalConstantValue a, _) => DEFERRED_GLOBAL;
+ int visitInstantiation(InstantiationConstantValue a, _) => INSTANTIATION;
}
/// Visitor for distinguishing types by kind.
diff --git a/pkg/compiler/lib/src/js_model/js_strategy.dart b/pkg/compiler/lib/src/js_model/js_strategy.dart
index 9572c32..11fa8ee 100644
--- a/pkg/compiler/lib/src/js_model/js_strategy.dart
+++ b/pkg/compiler/lib/src/js_model/js_strategy.dart
@@ -699,6 +699,13 @@
return new DeferredGlobalConstantValue(referenced, constant.unit);
}
+ ConstantValue visitInstantiation(InstantiationConstantValue constant, _) {
+ ConstantValue function = constant.function.accept(this, null);
+ List<DartType> typeArguments =
+ typeConverter.convertTypes(constant.typeArguments);
+ return new InstantiationConstantValue(typeArguments, function);
+ }
+
List<ConstantValue> _handleValues(List<ConstantValue> values) {
List<ConstantValue> result;
for (int i = 0; i < values.length; i++) {
@@ -722,6 +729,8 @@
DartType convert(DartType type) => type.accept(this, null);
+ List<DartType> convertTypes(List<DartType> types) => _visitList(types);
+
DartType visitVoidType(VoidType type, _) => type;
DartType visitDynamicType(DynamicType type, _) => type;
diff --git a/pkg/compiler/lib/src/kernel/element_map_mixins.dart b/pkg/compiler/lib/src/kernel/element_map_mixins.dart
index 8d08535..1a4ca53 100644
--- a/pkg/compiler/lib/src/kernel/element_map_mixins.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_mixins.dart
@@ -699,9 +699,9 @@
@override
ConstantExpression visitInstantiation(ir.Instantiation node) {
- // TODO(sigmund, sra): add a constant representation for instantiations.
- // See issue 32774.
- return visit(node.expression);
+ return new InstantiationConstantExpression(
+ node.typeArguments.map(elementMap.getDartType).toList(),
+ visit(node.expression));
}
@override
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index f72edf3..01e4689 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -90,6 +90,9 @@
/// [analyzeOnly].
bool analyzeSignaturesOnly = false;
+ /// Sets a combination of flags for benchmarking 'production' mode.
+ bool benchmarkingProduction = false;
+
/// ID associated with this sdk build.
String buildId = _UNDETERMINED_BUILD_ID;
@@ -290,6 +293,8 @@
..analyzeMain = _hasOption(options, Flags.analyzeMain)
..analyzeOnly = _hasOption(options, Flags.analyzeOnly)
..analyzeSignaturesOnly = _hasOption(options, Flags.analyzeSignaturesOnly)
+ ..benchmarkingProduction =
+ _hasOption(options, Flags.benchmarkingProduction)
..buildId =
_extractStringOption(options, '--build-id=', _UNDETERMINED_BUILD_ID)
..compileForServer = _resolveCompileForServerFromOptions(options)
@@ -343,7 +348,7 @@
..useMultiSourceInfo = _hasOption(options, Flags.useMultiSourceInfo)
..useNewSourceInfo = _hasOption(options, Flags.useNewSourceInfo)
..useStartupEmitter = _hasOption(options, Flags.fastStartup)
- ..startAsyncSynchronously = _hasOption(options, Flags.syncAsync)
+ ..startAsyncSynchronously = !_hasOption(options, Flags.noSyncAsync)
..verbose = _hasOption(options, Flags.verbose);
}
@@ -371,6 +376,15 @@
void deriveOptions() {
if (analyzeSignaturesOnly || analyzeAll) analyzeOnly = true;
+ if (benchmarkingProduction) {
+ useStartupEmitter = true;
+ trustPrimitives = true;
+ if (strongMode) {
+ omitImplicitChecks = true;
+ } else {
+ trustTypeAnnotations = true;
+ }
+ }
if (useKernel) generateCodeWithCompileTimeErrors = false;
if (platformConfigUri == null) {
platformConfigUri = _resolvePlatformConfig(libraryRoot, null, const []);
diff --git a/pkg/compiler/lib/src/types/constants.dart b/pkg/compiler/lib/src/types/constants.dart
index 0bd4b32..5d2b2af 100644
--- a/pkg/compiler/lib/src/types/constants.dart
+++ b/pkg/compiler/lib/src/types/constants.dart
@@ -84,6 +84,12 @@
}
@override
+ TypeMask visitInstantiation(
+ InstantiationConstantValue constant, ClosedWorld closedWorld) {
+ return closedWorld.commonMasks.functionType;
+ }
+
+ @override
TypeMask visitInt(IntConstantValue constant, ClosedWorld closedWorld) {
if (constant.isUInt31()) return closedWorld.commonMasks.uint31Type;
if (constant.isUInt32()) return closedWorld.commonMasks.uint32Type;
diff --git a/pkg/compiler/lib/src/universe/codegen_world_builder.dart b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
index d679a67..b6b3485 100644
--- a/pkg/compiler/lib/src/universe/codegen_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
@@ -600,6 +600,24 @@
_instanceMemberUsage.forEach(processMemberUse);
return functions;
}
+
+ @override
+ Iterable<FunctionEntity> get userNoSuchMethods {
+ List<FunctionEntity> functions = <FunctionEntity>[];
+
+ void processMemberUse(MemberEntity member, _MemberUsage memberUsage) {
+ if (member.isInstanceMember &&
+ member is FunctionEntity &&
+ memberUsage.hasUse &&
+ member.name == Identifiers.noSuchMethod_ &&
+ !_world.commonElements.isDefaultNoSuchMethodImplementation(member)) {
+ functions.add(member);
+ }
+ }
+
+ _instanceMemberUsage.forEach(processMemberUse);
+ return functions;
+ }
}
class ElementCodegenWorldBuilderImpl extends CodegenWorldBuilderImpl {
diff --git a/pkg/compiler/lib/src/universe/resolution_world_builder.dart b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
index fc3502f..2849612 100644
--- a/pkg/compiler/lib/src/universe/resolution_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
@@ -434,6 +434,19 @@
return functions;
}
+ Iterable<FunctionEntity> get userNoSuchMethods {
+ List<FunctionEntity> functions = <FunctionEntity>[];
+ for (MemberEntity member in processedMembers) {
+ if (member.isInstanceMember &&
+ member.isFunction &&
+ member.name == Identifiers.noSuchMethod_ &&
+ !_commonElements.isDefaultNoSuchMethodImplementation(member)) {
+ functions.add(member);
+ }
+ }
+ return functions;
+ }
+
Iterable<MemberEntity> get processedMembers => _processedMembers;
ClosedWorld get closedWorldForTesting {
diff --git a/pkg/compiler/lib/src/universe/world_builder.dart b/pkg/compiler/lib/src/universe/world_builder.dart
index 031baf2..9b67772 100644
--- a/pkg/compiler/lib/src/universe/world_builder.dart
+++ b/pkg/compiler/lib/src/universe/world_builder.dart
@@ -293,6 +293,9 @@
/// Live generic local functions.
Iterable<Local> get genericLocalFunctions;
+ /// Live user-defined 'noSuchMethod' implementations.
+ Iterable<FunctionEntity> get userNoSuchMethods;
+
/// Type variables used as type literals.
Iterable<TypeVariableType> get typeVariableTypeLiterals;
diff --git a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
index 48eaedb..8fbce54 100644
--- a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
@@ -40,7 +40,6 @@
import '../compiler/js_utils.dart' as JS;
import '../compiler/module_builder.dart' show pathToJSIdentifier;
import '../compiler/shared_compiler.dart';
-import '../compiler/type_utilities.dart';
import '../js_ast/js_ast.dart' as JS;
import '../js_ast/js_ast.dart' show js;
import '../js_ast/source_map_printer.dart' show NodeEnd, NodeSpan, HoverComment;
@@ -56,6 +55,7 @@
import 'reify_coercions.dart' show CoercionReifier;
import 'side_effect_analysis.dart'
show ConstFieldVisitor, isStateless, isPotentiallyMutated;
+import 'type_utilities.dart';
/// The code generator for Dart Dev Compiler.
///
@@ -5800,7 +5800,7 @@
@override
JS.LiteralString visitSimpleStringLiteral(SimpleStringLiteral node) =>
- js.escapedString(node.value, node.isSingleQuoted ? "'" : '"');
+ js.escapedString(node.value, '"');
@override
JS.Expression visitAdjacentStrings(AdjacentStrings node) {
@@ -6075,9 +6075,7 @@
useExtension ??= _isSymbolizedMember(type, name);
// Rename members that conflict with standard JS members unless we are
// actually try to access those JS members via interop.
- var isExternal = element != null &&
- !(element is ExecutableElement && !element.isExternal);
- name = JS.memberNameForDartMember(name, isExternal);
+ name = JS.memberNameForDartMember(name, _isExternal(element));
if (useExtension) {
return _getExtensionSymbolInternal(name);
}
diff --git a/pkg/dev_compiler/lib/src/compiler/type_utilities.dart b/pkg/dev_compiler/lib/src/analyzer/type_utilities.dart
similarity index 99%
rename from pkg/dev_compiler/lib/src/compiler/type_utilities.dart
rename to pkg/dev_compiler/lib/src/analyzer/type_utilities.dart
index c33df46..075903f 100644
--- a/pkg/dev_compiler/lib/src/compiler/type_utilities.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/type_utilities.dart
@@ -8,9 +8,9 @@
import 'package:analyzer/dart/element/type.dart';
import '../analyzer/element_helpers.dart';
+import '../compiler/js_names.dart' as JS;
import '../js_ast/js_ast.dart' as JS;
import '../js_ast/js_ast.dart' show js;
-import 'js_names.dart' as JS;
Set<TypeParameterElement> freeTypeParameters(DartType t) {
var result = new Set<TypeParameterElement>();
diff --git a/pkg/dev_compiler/lib/src/js_ast/printer.dart b/pkg/dev_compiler/lib/src/js_ast/printer.dart
index f2f785c..ea97d34 100644
--- a/pkg/dev_compiler/lib/src/js_ast/printer.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/printer.dart
@@ -1190,7 +1190,8 @@
spaceOut();
out("{}");
} else {
- blockBody(fun.body, needsSeparation: false, needsNewline: false);
+ spaceOut();
+ blockOut(fun.body, false, false);
}
localNamer.leaveScope();
}
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index f19890f..92a045d 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -213,7 +213,7 @@
emitMetadata: argResults['emit-metadata'] as bool,
enableAsserts: argResults['enable-asserts'] as bool);
var jsModule =
- compiler.emitProgram(component, result.inputSummaries, summaryUris);
+ compiler.emitModule(component, result.inputSummaries, summaryUris);
var jsCode = jsProgramToCode(jsModule, moduleFormat,
buildSourceMap: argResults['source-map'] as bool,
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 7b95975..c39004a 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -255,12 +255,12 @@
Uri get currentLibraryUri => _currentLibrary.importUri;
- JS.Program emitProgram(
- Component p, List<Component> summaries, List<Uri> summaryUris) {
+ JS.Program emitModule(
+ Component buildUnit, List<Component> summaries, List<Uri> summaryUris) {
if (_moduleItems.isNotEmpty) {
throw new StateError('Can only call emitModule once.');
}
- _component = p;
+ _component = buildUnit;
for (var i = 0; i < summaries.length; i++) {
var summary = summaries[i];
@@ -272,7 +272,7 @@
}
}
- var libraries = p.libraries.where((l) => !l.isExternal);
+ var libraries = buildUnit.libraries.where((l) => !l.isExternal);
var ddcRuntime =
libraries.firstWhere(isSdkInternalRuntime, orElse: () => null);
if (ddcRuntime != null) {
@@ -291,6 +291,8 @@
// Initialize our library variables.
var items = <JS.ModuleItem>[];
var exports = <JS.NameSpecifier>[];
+ // TODO(jmesserly): this is a performance optimization for V8 to prevent it
+ // from treating our Dart library objects as JS Maps.
var root = new JS.Identifier('_root');
items.add(js.statement('const # = Object.create(null)', [root]));
@@ -353,7 +355,7 @@
_copyAndFlattenBlocks(items, _moduleItems);
// Build the module.
- return new JS.Program(items, name: p.root.name);
+ return new JS.Program(items, name: buildUnit.root.name);
}
/// Flattens blocks in [items] to a single list.
@@ -454,9 +456,9 @@
// TODO(jmesserly): we can merge these once we change signatures to be
// lazily associated at the tear-off point for top-level functions.
_emitLibraryProcedures(library);
+ _emitTopLevelFields(library.fields);
library.classes.forEach(_emitClass);
library.typedefs.forEach(_emitTypedef);
- _emitTopLevelFields(library.fields);
} else {
library.classes.forEach(_emitClass);
library.typedefs.forEach(_emitTypedef);
@@ -536,6 +538,9 @@
}
JS.Statement _emitClassDeclaration(Class c) {
+ // Mixins are unrolled in _defineClass.
+ if (c.isSyntheticMixinImplementation) return null;
+
// If this class is annotated with `@JS`, then there is nothing to emit.
if (findAnnotation(c, isPublicJSAnnotation) != null) return null;
@@ -650,6 +655,7 @@
JS.Expression emitDeferredType(DartType t) {
if (t is InterfaceType && t.typeArguments.isNotEmpty) {
+ _declareBeforeUse(t.classNode);
return _emitGenericClassType(t, t.typeArguments.map(emitDeferredType));
}
return _emitType(t);
@@ -696,22 +702,19 @@
return base;
}
- var mixins = <InterfaceType>[];
- var mixedInType = c.mixedInType;
- var superclass = c.superclass;
- var supertype = c.supertype.asInterfaceType;
- if (mixedInType != null) {
- mixins.add(mixedInType.asInterfaceType);
- for (;
- superclass.isSyntheticMixinImplementation;
- superclass = superclass.superclass) {
- mixins.add(hierarchy
- .getClassAsInstanceOf(c, superclass.mixedInClass)
- .asInterfaceType);
- }
- if (mixins.length > 1) mixins = mixins.reversed.toList();
- supertype = hierarchy.getClassAsInstanceOf(c, superclass).asInterfaceType;
- }
+ // Find the real (user declared) superclass and the list of mixins.
+ // We'll use this to unroll the intermediate classes.
+ //
+ // TODO(jmesserly): consider using Kernel's mixin unrolling.
+ var mixinClasses = <Class>[];
+ var superclass = getSuperclassAndMixins(c, mixinClasses);
+ var supertype = identical(c.superclass, superclass)
+ ? c.supertype.asInterfaceType
+ : hierarchy.getClassAsInstanceOf(c, superclass).asInterfaceType;
+ mixinClasses = mixinClasses.reversed.toList();
+ var mixins = mixinClasses
+ .map((m) => hierarchy.getClassAsInstanceOf(c, m).asInterfaceType)
+ .toList();
var hasUnnamedSuper = _hasUnnamedConstructor(superclass);
@@ -1088,7 +1091,9 @@
/// Emits static fields for a class, and initialize them eagerly if possible,
/// otherwise define them as lazy properties.
void _emitStaticFields(Class c, List<JS.Statement> body) {
- var fields = c.fields.where((f) => f.isStatic).toList();
+ var fields = c.fields
+ .where((f) => f.isStatic && getRedirectingFactories(f) == null)
+ .toList();
if (c.isEnum) {
// We know enum fields can be safely emitted as const fields, as long
// as the `values` field is emitted last.
@@ -1289,7 +1294,9 @@
if (emitMetadata) {
var constructors = <JS.Property>[];
- for (var ctor in c.constructors) {
+ var allConstructors = new List<Member>.from(c.constructors)
+ ..addAll(c.procedures.where((p) => p.isFactory));
+ for (var ctor in allConstructors) {
var memberName = _constructorName(ctor.name.name);
var type = _emitAnnotatedFunctionType(
ctor.function.functionType.withoutTypeParameters, ctor);
@@ -1588,13 +1595,13 @@
}''', [runtimeModule, runtimeModule])));
}
+ Set<Member> redirectingFactories;
for (var m in c.fields) {
- if (_extensionTypes.isNativeClass(c)) {
+ if (m.isStatic) {
+ redirectingFactories ??= getRedirectingFactories(m)?.toSet();
+ } else if (_extensionTypes.isNativeClass(c)) {
jsMethods.addAll(_emitNativeFieldAccessors(m));
- continue;
- }
- if (m.isStatic) continue;
- if (virtualFields.containsKey(m)) {
+ } else if (virtualFields.containsKey(m)) {
jsMethods.addAll(_emitVirtualFieldAccessor(m));
}
}
@@ -1615,6 +1622,8 @@
// TODO(jmesserly): is there any other kind of forwarding stub?
jsMethods.addAll(_emitCovarianceCheckStub(m));
} else if (m.isFactory) {
+ // Skip redirecting factories (they've already been resolved).
+ if (redirectingFactories?.contains(m) ?? false) continue;
jsMethods.add(_emitFactoryConstructor(m));
} else if (m.isAccessor) {
jsMethods.add(_emitMethodDeclaration(m));
@@ -1718,8 +1727,11 @@
return [
new JS.Method(
name,
- js.fun('function(x) { return super.# = #._check(x); }',
- [name, _emitType(substituteType(superMember.setterType))]),
+ js.fun('function(x) { return super.# = #; }', [
+ name,
+ _emitImplicitCast(new JS.Identifier('x'),
+ substituteType(superMember.setterType))
+ ]),
isSetter: true),
new JS.Method(name, js.fun('function() { return super.#; }', [name]),
isGetter: true)
@@ -1745,8 +1757,8 @@
if (isCovariant(param) &&
!isCovariant(superMember.function.positionalParameters[i])) {
- var check = js.call('#._check(#)',
- [_emitType(superMethodType.positionalParameters[i]), jsParam]);
+ var check =
+ _emitImplicitCast(jsParam, superMethodType.positionalParameters[i]);
if (i >= function.requiredParameterCount) {
body.add(js.statement('if (# !== void 0) #;', [jsParam, check]));
} else {
@@ -1762,12 +1774,11 @@
var name = _propertyName(param.name);
var paramType = superMethodType.namedParameters
.firstWhere((n) => n.name == param.name);
- body.add(js.statement('if (# in #) #._check(#.#);', [
+ body.add(js.statement('if (# in #) #;', [
name,
namedArgumentTemp,
- _emitType(paramType.type),
- namedArgumentTemp,
- name
+ _emitImplicitCast(
+ new JS.PropertyAccess(namedArgumentTemp, name), paramType.type)
]));
}
}
@@ -1788,10 +1799,11 @@
JS.Method _emitFactoryConstructor(Procedure node) {
if (isUnsupportedFactoryConstructor(node)) return null;
+ var function = node.function;
return new JS.Method(
_constructorName(node.name.name),
- new JS.Fun(_emitFormalParameters(node.function),
- _emitFunctionBody(node.function)),
+ new JS.Fun(
+ _emitFormalParameters(function), _emitFunctionBody(function)),
isStatic: true)
..sourceInformation = _nodeEnd(node.fileEndOffset);
}
@@ -1884,9 +1896,7 @@
]);
returnType = _getTypeFromClass(returnType, member.enclosingClass, c);
- if (!types.isTop(returnType)) {
- fnBody = js.call('#._check(#)', [_emitType(returnType), fnBody]);
- }
+ fnBody = _emitImplicitCast(fnBody, returnType);
var fn = new JS.Fun(fnArgs, fnBody.toReturn().toBlock(),
typeParams: typeParams);
@@ -1943,15 +1953,15 @@
? [new JS.Super(), name]
: [new JS.This(), virtualField];
- String jsCode;
+ JS.Expression value = new JS.Identifier('value');
if (!field.isFinal && field.isGenericCovariantImpl) {
- args.add(_emitType(field.type));
- jsCode = 'function(value) { #[#] = #._check(value); }';
- } else {
- jsCode = 'function(value) { #[#] = value; }';
+ value = _emitImplicitCast(value, field.type);
}
+ args.add(value);
- result.add(new JS.Method(name, js.fun(jsCode, args), isSetter: true)
+ result.add(new JS.Method(
+ name, js.fun('function(value) { #[#] = #; }', args),
+ isSetter: true)
..sourceInformation = _nodeStart(field));
}
@@ -1968,7 +1978,7 @@
// Alternatively, perhaps it could be meta-programmed directly in
// dart.registerExtensions?
var jsMethods = <JS.Method>[];
- if (field.isStatic) return jsMethods;
+ assert(!field.isStatic);
var name = getAnnotationName(field, isJSName) ?? field.name.name;
// Generate getter
@@ -2110,9 +2120,7 @@
var init = field.initializer;
if (init == null ||
init is BasicLiteral ||
- init is StaticInvocation && isInlineJS(init.target) ||
- init is ConstructorInvocation &&
- isSdkInternalRuntime(init.target.enclosingLibrary)) {
+ init is StaticInvocation && isInlineJS(init.target)) {
_currentUri = field.fileUri;
_moduleItems.add(js.statement('# = #;', [
_emitTopLevelName(field),
@@ -2280,9 +2288,8 @@
}
useExtension ??= _isSymbolizedMember(type, name);
- // TODO(vsm): Do not rename members that conflict with standard JS members
- // if we are actually try to access those JS members via interop.
- name = JS.memberNameForDartMember(name);
+ name = JS.memberNameForDartMember(
+ name, member is Procedure && member.isExternal);
if (useExtension) {
return _getExtensionSymbolInternal(name);
}
@@ -2977,8 +2984,8 @@
initParameter(VariableDeclaration p, JS.Identifier jsParam) {
if (isCovariant(p)) {
- var castType = _emitType(p.type);
- body.add(js.statement('#._check(#);', [castType, jsParam]));
+ var castExpr = _emitImplicitCast(jsParam, p.type);
+ if (!identical(castExpr, jsParam)) body.add(castExpr.toStatement());
}
if (_annotatedNullCheck(p.annotations)) {
body.add(_nullParameterCheck(jsParam));
@@ -3057,7 +3064,7 @@
void _emitCovarianceBoundsCheck(
List<TypeParameter> typeFormals, List<JS.Statement> body) {
for (var t in typeFormals) {
- if (t.isGenericCovariantImpl) {
+ if (t.isGenericCovariantImpl && !types.isTop(t.bound)) {
body.add(runtimeStatement('checkTypeBound(#, #, #)', [
_emitType(new TypeParameterType(t)),
_emitType(t.bound),
@@ -3112,9 +3119,7 @@
if (node == null) return null;
if (node is Not) {
- // TODO(leafp): consider a peephole opt for identical
- // and == here.
- return js.call('!#', _visitTest(node.operand));
+ return visitNot(node);
}
if (node is LogicalExpression) {
JS.Expression shortCircuit(String code) {
@@ -3214,9 +3219,18 @@
}
@override
- visitBlock(Block node) =>
- new JS.Block(node.statements.map(_visitStatement).toList(),
- isScope: true);
+ visitBlock(Block node) {
+ // If this is the block body of a function, don't mark it as a separate
+ // scope, because the function is the scope. This avoids generating an
+ // unncessary nested block.
+ //
+ // NOTE: we do sometimes need to handle this because Dart and JS rules are
+ // slightly different (in Dart, there is a nested scope), but that's handled
+ // by _emitFunctionBody.
+ var isScope = !identical(node.parent, _currentFunction);
+ return new JS.Block(node.statements.map(_visitStatement).toList(),
+ isScope: isScope);
+ }
@override
visitEmptyStatement(EmptyStatement node) => new JS.EmptyStatement();
@@ -4218,7 +4232,8 @@
}
JS.Expression _emitEqualityOperator(
- Expression left, Member target, Expression right) {
+ Expression left, Member target, Expression right,
+ {bool negated = false}) {
var leftType = left.getStaticType(types);
// Conceptually `x == y` in Dart is defined as:
@@ -4246,7 +4261,7 @@
// If we know that the left type uses identity for equality, we can
// sometimes emit better code, either `===` or `==`.
if (usesIdentity) {
- return _emitCoreIdenticalCall([left, right]);
+ return _emitCoreIdenticalCall([left, right], negated: negated);
}
// If the left side is nullable, we need to use a runtime helper to check
@@ -4254,12 +4269,12 @@
// a measurable performance effect (possibly the helper is simple enough to
// be inlined).
if (isNullable(left)) {
- return runtimeCall(
- 'equals(#, #)', [_visitExpression(left), _visitExpression(right)]);
+ return js.call(negated ? '!#.equals(#, #)' : '#.equals(#, #)',
+ [runtimeModule, _visitExpression(left), _visitExpression(right)]);
}
// Otherwise we emit a call to the == method.
- return js.call('#[#](#)', [
+ return js.call(negated ? '!#[#](#)' : '#[#](#)', [
_visitExpression(left),
_emitMemberName('==', type: leftType),
_visitExpression(right)
@@ -4730,9 +4745,24 @@
@override
visitNot(Not node) {
+ var operand = node.operand;
+ if (operand is MethodInvocation && operand.name.name == '==') {
+ return _emitEqualityOperator(operand.receiver, operand.interfaceTarget,
+ operand.arguments.positional[0],
+ negated: true);
+ } else if (operand is DirectMethodInvocation && operand.name.name == '==') {
+ return _emitEqualityOperator(
+ operand.receiver, operand.target, operand.arguments.positional[0],
+ negated: true);
+ } else if (operand is StaticInvocation &&
+ operand.target == coreTypes.identicalProcedure) {
+ return _emitCoreIdenticalCall(operand.arguments.positional,
+ negated: true);
+ }
+
// Logical negation, `!e`, is a boolean conversion context since it is
// defined as `e ? false : true`.
- return _visitTest(node);
+ return js.call('!#', _visitTest(operand));
}
@override
@@ -4863,8 +4893,15 @@
return jsFrom;
}
- var code = isTypeError ? '#._check(#)' : '#.as(#)';
- return js.call(code, [_emitType(to), jsFrom]);
+ return isTypeError
+ ? _emitImplicitCast(jsFrom, to)
+ : js.call('#.as(#)', [_emitType(to), jsFrom]);
+ }
+
+ JS.Expression _emitImplicitCast(JS.Expression expr, DartType type) {
+ return types.isTop(type)
+ ? expr
+ : js.call('#._check(#)', [_emitType(type), expr]);
}
@override
@@ -5004,6 +5041,10 @@
JS.Block block = body;
if (block.statements.length == 1) {
JS.Statement s = block.statements[0];
+ if (s is JS.Block) {
+ block = s;
+ s = block.statements.length == 1 ? block.statements[0] : null;
+ }
if (s is JS.Return && s.value != null) body = s.value;
}
}
@@ -5108,6 +5149,7 @@
bool _reifyTearoff(Member member) {
return member is Procedure &&
!member.isAccessor &&
+ !member.isFactory &&
!_isInForeignJS &&
!usesJSInterop(member) &&
_reifyFunctionType(member.function);
diff --git a/pkg/dev_compiler/lib/src/kernel/js_typerep.dart b/pkg/dev_compiler/lib/src/kernel/js_typerep.dart
index 0f2a383..8b6500b 100644
--- a/pkg/dev_compiler/lib/src/kernel/js_typerep.dart
+++ b/pkg/dev_compiler/lib/src/kernel/js_typerep.dart
@@ -114,11 +114,12 @@
if (c == coreTypes.nullClass) return JSType.jsNull;
if (c == coreTypes.numClass ||
c == coreTypes.intClass ||
- c == coreTypes.doubleClass) {
+ c == coreTypes.doubleClass ||
+ c == _jsNumber) {
return JSType.jsNumber;
}
- if (c == coreTypes.boolClass) return JSType.jsBoolean;
- if (c == coreTypes.stringClass) return JSType.jsString;
+ if (c == coreTypes.boolClass || c == _jsBool) return JSType.jsBoolean;
+ if (c == coreTypes.stringClass || c == _jsString) return JSType.jsString;
if (c == coreTypes.objectClass) return JSType.jsUnknown;
if (c == coreTypes.futureOrClass) {
var argumentRep = typeFor(type.typeArguments[0]);
diff --git a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
index 18fb1a3..d0043bb 100644
--- a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
+++ b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
@@ -113,9 +113,20 @@
///
/// Given teh node for `@MyAnnotation('FooBar')` this will return `'FooBar'`.
String getNameFromAnnotation(ConstructorInvocation node) {
- if (node != null && node.arguments.positional.isNotEmpty) {
- var first = _followConstFields(node.arguments.positional[0]);
- if (first is StringLiteral) return first.value;
+ if (node != null) {
+ Expression first;
+ if (node.arguments.named.isNotEmpty) {
+ first = node.arguments.named
+ .firstWhere((n) => n.name == 'name', orElse: () => null)
+ ?.value;
+ }
+ if (node.arguments.positional.isNotEmpty) {
+ first ??= node.arguments.positional[0];
+ }
+ if (first != null) {
+ first = _followConstFields(first);
+ if (first is StringLiteral) return first.value;
+ }
}
return null;
}
@@ -296,3 +307,35 @@
}
return false;
}
+
+/// Returns the redirecting factory constructors for the enclosing class,
+/// if the field [f] is storing that information, otherwise returns `null`.
+Iterable<Member> getRedirectingFactories(Field f) {
+ // TODO(jmesserly): this relies on implementation details in Kernel
+ if (f.name.name == "_redirecting#") {
+ assert(f.isStatic);
+ var list = f.initializer as ListLiteral;
+ return list.expressions.map((e) => (e as StaticGet).target);
+ }
+ return null;
+}
+
+/// Gets the real supertype of [c] and the list of [mixins] in reverse
+/// application order (mixins will appear before ones they override).
+///
+/// This is used to ignore synthetic mixin application classes.
+///
+// TODO(jmesserly): consider replacing this with Kernel's mixin unrolling once
+// we don't have the Analyzer backend to maintain.
+Class getSuperclassAndMixins(Class c, List<Class> mixins) {
+ assert(mixins.isEmpty);
+
+ var mixedInClass = c.mixedInClass;
+ if (mixedInClass != null) mixins.add(mixedInClass);
+
+ var sc = c.superclass;
+ for (; sc.isSyntheticMixinImplementation; sc = sc.superclass) {
+ mixins.add(sc.mixedInClass);
+ }
+ return sc;
+}
diff --git a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
index 0dd31c6..edf71af 100644
--- a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
+++ b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
@@ -100,19 +100,24 @@
visitStaticSet(StaticSet node) => isNullable(node.value);
@override
- visitMethodInvocation(MethodInvocation node) =>
- _invocationIsNullable(node.interfaceTarget, node.receiver);
+ visitMethodInvocation(MethodInvocation node) => _invocationIsNullable(
+ node.interfaceTarget, node.name.name, node.receiver);
@override
visitDirectMethodInvocation(DirectMethodInvocation node) =>
- _invocationIsNullable(node.target, node.receiver);
+ _invocationIsNullable(node.target, node.name.name, node.receiver);
@override
visitSuperMethodInvocation(SuperMethodInvocation node) =>
- _invocationIsNullable(node.interfaceTarget);
+ _invocationIsNullable(node.interfaceTarget, node.name.name);
- bool _invocationIsNullable(Member target, [Expression receiver]) {
- if (target == null) return true;
+ bool _invocationIsNullable(Member target, String name,
+ [Expression receiver]) {
+ // TODO(jmesserly): this is not a valid assumption for user-defined equality
+ // but it is added to match the behavior of the Analyzer backend.
+ // https://github.com/dart-lang/sdk/issues/31854
+ if (name == '==') return false;
+ if (target == null) return true; // dynamic call
if (target.name.name == 'toString' &&
receiver != null &&
receiver.getStaticType(types) == coreTypes.stringClass.rawType) {
@@ -133,11 +138,6 @@
}
bool _returnValueIsNullable(Member target) {
- // TODO(jmesserly): this is not a valid assumption for user-defined equality
- // but it is added to match the behavior of the Analyzer backend.
- // https://github.com/dart-lang/sdk/issues/31854
- if (target.name.name == '==') return false;
-
var targetClass = target.enclosingClass;
if (targetClass != null) {
// Convert `int` `double` `num` `String` and `bool` to their corresponding
@@ -168,13 +168,13 @@
var args = node.arguments.positional;
var first = args.isNotEmpty ? args.first : null;
if (first is StringLiteral) {
- var types = first.value;
- return types == '' ||
- types == 'var' ||
- types.split('|').contains('Null');
+ var typeString = first.value;
+ return typeString == '' ||
+ typeString == 'var' ||
+ typeString.split('|').contains('Null');
}
}
- return _invocationIsNullable(target);
+ return _invocationIsNullable(target, node.name.name);
}
@override
diff --git a/pkg/dev_compiler/lib/src/kernel/property_model.dart b/pkg/dev_compiler/lib/src/kernel/property_model.dart
index 9f49edb..51cad84 100644
--- a/pkg/dev_compiler/lib/src/kernel/property_model.dart
+++ b/pkg/dev_compiler/lib/src/kernel/property_model.dart
@@ -367,10 +367,12 @@
visitSuper(c);
}
- var m = class_.mixedInClass;
- if (m != null) visitImmediateSuper(m);
- var s = class_.superclass;
- if (s != null) visitImmediateSuper(s);
+ if (class_.superclass != null) {
+ var mixins = <Class>[];
+ var superclass = getSuperclassAndMixins(class_, mixins);
+ mixins.forEach(visitImmediateSuper);
+ visitImmediateSuper(superclass);
+ }
}
/// Searches all concrete instance members declared on this type, skipping
diff --git a/pkg/dev_compiler/test/transformer/hello_app/pubspec.lock b/pkg/dev_compiler/test/transformer/hello_app/pubspec.lock
deleted file mode 100644
index 01b736a..0000000
--- a/pkg/dev_compiler/test/transformer/hello_app/pubspec.lock
+++ /dev/null
@@ -1,226 +0,0 @@
-# Generated by pub
-# See http://pub.dartlang.org/doc/glossary.html#lockfile
-packages:
- analyzer:
- description:
- name: analyzer
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.27.3-alpha.2"
- args:
- description:
- name: args
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.13.3+6"
- async:
- description:
- name: async
- url: "https://pub.dartlang.org"
- source: hosted
- version: "1.9.0"
- barback:
- description:
- name: barback
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.15.2+7"
- browser:
- description:
- name: browser
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.10.0+2"
- charcode:
- description:
- name: charcode
- url: "https://pub.dartlang.org"
- source: hosted
- version: "1.1.0"
- cli_util:
- description:
- name: cli_util
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.0.1+2"
- code_transformers:
- description:
- name: code_transformers
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.4.1"
- collection:
- description:
- name: collection
- url: "https://pub.dartlang.org"
- source: hosted
- version: "1.4.0"
- crypto:
- description:
- name: crypto
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.9.1"
- csslib:
- description:
- name: csslib
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.12.2"
- dev_compiler:
- description:
- path: "../../.."
- relative: true
- source: path
- version: "0.1.22"
- func:
- description:
- name: func
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.1.0"
- glob:
- description:
- name: glob
- url: "https://pub.dartlang.org"
- source: hosted
- version: "1.1.1"
- hello_dep:
- description:
- path: "../hello_dep"
- relative: true
- source: path
- version: "0.0.1"
- html:
- description:
- name: html
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.12.2+1"
- http_parser:
- description:
- name: http_parser
- url: "https://pub.dartlang.org"
- source: hosted
- version: "2.2.0"
- js:
- description:
- name: js
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.6.0"
- logging:
- description:
- name: logging
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.11.2"
- mime:
- description:
- name: mime
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.9.3"
- package_config:
- description:
- name: package_config
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.1.3"
- path:
- description:
- name: path
- url: "https://pub.dartlang.org"
- source: hosted
- version: "1.3.9"
- plugin:
- description:
- name: plugin
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.1.0"
- pool:
- description:
- name: pool
- url: "https://pub.dartlang.org"
- source: hosted
- version: "1.2.1"
- pub_semver:
- description:
- name: pub_semver
- url: "https://pub.dartlang.org"
- source: hosted
- version: "1.2.3"
- shelf:
- description:
- name: shelf
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.6.5"
- shelf_static:
- description:
- name: shelf_static
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.2.3+3"
- source_maps:
- description:
- name: source_maps
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.10.1"
- source_span:
- description:
- name: source_span
- url: "https://pub.dartlang.org"
- source: hosted
- version: "1.2.2"
- stack_trace:
- description:
- name: stack_trace
- url: "https://pub.dartlang.org"
- source: hosted
- version: "1.6.1"
- stream_channel:
- description:
- name: stream_channel
- url: "https://pub.dartlang.org"
- source: hosted
- version: "1.3.1"
- string_scanner:
- description:
- name: string_scanner
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.1.4+1"
- utf:
- description:
- name: utf
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.9.0+3"
- watcher:
- description:
- name: watcher
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.9.7"
- when:
- description:
- name: when
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.2.0"
- which:
- description:
- name: which
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.1.3"
- yaml:
- description:
- name: yaml
- url: "https://pub.dartlang.org"
- source: hosted
- version: "2.1.8"
-sdk: ">=1.14.0 <2.0.0"
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart
index d082f88..4d2f78f 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart
@@ -36,9 +36,9 @@
throw new AssertionErrorImpl(message);
}
-throwCyclicInitializationError([String message]) {
+throwCyclicInitializationError([Object field]) {
if (JS('bool', 'dart.__trapRuntimeErrors')) JS('', 'debugger');
- throw new CyclicInitializationError(message);
+ throw new CyclicInitializationError(field);
}
throwNullValueError() {
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart
index 3215fa5..48b35b0 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart
@@ -706,35 +706,22 @@
return $type.toString();
}
- // Wrapped types
- if ($type instanceof $WrappedType) {
- return "Wrapped(" + $unwrapType($type) + ")";
- }
-
// Instance types
let tag = $type[$_runtimeType];
if (tag === $Type) {
let name = $type.name;
- let args = $getGenericArgs($type);
- if (!args) return name;
+ let args = ${getGenericArgs(type)};
+ if (args == null) return name;
+
+ if (${getGenericClass(type)} == ${getGenericClass(JSArray)}) name = 'List';
let result = name;
- let allDynamic = true;
-
result += '<';
for (let i = 0; i < args.length; ++i) {
if (i > 0) result += ', ';
-
- let argName = $typeName(args[i]);
- if (argName != 'dynamic') allDynamic = false;
-
- result += argName;
+ result += $typeName(args[i]);
}
result += '>';
-
- // Don't print the type arguments if they are all dynamic. Show "raw"
- // types as just the bare type name.
- if (allDynamic) return name;
return result;
}
if (tag) return "Not a type: " + tag.name;
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart
index 80a84de..d913dfa8 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart
@@ -69,14 +69,17 @@
let value = null;
$desc.get = function() {
if (init == null) return value;
-
- // Compute and store the value, guarding against reentry.
let f = init;
- init = () => $throwCyclicInitializationError($name);
+ init = $throwCyclicInitializationError;
+ if (f === init) f($name); // throw cycle error
try {
- return value = f();
- } finally {
+ value = f();
init = null;
+ return value;
+ } catch (e) {
+ init = null;
+ value = null;
+ throw e;
}
};
$desc.configurable = true;
diff --git a/pkg/dev_compiler/tool/input_sdk/private/debugger.dart b/pkg/dev_compiler/tool/input_sdk/private/debugger.dart
index 42128b2..2d9982b 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/debugger.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/debugger.dart
@@ -135,14 +135,10 @@
}
String getTypeName(type) {
- var name = dart.typeName(type);
- // Hack to cleanup names for List<dynamic>
// TODO(jacobr): it would be nice if there was a way we could distinguish
// between a List<dynamic> created from Dart and an Array passed in from
// JavaScript.
- if (name == 'JSArray<dynamic>' || name == 'JSObject<Array>')
- return 'List<dynamic>';
- return name;
+ return dart.typeName(type);
}
String safePreview(object, config) {
@@ -884,7 +880,6 @@
..addAll(sortProperties(instanceMethods));
}
- var typeName = getTypeName(type);
var mixin = dart.getMixin(type);
if (mixin != null) {
// TODO(jmesserly): this can only be one value.
diff --git a/pkg/dev_compiler/tool/input_sdk/private/interceptors.dart b/pkg/dev_compiler/tool/input_sdk/private/interceptors.dart
index 20aee27..23c00f0 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/interceptors.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/interceptors.dart
@@ -114,8 +114,9 @@
class JSFunction extends Interceptor {
toString() {
// If the function is a Type object, we should just display the type name.
+ //
// Regular Dart code should typically get wrapped type objects instead of
- // raw type (aka JS constructor) objects however raw type objects can be
+ // raw type (aka JS constructor) objects, however raw type objects can be
// exposed to Dart code via JS interop or debugging tools.
if (dart.isType(this)) return dart.typeName(this);
diff --git a/pkg/dev_compiler/tool/kernel_sdk.dart b/pkg/dev_compiler/tool/kernel_sdk.dart
index f8cb4e7..fac6737 100755
--- a/pkg/dev_compiler/tool/kernel_sdk.dart
+++ b/pkg/dev_compiler/tool/kernel_sdk.dart
@@ -47,7 +47,7 @@
await writeComponentToBinary(component, outputPath);
var jsModule = new ProgramCompiler(component, declaredVariables: {})
- .emitProgram(component, [], []);
+ .emitModule(component, [], []);
var moduleFormats = {
'amd': ModuleFormat.amd,
'common': ModuleFormat.common,
diff --git a/pkg/front_end/lib/src/fasta/kernel/fasta_accessors.dart b/pkg/front_end/lib/src/fasta/kernel/fasta_accessors.dart
index 79859e9..8e79571 100644
--- a/pkg/front_end/lib/src/fasta/kernel/fasta_accessors.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/fasta_accessors.dart
@@ -434,7 +434,7 @@
Expression buildSimpleRead() {
if (!isSuper) {
- return new ShadowThisExpression();
+ return new ShadowThisExpression()..fileOffset = offsetForToken(token);
} else {
return helper.buildCompileTimeError(messageSuperAsExpression,
offsetForToken(token), lengthForToken(token));
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
index 36c7523..b4c9192 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
@@ -413,16 +413,18 @@
if (isPreIncDec || isPostIncDec) {
rhsType = inferrer.coreTypes.intClass.rawType;
} else {
- // Analyzer uses a null context for the RHS here.
- // TODO(paulberry): improve on this.
- rhsType = inferrer.inferExpression(rhs, const UnknownType(), true);
// It's not necessary to call _storeLetType for [rhs] because the RHS
// is always passed directly to the combiner; it's never stored in a
// temporary variable first.
- assert(identical(combiner.arguments.positional[0], rhs));
+ assert(identical(combiner.arguments.positional.first, rhs));
+ // Analyzer uses a null context for the RHS here.
+ // TODO(paulberry): improve on this.
+ rhsType = inferrer.inferExpression(rhs, const UnknownType(), true);
+ // Do not use rhs after this point because it may be a Shadow node
+ // that has been replaced in the tree with its desugaring.
var expectedType = getPositionalParameterType(combinerType, 0);
- inferrer.ensureAssignable(
- expectedType, rhsType, rhs, combiner.fileOffset);
+ inferrer.ensureAssignable(expectedType, rhsType,
+ combiner.arguments.positional.first, combiner.fileOffset);
}
if (isOverloadedArithmeticOperator) {
combinedType = inferrer.typeSchemaEnvironment
@@ -1910,6 +1912,7 @@
/// [desugared].
void _replaceWithDesugared() {
parent.replaceChild(this, desugared);
+ parent = null;
}
/// Updates any [Let] nodes in the desugared expression to account for the
diff --git a/pkg/front_end/lib/src/fasta/parser/identifier_context.dart b/pkg/front_end/lib/src/fasta/parser/identifier_context.dart
index b2969e2..26dea92 100644
--- a/pkg/front_end/lib/src/fasta/parser/identifier_context.dart
+++ b/pkg/front_end/lib/src/fasta/parser/identifier_context.dart
@@ -132,8 +132,7 @@
inDeclaration: true);
/// Identifier is a name being declared by a field declaration.
- static const fieldDeclaration =
- const IdentifierContext('fieldDeclaration', inDeclaration: true);
+ static const fieldDeclaration = const FieldDeclarationIdentifierContext();
/// Identifier is the name being declared by a top level function declaration.
static const topLevelFunctionDeclaration = const IdentifierContext(
@@ -142,8 +141,7 @@
/// Identifier is the start of the name being declared by a method
/// declaration.
- static const methodDeclaration =
- const IdentifierContext('methodDeclaration', inDeclaration: true);
+ static const methodDeclaration = const MethodDeclarationIdentifierContext();
/// Identifier is part of the name being declared by a method declaration,
/// but it's not the first identifier of the name.
@@ -151,10 +149,8 @@
/// In valid Dart, this can only happen if the identifier is the name of a
/// named constructor which is being declared, e.g. `foo` in
/// `class C { C.foo(); }`.
- static const methodDeclarationContinuation = const IdentifierContext(
- 'methodDeclarationContinuation',
- inDeclaration: true,
- isContinuation: true);
+ static const methodDeclarationContinuation =
+ const MethodDeclarationIdentifierContext.continuation();
/// Identifier appears after the word `operator` in a method declaration.
///
diff --git a/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart b/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart
index a5e4efa..97798fb 100644
--- a/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart
+++ b/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart
@@ -31,7 +31,7 @@
return identifier;
}
- if (looksLikeStartOfNextDeclaration(identifier) ||
+ if (looksLikeStartOfNextTopLevelDeclaration(identifier) ||
isOneOfOrEof(
identifier, const ['<', '{', 'extends', 'with', 'implements'])) {
identifier = parser.insertSyntheticIdentifier(token, this,
@@ -76,7 +76,7 @@
}
}
- if (looksLikeStartOfNextDeclaration(identifier) ||
+ if (looksLikeStartOfNextTopLevelDeclaration(identifier) ||
isOneOfOrEof(identifier, followingValues)) {
identifier = parser.insertSyntheticIdentifier(token, this,
message: fasta.templateExpectedIdentifier.withArguments(identifier));
@@ -141,6 +141,35 @@
}
}
+class FieldDeclarationIdentifierContext extends IdentifierContext {
+ const FieldDeclarationIdentifierContext()
+ : super('fieldDeclaration', inDeclaration: true);
+
+ @override
+ Token ensureIdentifier(Token token, Parser parser) {
+ Token identifier = token.next;
+ assert(identifier.kind != IDENTIFIER_TOKEN);
+ if (identifier.isIdentifier) {
+ return identifier;
+ }
+ // Recovery
+ if (isOneOfOrEof(identifier, const [';', '=', ',', '}']) ||
+ looksLikeStartOfNextClassMember(identifier)) {
+ return parser.insertSyntheticIdentifier(token, this);
+ } else if (!identifier.isKeywordOrIdentifier) {
+ // When in doubt, consume the token to ensure we make progress
+ // but insert a synthetic identifier to satisfy listeners.
+ return parser.insertSyntheticIdentifier(identifier, this,
+ message: fasta.templateExpectedIdentifier.withArguments(identifier),
+ messageOnToken: identifier);
+ } else {
+ parser.reportRecoverableErrorWithToken(
+ identifier, fasta.templateExpectedIdentifier);
+ return identifier;
+ }
+ }
+}
+
/// See [IdentifierContext].fieldInitializer
class FieldInitializerIdentifierContext extends IdentifierContext {
const FieldInitializerIdentifierContext()
@@ -177,7 +206,7 @@
if (identifier.isIdentifier) {
Token next = identifier.next;
if (isOneOfOrEof(next, const ['.', ';']) ||
- !looksLikeStartOfNextDeclaration(identifier)) {
+ !looksLikeStartOfNextTopLevelDeclaration(identifier)) {
return identifier;
}
// Although this is a valid library name, the library declaration
@@ -185,7 +214,7 @@
// In this situation, fall through to insert a synthetic library name.
}
if (isOneOfOrEof(identifier, const ['.', ';']) ||
- looksLikeStartOfNextDeclaration(identifier)) {
+ looksLikeStartOfNextTopLevelDeclaration(identifier)) {
identifier = parser.insertSyntheticIdentifier(token, this,
message: fasta.templateExpectedIdentifier.withArguments(identifier));
} else {
@@ -231,6 +260,43 @@
}
}
+class MethodDeclarationIdentifierContext extends IdentifierContext {
+ const MethodDeclarationIdentifierContext()
+ : super('methodDeclaration', inDeclaration: true);
+
+ const MethodDeclarationIdentifierContext.continuation()
+ : super('methodDeclarationContinuation',
+ inDeclaration: true, isContinuation: true);
+
+ @override
+ Token ensureIdentifier(Token token, Parser parser) {
+ Token identifier = token.next;
+ assert(identifier.kind != IDENTIFIER_TOKEN);
+ if (identifier.isIdentifier) {
+ return identifier;
+ }
+ // Recovery
+ if (identifier.isUserDefinableOperator && !isContinuation) {
+ return parser.insertSyntheticIdentifier(identifier, this,
+ message: fasta.messageMissingOperatorKeyword,
+ messageOnToken: identifier);
+ } else if (isOneOfOrEof(identifier, const ['.', '(', '{', '=>']) ||
+ looksLikeStartOfNextClassMember(identifier)) {
+ return parser.insertSyntheticIdentifier(token, this);
+ } else if (!identifier.isKeywordOrIdentifier) {
+ // When in doubt, consume the token to ensure we make progress
+ // but insert a synthetic identifier to satisfy listeners.
+ return parser.insertSyntheticIdentifier(identifier, this,
+ message: fasta.templateExpectedIdentifier.withArguments(identifier),
+ messageOnToken: identifier);
+ } else {
+ parser.reportRecoverableErrorWithToken(
+ identifier, fasta.templateExpectedIdentifier);
+ return identifier;
+ }
+ }
+}
+
/// See [IdentifierContext].typeReference
class TypeReferenceIdentifierContext extends IdentifierContext {
const TypeReferenceIdentifierContext()
@@ -315,9 +381,8 @@
return token.isEof;
}
-bool looksLikeStartOfNextDeclaration(Token token) =>
- token.isTopLevelKeyword ||
- isOneOfOrEof(token, const ['const', 'get', 'final', 'set', 'var', 'void']);
+bool looksLikeStartOfNextClassMember(Token token) =>
+ token.isModifier || isOneOfOrEof(token, const ['get', 'set', 'void']);
bool looksLikeStartOfNextStatement(Token token) => isOneOfOrEof(token, const [
'assert',
@@ -336,6 +401,10 @@
'while'
]);
+bool looksLikeStartOfNextTopLevelDeclaration(Token token) =>
+ token.isTopLevelKeyword ||
+ isOneOfOrEof(token, const ['const', 'get', 'final', 'set', 'var', 'void']);
+
Token skipMetadata(Token token) {
assert(optional('@', token));
Token next = token.next;
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index a23beb1..e66820c 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -34,8 +34,6 @@
EOF_TOKEN,
EQ_TOKEN,
FUNCTION_TOKEN,
- GT_GT_TOKEN,
- GT_TOKEN,
HASH_TOKEN,
HEXADECIMAL_TOKEN,
IDENTIFIER_TOKEN,
@@ -45,7 +43,6 @@
OPEN_CURLY_BRACKET_TOKEN,
OPEN_PAREN_TOKEN,
OPEN_SQUARE_BRACKET_TOKEN,
- PERIOD_TOKEN,
SEMICOLON_TOKEN,
STRING_INTERPOLATION_IDENTIFIER_TOKEN,
STRING_INTERPOLATION_TOKEN,
@@ -94,6 +91,8 @@
isValidTypeReference,
noType;
+import 'type_info_impl.dart' show skipTypeVariables;
+
import 'util.dart' show optional;
/// An event generating parser of Dart programs. This parser expects all tokens
@@ -1506,76 +1505,14 @@
/// arguments in generic method invocations can be recognized, and as few as
/// possible other constructs will pass (e.g., 'a < C, D > 3').
bool isValidMethodTypeArguments(Token token) {
- Token Function(Token token) tryParseType;
-
- /// Returns token after match if [token] matches '<' type (',' type)* '>'
- /// '(', and otherwise returns null. Does not produce listener events. With
- /// respect to the final '(', please see the description of
- /// [isValidMethodTypeArguments].
- Token tryParseMethodTypeArguments(Token token) {
- if (!identical(token.kind, LT_TOKEN)) return null;
- Token endToken = token.endGroup;
- if (endToken == null ||
- !identical(endToken.next.kind, OPEN_PAREN_TOKEN)) {
- return null;
+ // TODO(danrubel): Replace call with a call to computeTypeVar.
+ if (optional('<', token)) {
+ Token endGroup = skipTypeVariables(token);
+ if (endGroup != null && optional('(', endGroup.next)) {
+ return true;
}
- token = tryParseType(token.next);
- while (token != null && identical(token.kind, COMMA_TOKEN)) {
- token = tryParseType(token.next);
- }
- if (token == null || !identical(token.kind, GT_TOKEN)) return null;
- return token.next;
}
-
- /// Returns token after match if [token] matches identifier ('.'
- /// identifier)?, and otherwise returns null. Does not produce listener
- /// events.
- Token tryParseQualified(Token token) {
- if (!isValidTypeReference(token)) return null;
- token = token.next;
- if (!identical(token.kind, PERIOD_TOKEN)) return token;
- token = token.next;
- if (!identical(token.kind, IDENTIFIER_TOKEN)) return null;
- return token.next;
- }
-
- /// Returns token after match if [token] matches '<' type (',' type)* '>',
- /// and otherwise returns null. Does not produce listener events. The final
- /// '>' may be the first character in a '>>' token, in which case a
- /// synthetic '>' token is created and returned, representing the second
- /// '>' in the '>>' token.
- Token tryParseNestedTypeArguments(Token token) {
- if (!identical(token.kind, LT_TOKEN)) return null;
- // If the initial '<' matches the first '>' in a '>>' token, we will have
- // `token.endGroup == null`, so we cannot rely on `token.endGroup == null`
- // to imply that the match must fail. Hence no `token.endGroup == null`
- // test here.
- token = tryParseType(token.next);
- while (token != null && identical(token.kind, COMMA_TOKEN)) {
- token = tryParseType(token.next);
- }
- if (token == null) return null;
- if (identical(token.kind, GT_TOKEN)) return token.next;
- if (!identical(token.kind, GT_GT_TOKEN)) return null;
- // [token] is '>>' of which the final '>' that we are parsing is the first
- // character. In order to keep the parsing process on track we must return
- // a synthetic '>' corresponding to the second character of that '>>'.
- Token syntheticToken = new Token(TokenType.GT, token.charOffset + 1);
- syntheticToken.next = token.next;
- return syntheticToken;
- }
-
- /// Returns token after match if [token] matches typeName typeArguments?,
- /// and otherwise returns null. Does not produce listener events.
- tryParseType = (Token token) {
- token = tryParseQualified(token);
- if (token == null) return null;
- Token tokenAfterQualified = token;
- token = tryParseNestedTypeArguments(token);
- return token == null ? tokenAfterQualified : token;
- };
-
- return tryParseMethodTypeArguments(token) != null;
+ return false;
}
/// ```
@@ -1981,24 +1918,9 @@
} else if (next.isKeywordOrIdentifier) {
reportRecoverableErrorWithToken(next, context.recoveryTemplate);
token = next;
- } else if (next.isUserDefinableOperator &&
- context == IdentifierContext.methodDeclaration) {
- // If this is a user definable operator, then assume that the user has
- // forgotten the `operator` keyword.
- token = rewriteAndRecover(token, fasta.messageMissingOperatorKeyword,
- new SyntheticKeywordToken(Keyword.OPERATOR, next.offset));
- return parseOperatorName(token);
} else {
reportRecoverableErrorWithToken(next, context.recoveryTemplate);
- if (context == IdentifierContext.methodDeclaration) {
- // Since the token is not a keyword or identifier, consume it to
- // ensure forward progress in parseMethod.
- token = next.next;
- // Supply a non-empty method name so that it does not accidentally
- // match the default constructor.
- token = insertSyntheticIdentifier(next, context);
- } else if (context == IdentifierContext.topLevelVariableDeclaration ||
- context == IdentifierContext.fieldDeclaration) {
+ if (context == IdentifierContext.topLevelVariableDeclaration) {
// Since the token is not a keyword or identifier, consume it to
// ensure forward progress in parseField.
token = next.next;
@@ -2077,8 +1999,6 @@
followingValues = [';'];
} else if (context == IdentifierContext.constructorReferenceContinuation) {
followingValues = ['.', ',', '(', ')', '[', ']', '}', ';'];
- } else if (context == IdentifierContext.fieldDeclaration) {
- followingValues = [';', '=', ',', '}'];
} else if (context == IdentifierContext.enumDeclaration) {
followingValues = ['{'];
} else if (context == IdentifierContext.enumValueDeclaration) {
@@ -2097,9 +2017,6 @@
} else if (context == IdentifierContext.localFunctionDeclaration ||
context == IdentifierContext.localFunctionDeclarationContinuation) {
followingValues = ['.', '(', '{', '=>'];
- } else if (context == IdentifierContext.methodDeclaration ||
- context == IdentifierContext.methodDeclarationContinuation) {
- followingValues = ['.', '(', '{', '=>'];
} else if (context == IdentifierContext.topLevelFunctionDeclaration) {
followingValues = ['(', '{', '=>'];
} else if (context == IdentifierContext.topLevelVariableDeclaration) {
@@ -2160,9 +2077,7 @@
// could create a method to test whether a given token matches one of the
// patterns.
List<String> initialKeywords;
- if (context == IdentifierContext.fieldDeclaration) {
- initialKeywords = classMemberKeywords();
- } else if (context == IdentifierContext.enumDeclaration) {
+ if (context == IdentifierContext.enumDeclaration) {
initialKeywords = topLevelKeywords();
} else if (context == IdentifierContext.formalParameterDeclaration) {
initialKeywords = topLevelKeywords()
@@ -2180,10 +2095,6 @@
} else if (context ==
IdentifierContext.localFunctionDeclarationContinuation) {
initialKeywords = statementKeywords();
- } else if (context == IdentifierContext.methodDeclaration) {
- initialKeywords = classMemberKeywords();
- } else if (context == IdentifierContext.methodDeclarationContinuation) {
- initialKeywords = classMemberKeywords();
} else if (context == IdentifierContext.topLevelFunctionDeclaration) {
initialKeywords = topLevelKeywords();
} else if (context == IdentifierContext.topLevelVariableDeclaration) {
@@ -6209,54 +6120,29 @@
staticToken, covariantToken, varFinalOrConst, beforeType);
}
- bool looksLikeMethod = getOrSet != null ||
+ if (getOrSet != null ||
identical(value, '(') ||
identical(value, '=>') ||
- identical(value, '{');
- if (token == beforeStart && !looksLikeMethod) {
- // Ensure we make progress.
+ identical(value, '{')) {
+ token = parseMethod(
+ beforeStart,
+ externalToken,
+ staticToken,
+ covariantToken,
+ varFinalOrConst,
+ beforeType,
+ typeInfo,
+ getOrSet,
+ token);
+ } else if (token == beforeStart) {
// TODO(danrubel): Provide a more specific error message for extra ';'.
reportRecoverableErrorWithToken(next, fasta.templateExpectedClassMember);
listener.handleInvalidMember(next);
+ // Ensure we make progress.
token = next;
} else {
- // Looks like a partial declaration.
- reportRecoverableError(
- next, fasta.templateExpectedIdentifier.withArguments(next));
- // Insert a synthetic identifier and continue parsing.
- if (!next.isIdentifier) {
- rewriter.insertTokenAfter(
- token,
- new SyntheticStringToken(
- TokenType.IDENTIFIER,
- '#synthetic_identifier_${next.charOffset}',
- next.charOffset,
- 0));
- }
-
- if (looksLikeMethod) {
- token = parseMethod(
- beforeStart,
- externalToken,
- staticToken,
- covariantToken,
- varFinalOrConst,
- beforeType,
- typeInfo,
- getOrSet,
- token);
- } else {
- token = parseFields(
- beforeStart,
- externalToken,
- staticToken,
- covariantToken,
- varFinalOrConst,
- beforeType,
- typeInfo,
- token,
- false);
- }
+ token = parseFields(beforeStart, externalToken, staticToken,
+ covariantToken, varFinalOrConst, beforeType, typeInfo, token, false);
}
listener.endMember();
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 47471e5..23a9329 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -219,7 +219,7 @@
!_analyzerSubtypeOf(inferrer, inferredType, returnOrYieldContext)) {
// If the inferred return type isn't a subtype of the context, we use the
// context.
- inferredType = returnOrYieldContext;
+ inferredType = greatestClosure(inferrer.coreTypes, returnOrYieldContext);
}
return _wrapAsyncOrGenerator(inferrer, inferredType);
diff --git a/pkg/front_end/testcases/external_import.dart.direct.expect b/pkg/front_end/testcases/external_import.dart.direct.expect
index 145e77a..b262abf 100644
--- a/pkg/front_end/testcases/external_import.dart.direct.expect
+++ b/pkg/front_end/testcases/external_import.dart.direct.expect
@@ -3,5 +3,6 @@
@dart._internal::ExternalName::•("file:///usr/local/somewhere")
library;
import self as self;
+import "dart:_internal" as _in;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/external_import.dart.direct.transformed.expect b/pkg/front_end/testcases/external_import.dart.direct.transformed.expect
index 145e77a..b262abf 100644
--- a/pkg/front_end/testcases/external_import.dart.direct.transformed.expect
+++ b/pkg/front_end/testcases/external_import.dart.direct.transformed.expect
@@ -3,5 +3,6 @@
@dart._internal::ExternalName::•("file:///usr/local/somewhere")
library;
import self as self;
+import "dart:_internal" as _in;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/external_import.dart.outline.expect b/pkg/front_end/testcases/external_import.dart.outline.expect
index d48db80..b446720 100644
--- a/pkg/front_end/testcases/external_import.dart.outline.expect
+++ b/pkg/front_end/testcases/external_import.dart.outline.expect
@@ -3,6 +3,7 @@
@dart._internal::ExternalName::•("file:///usr/local/somewhere")
library;
import self as self;
+import "dart:_internal" as _in;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/external_import.dart.strong.expect b/pkg/front_end/testcases/external_import.dart.strong.expect
index 145e77a..b262abf 100644
--- a/pkg/front_end/testcases/external_import.dart.strong.expect
+++ b/pkg/front_end/testcases/external_import.dart.strong.expect
@@ -3,5 +3,6 @@
@dart._internal::ExternalName::•("file:///usr/local/somewhere")
library;
import self as self;
+import "dart:_internal" as _in;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/external_import.dart.strong.transformed.expect b/pkg/front_end/testcases/external_import.dart.strong.transformed.expect
index 145e77a..b262abf 100644
--- a/pkg/front_end/testcases/external_import.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/external_import.dart.strong.transformed.expect
@@ -3,5 +3,6 @@
@dart._internal::ExternalName::•("file:///usr/local/somewhere")
library;
import self as self;
+import "dart:_internal" as _in;
static method main() → dynamic {}
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index 0cfe661..f87de3d 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -902,11 +902,22 @@
List<[FieldReference, ConstantReference]> values;
}
-type TearOffConstant extends Constant {
+type PartialInstantiationConstant extends Constant {
Byte tag = 8;
+ ConstantReference tearOffConstant;
+ List<DartType> typeArguments;
+}
+
+type TearOffConstant extends Constant {
+ Byte tag = 9;
CanonicalNameReference staticProcedureReference;
}
+type TypeLiteralConstant extends Constant {
+ Byte tag = 10;
+ DartType type;
+}
+
abstract type Statement extends Node {}
type ExpressionStatement extends Statement {
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index d4983da..4d44b72 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -409,6 +409,7 @@
accept(TreeVisitor v) => v.visitLibrary(this);
visitChildren(Visitor v) {
+ visitList(annotations, v);
visitList(dependencies, v);
visitList(parts, v);
visitList(typedefs, v);
@@ -418,6 +419,7 @@
}
transformChildren(Transformer v) {
+ transformList(annotations, v, this);
transformList(dependencies, v, this);
transformList(parts, v, this);
transformList(typedefs, v, this);
@@ -5386,6 +5388,34 @@
}
}
+class PartialInstantiationConstant extends Constant {
+ final TearOffConstant tearOffConstant;
+ final List<DartType> types;
+
+ PartialInstantiationConstant(this.tearOffConstant, this.types);
+
+ visitChildren(Visitor v) {
+ tearOffConstant.acceptReference(v);
+ visitList(types, v);
+ }
+
+ accept(ConstantVisitor v) => v.visitPartialInstantiationConstant(this);
+ acceptReference(Visitor v) =>
+ v.visitPartialInstantiationConstantReference(this);
+
+ String toString() {
+ return '${runtimeType}(${tearOffConstant.procedure}<${types.join(', ')}>)';
+ }
+
+ int get hashCode => tearOffConstant.hashCode ^ listHashCode(types);
+
+ bool operator ==(Object other) {
+ return other is PartialInstantiationConstant &&
+ other.tearOffConstant == tearOffConstant &&
+ listEquals(other.types, types);
+ }
+}
+
class TearOffConstant extends Constant {
final Reference procedureReference;
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index 6749c74..bfdf151 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -215,6 +215,14 @@
fieldValues[fieldRef] = constant;
}
return new InstanceConstant(classReference, typeArguments, fieldValues);
+ case ConstantTag.PartialInstantiationConstant:
+ final tearOffConstant = readConstantReference() as TearOffConstant;
+ final int length = readUInt();
+ final List<DartType> types = new List<DartType>(length);
+ for (int i = 0; i < length; i++) {
+ types[i] = readDartType();
+ }
+ return new PartialInstantiationConstant(tearOffConstant, types);
case ConstantTag.TearOffConstant:
final Reference reference = readCanonicalNameReference().getReference();
return new TearOffConstant.byReference(reference);
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index 6d4c937..3c8dc01 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -175,6 +175,14 @@
writeCanonicalNameReference(fieldRef.canonicalName);
writeConstantReference(value);
});
+ } else if (constant is PartialInstantiationConstant) {
+ writeByte(ConstantTag.PartialInstantiationConstant);
+ writeConstantReference(constant.tearOffConstant);
+ final int length = constant.types.length;
+ writeUInt30(length);
+ for (int i = 0; i < length; ++i) {
+ writeDartType(constant.types[i]);
+ }
} else if (constant is TearOffConstant) {
writeByte(ConstantTag.TearOffConstant);
writeCanonicalNameReference(constant.procedure.canonicalName);
@@ -412,7 +420,23 @@
// RList<UInt32> nodeReferences
if (subsection.nodeToReferenceId != null) {
- for (var nodeOffset in subsection.offsetsOfReferencedNodes) {
+ final offsets = subsection.offsetsOfReferencedNodes;
+ for (int i = 0; i < offsets.length; ++i) {
+ final nodeOffset = offsets[i];
+ if (nodeOffset < 0) {
+ // Dangling reference.
+ // Find a node which was referenced to report meaningful error.
+ Node referencedNode;
+ subsection.nodeToReferenceId.forEach((node, id) {
+ if (id == i) {
+ referencedNode = node;
+ }
+ });
+ throw 'Unable to write reference to node'
+ ' ${referencedNode.runtimeType} $referencedNode'
+ ' from metadata ${subsection.repository.tag}'
+ ' (node is not written into kernel binary)';
+ }
writeUInt32(nodeOffset);
}
writeUInt32(subsection.offsetsOfReferencedNodes.length);
@@ -1897,6 +1921,19 @@
}
@override
+ void visitPartialInstantiationConstant(PartialInstantiationConstant node) {
+ throw new UnsupportedError(
+ 'serialization of PartialInstantiationConstants ');
+ }
+
+ @override
+ void visitPartialInstantiationConstantReference(
+ PartialInstantiationConstant node) {
+ throw new UnsupportedError(
+ 'serialization of PartialInstantiationConstant references');
+ }
+
+ @override
void visitTearOffConstant(TearOffConstant node) {
throw new UnsupportedError('serialization of TearOffConstants ');
}
@@ -2257,6 +2294,6 @@
: nodeToReferenceId =
nodeToReferenceId.isNotEmpty ? nodeToReferenceId : null,
offsetsOfReferencedNodes = nodeToReferenceId.isNotEmpty
- ? new List<int>.filled(nodeToReferenceId.length, 0)
+ ? new List<int>.filled(nodeToReferenceId.length, -1)
: null;
}
diff --git a/pkg/kernel/lib/binary/tag.dart b/pkg/kernel/lib/binary/tag.dart
index e55935e..bc70203 100644
--- a/pkg/kernel/lib/binary/tag.dart
+++ b/pkg/kernel/lib/binary/tag.dart
@@ -147,6 +147,7 @@
static const int MapConstant = 5;
static const int ListConstant = 6;
static const int InstanceConstant = 7;
- static const int TearOffConstant = 8;
- static const int TypeLiteralConstant = 9;
+ static const int PartialInstantiationConstant = 8;
+ static const int TearOffConstant = 9;
+ static const int TypeLiteralConstant = 10;
}
diff --git a/pkg/kernel/lib/clone.dart b/pkg/kernel/lib/clone.dart
index b70521e..c104afe 100644
--- a/pkg/kernel/lib/clone.dart
+++ b/pkg/kernel/lib/clone.dart
@@ -345,7 +345,8 @@
switchCases[switchCase] = new SwitchCase(
switchCase.expressions.map(clone).toList(),
new List<int>.from(switchCase.expressionOffsets),
- null);
+ null,
+ isDefault: switchCase.isDefault);
}
return new SwitchStatement(
clone(node.expression), node.cases.map(clone).toList());
diff --git a/pkg/kernel/lib/target/targets.dart b/pkg/kernel/lib/target/targets.dart
index c7efa89..ec9a8aa 100644
--- a/pkg/kernel/lib/target/targets.dart
+++ b/pkg/kernel/lib/target/targets.dart
@@ -22,13 +22,11 @@
final bool syncAsync;
final List<ProgramRoot> programRoots;
final Uri kernelRuntime;
- final bool allowDartInternalImport;
TargetFlags(
{this.strongMode: false,
this.treeShake: false,
this.syncAsync: false,
- this.allowDartInternalImport: false,
this.programRoots: const <ProgramRoot>[],
this.kernelRuntime});
}
diff --git a/pkg/kernel/lib/target/vm.dart b/pkg/kernel/lib/target/vm.dart
index 7fa5ec3..322d2c5 100644
--- a/pkg/kernel/lib/target/vm.dart
+++ b/pkg/kernel/lib/target/vm.dart
@@ -58,16 +58,6 @@
];
@override
- bool allowPlatformPrivateLibraryAccess(Uri importer, Uri imported) {
- if (flags.allowDartInternalImport &&
- (imported.scheme == 'dart') &&
- (imported.path == '_internal')) {
- return true;
- }
- return super.allowPlatformPrivateLibraryAccess(importer, imported);
- }
-
- @override
void performModularTransformationsOnLibraries(
CoreTypes coreTypes, ClassHierarchy hierarchy, List<Library> libraries,
{void logger(String msg)}) {
diff --git a/pkg/kernel/lib/transformations/constants.dart b/pkg/kernel/lib/transformations/constants.dart
index 84ae345..c618d81 100644
--- a/pkg/kernel/lib/transformations/constants.dart
+++ b/pkg/kernel/lib/transformations/constants.dart
@@ -729,6 +729,22 @@
return canonicalize(backend.buildSymbolConstant(value));
}
+ visitInstantiation(Instantiation node) {
+ final Constant constant = evaluate(node.expression);
+ if (constant is TearOffConstant) {
+ if (node.typeArguments.length ==
+ constant.procedure.function.typeParameters.length) {
+ return canonicalize(
+ new PartialInstantiationConstant(constant, node.typeArguments));
+ }
+ throw new ConstantEvaluationError(
+ 'The number of type arguments supplied in the partial instantiation '
+ 'does not match the number of type arguments of the $constant.');
+ }
+ throw new ConstantEvaluationError(
+ 'Only tear-off constants can be partially instantiated.');
+ }
+
// Helper methods:
void ensureIsSubtype(Constant constant, DartType type) {
diff --git a/pkg/kernel/lib/visitor.dart b/pkg/kernel/lib/visitor.dart
index fa6337c..cde0c92 100644
--- a/pkg/kernel/lib/visitor.dart
+++ b/pkg/kernel/lib/visitor.dart
@@ -283,6 +283,8 @@
R visitMapConstant(MapConstant node) => defaultConstant(node);
R visitListConstant(ListConstant node) => defaultConstant(node);
R visitInstanceConstant(InstanceConstant node) => defaultConstant(node);
+ R visitPartialInstantiationConstant(PartialInstantiationConstant node) =>
+ defaultConstant(node);
R visitTearOffConstant(TearOffConstant node) => defaultConstant(node);
R visitTypeLiteralConstant(TypeLiteralConstant node) => defaultConstant(node);
}
@@ -334,6 +336,8 @@
R visitMapConstant(MapConstant node) => defaultConstant(node);
R visitListConstant(ListConstant node) => defaultConstant(node);
R visitInstanceConstant(InstanceConstant node) => defaultConstant(node);
+ R visitPartialInstantiationConstant(PartialInstantiationConstant node) =>
+ defaultConstant(node);
R visitTearOffConstant(TearOffConstant node) => defaultConstant(node);
R visitTypeLiteralConstant(TypeLiteralConstant node) => defaultConstant(node);
@@ -359,6 +363,9 @@
defaultConstantReference(node);
R visitInstanceConstantReference(InstanceConstant node) =>
defaultConstantReference(node);
+ R visitPartialInstantiationConstantReference(
+ PartialInstantiationConstant node) =>
+ defaultConstantReference(node);
R visitTearOffConstantReference(TearOffConstant node) =>
defaultConstantReference(node);
R visitTypeLiteralConstantReference(TypeLiteralConstant node) =>
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 2ae5e58..7b88bf2 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -150,6 +150,25 @@
analyzer/test/*: Skip # Issue 26813
analyzer/tool/*: Skip # Issue 26813
+# ILLEGAL_ASYNC_RETURN_TYPE warnings appear on some subset of Linux configurations,
+# but do not always fail.
+[ $compiler == dart2analyzer && $system == linux && !$preview_dart_2 && !$strong ]
+analyzer/test/src/dart/ast/ast_test: StaticWarning, Pass
+analyzer/test/src/summary/expr_builder_test: StaticWarning, Pass
+analyzer/test/src/summary/resynthesize_ast_test: StaticWarning, Pass
+analyzer/test/src/summary/resynthesize_kernel_test: StaticWarning, Pass
+front_end/test/incremental_dart2js_load_from_dill_test: StaticWarning, Pass
+front_end/test/incremental_load_from_dill_test: StaticWarning, Pass
+
+# ILLEGAL_ASYNC_RETURN_TYPE warnings
+[ $compiler == dart2analyzer && !$preview_dart_2 && !$strong && ($system == macos || $system == windows) ]
+analyzer/test/src/dart/ast/ast_test: StaticWarning
+analyzer/test/src/summary/expr_builder_test: StaticWarning
+analyzer/test/src/summary/resynthesize_ast_test: StaticWarning
+analyzer/test/src/summary/resynthesize_kernel_test: StaticWarning
+front_end/test/incremental_dart2js_load_from_dill_test: StaticWarning
+front_end/test/incremental_load_from_dill_test: StaticWarning
+
# Don't analyze tests in strong mode yet
[ $compiler == dart2analyzer && $strong ]
*: Skip # Issue 28649
@@ -214,9 +233,6 @@
analyzer/test/src/summary/resynthesize_ast_test: Pass, Slow
analyzer/test/src/task/strong/front_end_inference_test: Pass, Slow
-[ $runtime == vm && $use_sdk ]
-kernel/test/metadata_test: Skip # Issue 31900
-
# Timeout. These tests do not run efficiently on our simulator or low-end
# devices.
[ $runtime == vm && ($arch == armv5te || $arch == armv6 || $arch == simarm || $arch == simarm64 || $arch == simarmv5te || $arch == simarmv6 || $arch == simdbc64) ]
diff --git a/pkg/vm/bin/kernel_service.dart b/pkg/vm/bin/kernel_service.dart
index e146590..c3b0f6b 100644
--- a/pkg/vm/bin/kernel_service.dart
+++ b/pkg/vm/bin/kernel_service.dart
@@ -49,14 +49,10 @@
// 1 - Update in-memory file system with in-memory sources (used by tests).
// 2 - Accept last compilation result.
// 3 - APP JIT snapshot training run for kernel_service.
-// 4 - Allows for `dart:_internal` to be imported (used by tests).
const int kCompileTag = 0;
const int kUpdateSourcesTag = 1;
const int kAcceptTag = 2;
const int kTrainTag = 3;
-const int kAllowDartInternalImportTag = 4;
-
-bool allowDartInternalImport = false;
abstract class Compiler {
final FileSystem fileSystem;
@@ -80,16 +76,13 @@
print("DFE: platformKernelPath: ${platformKernelPath}");
print("DFE: strongMode: ${strongMode}");
print("DFE: syncAsync: ${syncAsync}");
- print("DFE: allowDartInternalImport: ${allowDartInternalImport}");
}
options = new CompilerOptions()
..strongMode = strongMode
..fileSystem = fileSystem
- ..target = new VmTarget(new TargetFlags(
- strongMode: strongMode,
- syncAsync: syncAsync,
- allowDartInternalImport: allowDartInternalImport))
+ ..target = new VmTarget(
+ new TargetFlags(strongMode: strongMode, syncAsync: syncAsync))
..packagesFileUri = packagesUri
..sdkSummary = platformKernelPath
..verbose = verbose
@@ -101,7 +94,7 @@
case Severity.internalProblem:
// TODO(sigmund): support emitting code with errors as long as they
// are handled in the generated code (issue #30194).
- printMessage = true;
+ printMessage = false; // errors are printed by VM
errors.add(message.formatted);
break;
case Severity.nit:
@@ -288,15 +281,6 @@
}
port.send(new CompilationResult.ok(null).toResponse());
return;
- } else if (tag == kAllowDartInternalImportTag) {
- compiler = lookupIncrementalCompiler(isolateId);
- assert(
- lookupIncrementalCompiler(isolateId) == null,
- "allowDartInternalImport must be set before creating a compiler"
- " instance.");
- allowDartInternalImport = true;
- port.send(new CompilationResult.ok(null).toResponse());
- return;
}
// script should only be null for kUpdateSourcesTag.
@@ -332,8 +316,6 @@
Component component = await compiler.compile(script);
if (compiler.errors.isNotEmpty) {
- // TODO(sigmund): the compiler prints errors to the console, so we
- // shouldn't print those messages again here.
result = new CompilationResult.errors(compiler.errors);
} else {
// We serialize the component excluding vm_platform.dill because the VM has
diff --git a/pkg/vm/lib/bytecode/constant_pool.dart b/pkg/vm/lib/bytecode/constant_pool.dart
index 770ff55..25da76d 100644
--- a/pkg/vm/lib/bytecode/constant_pool.dart
+++ b/pkg/vm/lib/bytecode/constant_pool.dart
@@ -17,6 +17,8 @@
List<ConstantPoolEntry>
}
+type ConstantIndex = UInt;
+
abstract type ConstantPoolEntry {
Byte tag;
}
@@ -57,13 +59,13 @@
type ConstantICData extends ConstantPoolEntry {
Byte tag = 7;
StringReference targetName;
- UInt argDescConstantIndex;
+ ConstantIndex argDesc;
}
type ConstantStaticICData extends ConstantPoolEntry {
Byte tag = 8;
CanonicalNameReference target;
- UInt argDescConstantIndex;
+ ConstantIndex argDesc;
}
type ConstantField extends ConstantPoolEntry {
@@ -104,14 +106,14 @@
type ConstantList extends ConstantPoolEntry {
Byte tag = 16;
NodeReference typeArg;
- List<UInt> entries;
+ List<ConstantIndex> entries;
}
type ConstantInstance extends ConstantPoolEntry {
Byte tag = 17;
CanonicalNameReference class;
UInt typeArgumentsConstantIndex;
- List<Pair<CanonicalNameReference, UInt>> fieldValues;
+ List<Pair<CanonicalNameReference, ConstantIndex>> fieldValues;
}
type ConstantSymbol extends ConstantPoolEntry {
@@ -119,6 +121,12 @@
StringReference value;
}
+type ConstantTypeArgumentsForInstanceAllocation extends ConstantPoolEntry {
+ Byte tag = 19;
+ CanonicalNameReference instantiatingClass;
+ ConstantIndex typeArguments;
+}
+
*/
enum ConstantTag {
@@ -141,6 +149,7 @@
kList,
kInstance,
kSymbol,
+ kTypeArgumentsForInstanceAllocation,
}
abstract class ConstantPoolEntry {
@@ -196,6 +205,9 @@
return new ConstantInstance.readFromBinary(source);
case ConstantTag.kSymbol:
return new ConstantSymbol.readFromBinary(source);
+ case ConstantTag.kTypeArgumentsForInstanceAllocation:
+ return new ConstantTypeArgumentsForInstanceAllocation.readFromBinary(
+ source);
}
throw 'Unexpected constant tag $tag';
}
@@ -798,6 +810,49 @@
other is ConstantSymbol && this.value == other.value;
}
+class ConstantTypeArgumentsForInstanceAllocation extends ConstantPoolEntry {
+ final Reference _instantiatingClassRef;
+ final int _typeArgumentsConstantIndex;
+
+ Class get instantiatingClass => _instantiatingClassRef.asClass;
+
+ ConstantTypeArgumentsForInstanceAllocation(
+ Class instantiatingClass, int typeArgumentsConstantIndex)
+ : this.byReference(
+ instantiatingClass.reference, typeArgumentsConstantIndex);
+ ConstantTypeArgumentsForInstanceAllocation.byReference(
+ this._instantiatingClassRef, this._typeArgumentsConstantIndex);
+
+ @override
+ ConstantTag get tag => ConstantTag.kTypeArgumentsForInstanceAllocation;
+
+ @override
+ void writeValueToBinary(BinarySink sink) {
+ sink.writeCanonicalNameReference(
+ getCanonicalNameOfClass(instantiatingClass));
+ sink.writeUInt30(_typeArgumentsConstantIndex);
+ }
+
+ ConstantTypeArgumentsForInstanceAllocation.readFromBinary(BinarySource source)
+ : _instantiatingClassRef =
+ source.readCanonicalNameReference().getReference(),
+ _typeArgumentsConstantIndex = source.readUInt();
+
+ @override
+ String toString() =>
+ 'TypeArgumentsForInstanceAllocation $instantiatingClass type-args CP#$_typeArgumentsConstantIndex';
+
+ @override
+ int get hashCode =>
+ instantiatingClass.hashCode * 31 + _typeArgumentsConstantIndex;
+
+ @override
+ bool operator ==(other) =>
+ other is ConstantTypeArgumentsForInstanceAllocation &&
+ this.instantiatingClass == other.instantiatingClass &&
+ this._typeArgumentsConstantIndex == other._typeArgumentsConstantIndex;
+}
+
class ConstantPool {
final List<ConstantPoolEntry> entries = <ConstantPoolEntry>[];
final Map<ConstantPoolEntry, int> _canonicalizationCache =
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index 1fd4ebe..3763ecc 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -10,7 +10,6 @@
import 'package:kernel/library_index.dart' show LibraryIndex;
import 'package:kernel/transformations/constants.dart'
show ConstantEvaluator, ConstantsBackend, EvaluationEnvironment;
-import 'package:kernel/type_algebra.dart' show Substitution;
import 'package:kernel/type_environment.dart' show TypeEnvironment;
import 'package:kernel/vm/constants_native_effects.dart'
show VmConstantsBackend;
@@ -165,7 +164,6 @@
asm.emitPush(locals.thisVarIndex);
initializer.accept(this);
- // TODO(alexmarkov): field guards?
// TODO(alexmarkov): assignability check
final int cpIndex = cp.add(new ConstantFieldOffset(field));
@@ -240,20 +238,28 @@
return function != null && function.typeParameters.isNotEmpty;
}
- void _genTypeArguments(List<DartType> typeArgs) {
- final int typeArgsCPIndex = cp.add(new ConstantTypeArguments(typeArgs));
+ void _genTypeArguments(List<DartType> typeArgs, {Class instantiatingClass}) {
+ int typeArgsCPIndex = cp.add(new ConstantTypeArguments(typeArgs));
+ if (instantiatingClass != null) {
+ typeArgsCPIndex = cp.add(new ConstantTypeArgumentsForInstanceAllocation(
+ instantiatingClass, typeArgsCPIndex));
+ }
if (typeArgs.isEmpty || !hasTypeParameters(typeArgs)) {
asm.emitPushConstant(typeArgsCPIndex);
} else {
// TODO(alexmarkov): try to reuse instantiator type arguments
- // TODO(alexmarkov): do not load instantiator type arguments / function type
- // arguments if they are not needed for these particular [typeArgs].
- _genPushInstantiatorTypeArguments();
- _genPushFunctionTypeArguments();
+ _genPushInstantiatorAndFunctionTypeArguments(typeArgs);
asm.emitInstantiateTypeArgumentsTOS(1, typeArgsCPIndex);
}
}
+ void _genPushInstantiatorAndFunctionTypeArguments(List<DartType> types) {
+ // TODO(alexmarkov): do not load instantiator type arguments / function type
+ // arguments if they are not needed for these particular [types].
+ _genPushInstantiatorTypeArguments();
+ _genPushFunctionTypeArguments();
+ }
+
void _genPushInstantiatorTypeArguments() {
// TODO(alexmarkov): access from closures to up-level type arguments.
if ((enclosingMember.isInstanceMember || enclosingMember is Constructor) &&
@@ -276,24 +282,6 @@
}
}
- List<DartType> _flattenTypeArgumentsForInstantiation(
- Class instantiatedClass, List<DartType> typeArgs) {
- assert(typeArgs.length == instantiatedClass.typeParameters.length);
-
- List<DartType> flatTypeArgs;
- final supertype = instantiatedClass.supertype;
- if (supertype == null) {
- flatTypeArgs = <DartType>[];
- } else {
- final substitution =
- Substitution.fromPairs(instantiatedClass.typeParameters, typeArgs);
- flatTypeArgs = _flattenTypeArgumentsForInstantiation(supertype.classNode,
- substitution.substituteSupertype(supertype).typeArguments);
- }
- flatTypeArgs.addAll(typeArgs);
- return flatTypeArgs;
- }
-
/// Generates bool condition. Returns `true` if condition is negated.
bool _genCondition(Node condition) {
bool negated = false;
@@ -415,10 +403,7 @@
return;
}
if (hasTypeParameters([node.type])) {
- // TODO(alexmarkov): do not load instantiator type arguments / function
- // type arguments if they are not needed for this particular type.
- _genPushInstantiatorTypeArguments();
- _genPushFunctionTypeArguments();
+ _genPushInstantiatorAndFunctionTypeArguments([node.type]);
} else {
_genPushNull(); // Instantiator type arguments.
_genPushNull(); // Function type arguments.
@@ -480,9 +465,8 @@
final classIndex = cp.add(new ConstantClass(constructedClass));
if (hasInstantiatorTypeArguments(constructedClass)) {
- List<DartType> flatTypeArgs = _flattenTypeArgumentsForInstantiation(
- constructedClass, node.arguments.types);
- _genTypeArguments(flatTypeArgs);
+ _genTypeArguments(node.arguments.types,
+ instantiatingClass: constructedClass);
asm.emitPushConstant(cp.add(new ConstantClass(constructedClass)));
asm.emitAllocateT();
} else {
@@ -540,10 +524,7 @@
// TODO(alexmarkov): generate _simpleInstanceOf if possible
if (hasTypeParameters([node.type])) {
- // TODO(alexmarkov): do not load instantiator type arguments / function type
- // arguments if they are not needed for this particular type.
- _genPushInstantiatorTypeArguments();
- _genPushFunctionTypeArguments();
+ _genPushInstantiatorAndFunctionTypeArguments([node.type]);
} else {
_genPushNull(); // Instantiator type arguments.
_genPushNull(); // Function type arguments.
@@ -873,10 +854,7 @@
if (!hasTypeParameters([type])) {
asm.emitPushConstant(typeCPIndex);
} else {
- // TODO(alexmarkov): do not load instantiator type arguments / function type
- // arguments if they are not needed for this particular [type].
- _genPushInstantiatorTypeArguments();
- _genPushFunctionTypeArguments();
+ _genPushInstantiatorAndFunctionTypeArguments([type]);
asm.emitInstantiateType(typeCPIndex);
}
}
diff --git a/pkg/vm/testcases/bytecode/instance_creation.dart.expect b/pkg/vm/testcases/bytecode/instance_creation.dart.expect
index e4dca47..b026f3c0 100644
--- a/pkg/vm/testcases/bytecode/instance_creation.dart.expect
+++ b/pkg/vm/testcases/bytecode/instance_creation.dart.expect
@@ -216,39 +216,41 @@
Bytecode {
Entry 2
CheckStack
- PushConstant CP#1
+ PushConstant CP#2
PushConstant CP#0
AllocateT
StoreLocal r0
Push r0
- PushConstant CP#2
- PushConstant CP#4
- IndirectStaticCall 2, CP#3
- Drop1
- Drop1
- PushConstant CP#6
+ PushConstant CP#3
PushConstant CP#5
+ IndirectStaticCall 2, CP#4
+ Drop1
+ Drop1
+ PushConstant CP#8
+ PushConstant CP#6
AllocateT
StoreLocal r1
Push r1
- PushConstant CP#8
- IndirectStaticCall 1, CP#7
+ PushConstant CP#10
+ IndirectStaticCall 1, CP#9
Drop1
Drop1
- PushConstant CP#9
+ PushConstant CP#11
ReturnTOS
}
ConstantPool {
[0] = Class #lib::A
- [1] = TypeArgs [dart.core::int, dart.core::String]
- [2] = String 'hi'
- [3] = ArgDesc num-args 2, num-type-args 0, names []
- [4] = StaticICData target '#lib::A::', arg-desc CP#3
- [5] = Class #lib::B
- [6] = TypeArgs [dart.core::List<dart.core::int>, dart.core::String, dart.core::int]
- [7] = ArgDesc num-args 1, num-type-args 0, names []
- [8] = StaticICData target '#lib::B::', arg-desc CP#7
- [9] = Null
+ [1] = TypeArgs []
+ [2] = TypeArgumentsForInstanceAllocation #lib::A type-args CP#1
+ [3] = String 'hi'
+ [4] = ArgDesc num-args 2, num-type-args 0, names []
+ [5] = StaticICData target '#lib::A::', arg-desc CP#4
+ [6] = Class #lib::B
+ [7] = TypeArgs [dart.core::int]
+ [8] = TypeArgumentsForInstanceAllocation #lib::B type-args CP#7
+ [9] = ArgDesc num-args 1, num-type-args 0, names []
+ [10] = StaticICData target '#lib::B::', arg-desc CP#9
+ [11] = Null
}
]static method foo2() → void {
new self::A::•("hi");
@@ -258,26 +260,27 @@
Bytecode {
Entry 1
CheckStack
- PushConstant CP#2
+ PushConstant CP#3
Push FP[-5]
- InstantiateTypeArgumentsTOS 1, CP#1
+ InstantiateTypeArgumentsTOS 1, CP#2
PushConstant CP#0
AllocateT
StoreLocal r0
Push r0
- PushConstant CP#4
- IndirectStaticCall 1, CP#3
+ PushConstant CP#5
+ IndirectStaticCall 1, CP#4
Drop1
Drop1
- PushConstant CP#2
+ PushConstant CP#3
ReturnTOS
}
ConstantPool {
[0] = Class #lib::B
- [1] = TypeArgs [dart.core::List<dart.core::List<#lib::foo3::T>>, dart.core::String, dart.core::List<#lib::foo3::T>]
- [2] = Null
- [3] = ArgDesc num-args 1, num-type-args 0, names []
- [4] = StaticICData target '#lib::B::', arg-desc CP#3
+ [1] = TypeArgs [dart.core::List<#lib::foo3::T>]
+ [2] = TypeArgumentsForInstanceAllocation #lib::B type-args CP#1
+ [3] = Null
+ [4] = ArgDesc num-args 1, num-type-args 0, names []
+ [5] = StaticICData target '#lib::B::', arg-desc CP#4
}
]static method foo3<T extends core::Object>() → void {
new self::B::•<core::List<self::foo3::T>>();
diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn
index 6fd1c76..585562d 100644
--- a/runtime/BUILD.gn
+++ b/runtime/BUILD.gn
@@ -197,7 +197,7 @@
if (defined(invoker.extra_deps)) {
extra_deps += invoker.extra_deps
}
- static_library(target_name) {
+ target(dart_component_kind, target_name) {
configs += [
":dart_arch_config",
":dart_config",
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index 0d475e9..7e9725e 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -10,6 +10,7 @@
#include <string.h>
#include <cstdarg>
+#include <memory>
#include "bin/builtin.h"
#include "bin/console.h"
@@ -144,6 +145,8 @@
V(vm_snapshot_instructions, vm_snapshot_instructions_filename) \
V(isolate_snapshot_data, isolate_snapshot_data_filename) \
V(isolate_snapshot_instructions, isolate_snapshot_instructions_filename) \
+ V(shared_data, shared_data_filename) \
+ V(shared_instructions, shared_instructions_filename) \
V(assembly, assembly_filename) \
V(script_snapshot, script_snapshot_filename) \
V(dependencies, dependencies_filename) \
@@ -1217,6 +1220,30 @@
}
}
+static std::unique_ptr<MappedMemory> MapFile(const char* filename,
+ File::MapType type,
+ const uint8_t** buffer) {
+ File* file = File::Open(NULL, filename, File::kRead);
+ if (file == NULL) {
+ Log::PrintErr("Failed to open: %s\n", filename);
+ exit(kErrorExitCode);
+ }
+ RefCntReleaseScope<File> rs(file);
+ intptr_t length = file->Length();
+ if (length == 0) {
+ // Can't map an empty file.
+ *buffer = NULL;
+ return NULL;
+ }
+ MappedMemory* mapping = file->Map(type, 0, length);
+ if (mapping == NULL) {
+ Log::PrintErr("Failed to read: %s\n", filename);
+ exit(kErrorExitCode);
+ }
+ *buffer = reinterpret_cast<const uint8_t*>(mapping->address());
+ return std::unique_ptr<MappedMemory>(mapping);
+}
+
static void CreateAndWritePrecompiledSnapshot(
Dart_QualifiedFunctionName* standalone_entry_points) {
ASSERT(IsSnapshottingForPrecompilation());
@@ -1237,6 +1264,19 @@
} else {
ASSERT(snapshot_kind == kAppAOTBlobs);
+ const uint8_t* shared_data = NULL;
+ const uint8_t* shared_instructions = NULL;
+ std::unique_ptr<MappedMemory> mapped_shared_data;
+ std::unique_ptr<MappedMemory> mapped_shared_instructions;
+ if (shared_data_filename != NULL) {
+ mapped_shared_data =
+ MapFile(shared_data_filename, File::kReadOnly, &shared_data);
+ }
+ if (shared_instructions_filename != NULL) {
+ mapped_shared_instructions = MapFile(
+ shared_instructions_filename, File::kReadOnly, &shared_instructions);
+ }
+
uint8_t* vm_snapshot_data_buffer = NULL;
intptr_t vm_snapshot_data_size = 0;
uint8_t* vm_snapshot_instructions_buffer = NULL;
@@ -1250,7 +1290,7 @@
&vm_snapshot_instructions_buffer, &vm_snapshot_instructions_size,
&isolate_snapshot_data_buffer, &isolate_snapshot_data_size,
&isolate_snapshot_instructions_buffer,
- &isolate_snapshot_instructions_size);
+ &isolate_snapshot_instructions_size, shared_data, shared_instructions);
CHECK_RESULT(result);
WriteFile(vm_snapshot_data_filename, vm_snapshot_data_buffer,
@@ -1319,7 +1359,7 @@
new IsolateData(script_uri, package_root, package_config, NULL);
Dart_Isolate isolate = NULL;
isolate = Dart_CreateIsolate(script_uri, main, isolate_snapshot_data,
- isolate_snapshot_instructions, flags,
+ isolate_snapshot_instructions, NULL, NULL, flags,
isolate_data, error);
if (isolate == NULL) {
@@ -1355,30 +1395,6 @@
return isolate;
}
-static MappedMemory* MapFile(const char* filename,
- File::MapType type,
- const uint8_t** buffer) {
- File* file = File::Open(NULL, filename, File::kRead);
- if (file == NULL) {
- Log::PrintErr("Failed to open: %s\n", filename);
- exit(kErrorExitCode);
- }
- RefCntReleaseScope<File> rs(file);
- intptr_t length = file->Length();
- if (length == 0) {
- // Can't map an empty file.
- *buffer = NULL;
- return NULL;
- }
- MappedMemory* mapping = file->Map(type, 0, length);
- if (mapping == NULL) {
- Log::PrintErr("Failed to read: %s\n", filename);
- exit(kErrorExitCode);
- }
- *buffer = reinterpret_cast<const uint8_t*>(mapping->address());
- return mapping;
-}
-
static int GenerateSnapshotFromKernelProgram(void* kernel_program) {
ASSERT(SnapshotKindAllowedFromKernel());
@@ -1538,10 +1554,10 @@
init_params.entropy_source = DartUtils::EntropySource;
init_params.start_kernel_isolate = false;
- MappedMemory* mapped_vm_snapshot_data = NULL;
- MappedMemory* mapped_vm_snapshot_instructions = NULL;
- MappedMemory* mapped_isolate_snapshot_data = NULL;
- MappedMemory* mapped_isolate_snapshot_instructions = NULL;
+ std::unique_ptr<MappedMemory> mapped_vm_snapshot_data;
+ std::unique_ptr<MappedMemory> mapped_vm_snapshot_instructions;
+ std::unique_ptr<MappedMemory> mapped_isolate_snapshot_data;
+ std::unique_ptr<MappedMemory> mapped_isolate_snapshot_instructions;
if (snapshot_kind == kScript) {
mapped_vm_snapshot_data =
MapFile(vm_snapshot_data_filename, File::kReadOnly,
@@ -1585,7 +1601,7 @@
commandline_packages_file, NULL);
Dart_Isolate isolate = Dart_CreateIsolate(NULL, NULL, isolate_snapshot_data,
isolate_snapshot_instructions, NULL,
- isolate_data, &error);
+ NULL, NULL, isolate_data, &error);
if (isolate == NULL) {
Log::PrintErr("Error: %s\n", error);
free(error);
@@ -1652,8 +1668,8 @@
Dart_Isolate isolate = NULL;
isolate = Dart_CreateIsolate(NULL, NULL, isolate_snapshot_data,
- isolate_snapshot_instructions, &flags,
- isolate_data, &error);
+ isolate_snapshot_instructions, NULL, NULL,
+ &flags, isolate_data, &error);
if (isolate == NULL) {
Log::PrintErr("%s\n", error);
free(error);
@@ -1744,10 +1760,6 @@
free(error);
}
EventHandler::Stop();
- delete mapped_vm_snapshot_data;
- delete mapped_vm_snapshot_instructions;
- delete mapped_isolate_snapshot_data;
- delete mapped_isolate_snapshot_instructions;
return 0;
}
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index d8bbc6f..36e3a24 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -87,6 +87,8 @@
static char* app_script_uri = NULL;
static const uint8_t* app_isolate_snapshot_data = NULL;
static const uint8_t* app_isolate_snapshot_instructions = NULL;
+static const uint8_t* app_isolate_shared_data = NULL;
+static const uint8_t* app_isolate_shared_instructions = NULL;
static Dart_Isolate main_isolate = NULL;
@@ -373,7 +375,8 @@
new IsolateData(uri, package_root, packages_config, app_snapshot);
isolate = Dart_CreateIsolate(
DART_KERNEL_ISOLATE_NAME, main, isolate_snapshot_data,
- isolate_snapshot_instructions, flags, isolate_data, error);
+ isolate_snapshot_instructions, app_isolate_shared_data,
+ app_isolate_shared_instructions, flags, isolate_data, error);
} else {
void* kernel_service_program = dfe.LoadKernelServiceProgram();
ASSERT(kernel_service_program != NULL);
@@ -424,9 +427,10 @@
IsolateData* isolate_data =
new IsolateData(script_uri, package_root, packages_config, NULL);
#if defined(DART_PRECOMPILED_RUNTIME)
- isolate = Dart_CreateIsolate(script_uri, main, isolate_snapshot_data,
- isolate_snapshot_instructions, flags,
- isolate_data, error);
+ isolate = Dart_CreateIsolate(
+ script_uri, main, isolate_snapshot_data, isolate_snapshot_instructions,
+ app_isolate_shared_data, app_isolate_shared_instructions, flags,
+ isolate_data, error);
#else
// Set the flag to load the vmservice library. If not set, the kernel
// loader might skip loading it. This is flag is not relevant for the
@@ -454,9 +458,10 @@
}
skip_library_load = true;
} else {
- isolate = Dart_CreateIsolate(script_uri, main, isolate_snapshot_data,
- isolate_snapshot_instructions, flags,
- isolate_data, error);
+ isolate = Dart_CreateIsolate(
+ script_uri, main, isolate_snapshot_data, isolate_snapshot_instructions,
+ app_isolate_shared_data, app_isolate_shared_instructions, flags,
+ isolate_data, error);
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
if (isolate == NULL) {
@@ -583,9 +588,10 @@
} else {
#endif // !defined(DART_PRECOMPILED_RUNTIME)
- isolate = Dart_CreateIsolate(script_uri, main, isolate_snapshot_data,
- isolate_snapshot_instructions, flags,
- isolate_data, error);
+ isolate = Dart_CreateIsolate(
+ script_uri, main, isolate_snapshot_data, isolate_snapshot_instructions,
+ app_isolate_shared_data, app_isolate_shared_instructions, flags,
+ isolate_data, error);
#if !defined(DART_PRECOMPILED_RUNTIME)
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
@@ -714,7 +720,9 @@
static void GenerateAppAOTSnapshot() {
if (Options::use_blobs()) {
- Snapshot::GenerateAppAOTAsBlobs(Options::snapshot_filename());
+ Snapshot::GenerateAppAOTAsBlobs(Options::snapshot_filename(),
+ app_isolate_shared_data,
+ app_isolate_shared_instructions);
} else {
Snapshot::GenerateAppAOTAsAssembly(Options::snapshot_filename());
}
@@ -1076,6 +1084,19 @@
app_isolate_snapshot_data = _kDartIsolateSnapshotData;
app_isolate_snapshot_instructions = _kDartIsolateSnapshotInstructions;
#else
+ AppSnapshot* shared_blobs = NULL;
+ if (Options::shared_blobs_filename() != NULL) {
+ Log::PrintErr("Shared blobs in the standalone VM are for testing only.\n");
+ shared_blobs =
+ Snapshot::TryReadAppSnapshot(Options::shared_blobs_filename());
+ if (shared_blobs == NULL) {
+ Log::PrintErr("Failed to load: %s\n", Options::shared_blobs_filename());
+ Platform::Exit(kErrorExitCode);
+ }
+ const uint8_t* ignored;
+ shared_blobs->SetBuffers(&ignored, &ignored, &app_isolate_shared_data,
+ &app_isolate_shared_instructions);
+ }
AppSnapshot* app_snapshot = Snapshot::TryReadAppSnapshot(script_name);
if (app_snapshot != NULL) {
vm_run_app_snapshot = true;
@@ -1181,6 +1202,7 @@
#if !defined(DART_LINK_APP_SNAPSHOT)
delete app_snapshot;
+ delete shared_blobs;
#endif
free(app_script_uri);
diff --git a/runtime/bin/main_options.h b/runtime/bin/main_options.h
index 80a4579..d4b46d8 100644
--- a/runtime/bin/main_options.h
+++ b/runtime/bin/main_options.h
@@ -21,6 +21,7 @@
V(package_root, package_root) \
V(snapshot, snapshot_filename) \
V(snapshot_depfile, snapshot_deps_filename) \
+ V(shared_blobs, shared_blobs_filename) \
V(save_obfuscation_map, obfuscation_map_filename) \
V(save_compilation_trace, save_compilation_trace_filename) \
V(load_compilation_trace, load_compilation_trace_filename) \
diff --git a/runtime/bin/run_vm_tests.cc b/runtime/bin/run_vm_tests.cc
index 6446440..8293434 100644
--- a/runtime/bin/run_vm_tests.cc
+++ b/runtime/bin/run_vm_tests.cc
@@ -163,7 +163,7 @@
script_uri, package_root, packages_config, app_snapshot);
Dart_Isolate isolate = Dart_CreateIsolate(
DART_KERNEL_ISOLATE_NAME, main, isolate_snapshot_data,
- isolate_snapshot_instructions, flags, isolate_data, error);
+ isolate_snapshot_instructions, NULL, NULL, flags, isolate_data, error);
if (isolate == NULL) {
delete isolate_data;
return NULL;
diff --git a/runtime/bin/snapshot_utils.cc b/runtime/bin/snapshot_utils.cc
index 999cbe0..dfceb0e 100644
--- a/runtime/bin/snapshot_utils.cc
+++ b/runtime/bin/snapshot_utils.cc
@@ -360,7 +360,9 @@
#endif
}
-void Snapshot::GenerateAppAOTAsBlobs(const char* snapshot_filename) {
+void Snapshot::GenerateAppAOTAsBlobs(const char* snapshot_filename,
+ const uint8_t* shared_data,
+ const uint8_t* shared_instructions) {
uint8_t* vm_data_buffer = NULL;
intptr_t vm_data_size = 0;
uint8_t* vm_instructions_buffer = NULL;
@@ -372,7 +374,8 @@
Dart_Handle result = Dart_CreateAppAOTSnapshotAsBlobs(
&vm_data_buffer, &vm_data_size, &vm_instructions_buffer,
&vm_instructions_size, &isolate_data_buffer, &isolate_data_size,
- &isolate_instructions_buffer, &isolate_instructions_size);
+ &isolate_instructions_buffer, &isolate_instructions_size, shared_data,
+ shared_instructions);
if (Dart_IsError(result)) {
ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result));
}
diff --git a/runtime/bin/snapshot_utils.h b/runtime/bin/snapshot_utils.h
index 758b386..8b74821 100644
--- a/runtime/bin/snapshot_utils.h
+++ b/runtime/bin/snapshot_utils.h
@@ -30,7 +30,9 @@
public:
static void GenerateScript(const char* snapshot_filename);
static void GenerateAppJIT(const char* snapshot_filename);
- static void GenerateAppAOTAsBlobs(const char* snapshot_filename);
+ static void GenerateAppAOTAsBlobs(const char* snapshot_filename,
+ const uint8_t* shared_data,
+ const uint8_t* shared_instructions);
static void GenerateAppAOTAsAssembly(const char* snapshot_filename);
static AppSnapshot* TryReadAppSnapshot(const char* script_name);
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 05ac9d1..1e9e8e1 100644
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -850,6 +850,8 @@
const char* main,
const uint8_t* isolate_snapshot_data,
const uint8_t* isolate_snapshot_instructions,
+ const uint8_t* shared_data,
+ const uint8_t* shared_instructions,
Dart_IsolateFlags* flags,
void* callback_data,
char** error);
@@ -3307,7 +3309,9 @@
uint8_t** isolate_snapshot_data_buffer,
intptr_t* isolate_snapshot_data_size,
uint8_t** isolate_snapshot_instructions_buffer,
- intptr_t* isolate_snapshot_instructions_size);
+ intptr_t* isolate_snapshot_instructions_size,
+ const uint8_t* shared_data,
+ const uint8_t* shared_instructions);
/**
* Sorts the class-ids in depth first traversal order of the inheritance
@@ -3380,6 +3384,10 @@
/**
* Print a native stack trace. Used for crash handling.
+ *
+ * If context is NULL, prints the current stack trace. Otherwise, context
+ * should be a CONTEXT* (Windows) or ucontext_t* (POSIX) from a signal handler
+ * running on the current thread.
*/
DART_EXPORT void Dart_DumpNativeStackTrace(void* context);
diff --git a/runtime/lib/compact_hash.dart b/runtime/lib/compact_hash.dart
index 82bc532..6f55f41 100644
--- a/runtime/lib/compact_hash.dart
+++ b/runtime/lib/compact_hash.dart
@@ -78,19 +78,14 @@
static const int _UNUSED_PAIR = 0;
static const int _DELETED_PAIR = 1;
- // On 32-bit, the top bits are wasted to avoid Mint allocation.
- // TODO(koda): Reclaim the bits by making the compiler treat hash patterns
- // as unsigned words.
+ // The top bits are wasted to avoid Mint allocation.
static int _indexSizeToHashMask(int indexSize) {
int indexBits = indexSize.bitLength - 2;
- return internal.is64Bit
- ? (1 << (32 - indexBits)) - 1
- : (1 << (30 - indexBits)) - 1;
+ return (1 << (30 - indexBits)) - 1;
}
static int _hashPattern(int fullHash, int hashMask, int size) {
final int maskedHash = fullHash & hashMask;
- // TODO(koda): Consider keeping bit length and use left shift.
return (maskedHash == 0) ? (size >> 1) : maskedHash * (size >> 1);
}
diff --git a/runtime/lib/integers_patch.dart b/runtime/lib/integers_patch.dart
index d1c13be..15598fe 100644
--- a/runtime/lib/integers_patch.dart
+++ b/runtime/lib/integers_patch.dart
@@ -32,7 +32,7 @@
return null; // Empty.
}
}
- var smiLimit = is64Bit ? 18 : 9;
+ var smiLimit = 9;
if ((last - ix) >= smiLimit) {
return null; // May not fit into a Smi.
}
@@ -133,7 +133,7 @@
static int _parseRadix(
String source, int radix, int start, int end, int sign) {
- int tableIndex = (radix - 2) * 4 + (is64Bit ? 2 : 0);
+ int tableIndex = (radix - 2) * 2;
int blockSize = _PARSE_LIMITS[tableIndex];
int length = end - start;
if (length <= blockSize) {
@@ -159,7 +159,7 @@
int positiveOverflowLimit = 0;
int negativeOverflowLimit = 0;
if (_limitIntsTo64Bits) {
- tableIndex = tableIndex << 1; // pre-multiply by 2 for simpler indexing
+ tableIndex = tableIndex << 1; // Pre-multiply by 2 for simpler indexing.
positiveOverflowLimit = _int64OverflowLimits[tableIndex];
if (positiveOverflowLimit == 0) {
positiveOverflowLimit =
@@ -175,14 +175,10 @@
if (result >= positiveOverflowLimit) {
if ((result > positiveOverflowLimit) ||
(smi > _int64OverflowLimits[tableIndex + 2])) {
- // Although the unsigned overflow limits do not depend on the
- // platform, the multiplier and block size, which are used to
- // compute it, do.
- int X = is64Bit ? 1 : 0;
if (radix == 16 &&
- !(result >= _int64UnsignedOverflowLimits[X] &&
- (result > _int64UnsignedOverflowLimits[X] ||
- smi > _int64UnsignedSmiOverflowLimits[X])) &&
+ !(result >= _int64UnsignedOverflowLimit &&
+ (result > _int64UnsignedOverflowLimit ||
+ smi > _int64UnsignedSmiOverflowLimit)) &&
blockEnd + blockSize > end) {
return (result * multiplier) + smi;
}
@@ -227,43 +223,42 @@
// For each radix, 2-36, how many digits are guaranteed to fit in a smi,
// and magnitude of such a block (radix ** digit-count).
- // 32-bit limit/multiplier at (radix - 2)*4, 64-bit limit at (radix-2)*4+2
static const _PARSE_LIMITS = const [
- 30, 1073741824, 62, 4611686018427387904, // radix: 2
- 18, 387420489, 39, 4052555153018976267,
- 15, 1073741824, 30, 1152921504606846976,
- 12, 244140625, 26, 1490116119384765625, // radix: 5
- 11, 362797056, 23, 789730223053602816,
- 10, 282475249, 22, 3909821048582988049,
- 10, 1073741824, 20, 1152921504606846976,
- 9, 387420489, 19, 1350851717672992089,
- 9, 1000000000, 18, 1000000000000000000, // radix: 10
- 8, 214358881, 17, 505447028499293771,
- 8, 429981696, 17, 2218611106740436992,
- 8, 815730721, 16, 665416609183179841,
- 7, 105413504, 16, 2177953337809371136,
- 7, 170859375, 15, 437893890380859375, // radix: 15
- 7, 268435456, 15, 1152921504606846976,
- 7, 410338673, 15, 2862423051509815793,
- 7, 612220032, 14, 374813367582081024,
- 7, 893871739, 14, 799006685782884121,
- 6, 64000000, 14, 1638400000000000000, // radix: 20
- 6, 85766121, 14, 3243919932521508681,
- 6, 113379904, 13, 282810057883082752,
- 6, 148035889, 13, 504036361936467383,
- 6, 191102976, 13, 876488338465357824,
- 6, 244140625, 13, 1490116119384765625, // radix: 25
- 6, 308915776, 13, 2481152873203736576,
- 6, 387420489, 13, 4052555153018976267,
- 6, 481890304, 12, 232218265089212416,
- 6, 594823321, 12, 353814783205469041,
- 6, 729000000, 12, 531441000000000000, // radix: 30
- 6, 887503681, 12, 787662783788549761,
- 6, 1073741824, 12, 1152921504606846976,
- 5, 39135393, 12, 1667889514952984961,
- 5, 45435424, 12, 2386420683693101056,
- 5, 52521875, 12, 3379220508056640625, // radix: 35
- 5, 60466176, 11, 131621703842267136,
+ 30, 1073741824, // radix: 2
+ 18, 387420489,
+ 15, 1073741824,
+ 12, 244140625, // radix: 5
+ 11, 362797056,
+ 10, 282475249,
+ 10, 1073741824,
+ 9, 387420489,
+ 9, 1000000000, // radix: 10
+ 8, 214358881,
+ 8, 429981696,
+ 8, 815730721,
+ 7, 105413504,
+ 7, 170859375, // radix: 15
+ 7, 268435456,
+ 7, 410338673,
+ 7, 612220032,
+ 7, 893871739,
+ 6, 64000000, // radix: 20
+ 6, 85766121,
+ 6, 113379904,
+ 6, 148035889,
+ 6, 191102976,
+ 6, 244140625, // radix: 25
+ 6, 308915776,
+ 6, 387420489,
+ 6, 481890304,
+ 6, 594823321,
+ 6, 729000000, // radix: 30
+ 6, 887503681,
+ 6, 1073741824,
+ 5, 39135393,
+ 5, 45435424,
+ 5, 52521875, // radix: 35
+ 5, 60466176,
];
/// Flag indicating if integers are limited by 64 bits
@@ -273,11 +268,8 @@
static const _maxInt64 = 0x7fffffffffffffff;
static const _minInt64 = -_maxInt64 - 1;
- static const _int64UnsignedOverflowLimits = const [0xfffffffff, 0xf];
- static const _int64UnsignedSmiOverflowLimits = const [
- 0xfffffff,
- 0xfffffffffffffff
- ];
+ static const _int64UnsignedOverflowLimit = 0xfffffffff;
+ static const _int64UnsignedSmiOverflowLimit = 0xfffffff;
/// In the `--limit-ints-to-64-bits` mode calculation of the expression
///
diff --git a/runtime/observatory/BUILD.gn b/runtime/observatory/BUILD.gn
index 94f0ce0..77571e2 100644
--- a/runtime/observatory/BUILD.gn
+++ b/runtime/observatory/BUILD.gn
@@ -8,128 +8,71 @@
import("observatory_sources.gni")
# Construct arguments to the observatory tool for finding pub.
-pub_build_deps = []
-pub_build_args = []
+build_deps = []
+build_args = []
if (!prebuilt_dart_exe_works) {
- pub_build_deps += [ "../bin:dart_bootstrap($dart_host_toolchain)" ]
+ build_deps += [ "../bin:dart_bootstrap($dart_host_toolchain)" ]
dart_out_dir = get_label_info("../bin:dart_bootstrap($dart_host_toolchain)",
"root_out_dir")
dart_bootstrap = rebase_path("$dart_out_dir/dart_bootstrap$executable_suffix")
- pub_build_args = [
+ build_args = [
"--sdk=True",
"--dart-executable",
dart_bootstrap,
]
} else {
- pub_build_args = [ "--sdk=True" ]
+ build_args = [ "--sdk=True" ]
}
current_dir = rebase_path(".", "//")
-# Helper build rules for packaging the Dart observatory resources.
-copy("copy_observatory") {
+action("build_observatory") {
+ deps = build_deps
+
sources = rebase_path(observatory_sources, "", ".")
- outputs = [
- "$root_gen_dir/observatory_copy/{{source_root_relative_dir}}/{{source_file_part}}",
- ]
-}
-action("write_observatory_pubspec_yaml") {
- deps = [ ":copy_observatory" ] + pub_build_deps
-
- inputs = [
- rebase_path("pubspec.yaml"),
- ]
+ inputs = sources + [ rebase_path("dart2js.packages") ]
script = "../../tools/observatory_tool.py"
- args =
- pub_build_args + [
- "--silent=True",
- "--directory",
- rebase_path("$root_gen_dir/observatory_copy/$current_dir/"),
- "--command",
- "rewrite",
- rebase_path("../observatory/pubspec.yaml"),
- rebase_path("$root_gen_dir/observatory_copy/$current_dir/pubspec.yaml"),
- "../../third_party/",
- rebase_path("../../third_party/"),
- ]
-
- outputs = [
- "$root_gen_dir/observatory_copy/$current_dir/pubspec.yaml",
- ]
-}
-
-action("copy_observatory_deps") {
- deps = [ ":write_observatory_pubspec_yaml" ] + pub_build_deps
-
- inputs = [
- "$root_gen_dir/observatory_copy/$current_dir/pubspec.yaml",
- ]
-
- script = "../../tools/observatory_tool.py"
- args = pub_build_args + [
- "--silent=True",
- "--stamp",
- rebase_path(
- "$root_gen_dir/observatory_copy/$current_dir/packages.stamp"),
- "--directory",
- rebase_path("$root_gen_dir/observatory_copy/$current_dir/"),
- "--command",
- "get",
- ]
-
- outputs = [
- "$root_gen_dir/observatory_copy/$current_dir/packages.stamp",
- ]
-}
-
-action("pub_build_observatory") {
- deps = [
- ":copy_observatory",
- ":copy_observatory_deps",
- ] + pub_build_deps
-
- sources = rebase_path(observatory_sources,
- "",
- "$root_gen_dir/observatory_copy/$current_dir")
-
- inputs =
- sources + [ "$root_gen_dir/observatory_copy/$current_dir/packages.stamp" ]
-
- script = "../../tools/observatory_tool.py"
- args = pub_build_args + [
+ args = build_args + [
"--silent=True",
"--directory",
- rebase_path("$root_gen_dir/observatory_copy/$current_dir/"),
+ rebase_path("."),
"--command",
"build",
- rebase_path("$root_out_dir/observatory/build"),
+ rebase_path("web/main.dart"),
+ rebase_path("$root_gen_dir/observatory/web/main.dart.js"),
+ rebase_path("dart2js.packages"),
]
outputs = [
- "$root_out_dir/observatory/build/web/main.dart.js",
+ "$root_gen_dir/observatory/web/main.dart.js",
]
}
action("deploy_observatory") {
- deps = [ ":pub_build_observatory" ] + pub_build_deps
+ deps = [ ":build_observatory" ] + build_deps
script = "../../tools/observatory_tool.py"
inputs = [
script,
- "$root_out_dir/observatory/build/web/main.dart.js",
+ "$root_gen_dir/observatory/web/main.dart.js",
]
- args = pub_build_args + [
+ args = build_args + [
"--silent=True",
"--directory",
rebase_path("$root_out_dir/observatory"),
"--command",
"deploy",
+ rebase_path("$root_out_dir/observatory/deployed"),
+ rebase_path("web"),
+ rebase_path("lib"),
+ rebase_path("$root_gen_dir/observatory/web/main.dart.js"),
+ rebase_path("../../third_party/observatory_pub_packages/packages"),
]
outputs = [
diff --git a/runtime/observatory/dart2js.packages b/runtime/observatory/dart2js.packages
new file mode 100644
index 0000000..b042c03
--- /dev/null
+++ b/runtime/observatory/dart2js.packages
@@ -0,0 +1,24 @@
+# Update if observatory dependencies change
+args:../../third_party/observatory_pub_packages/packages/args/lib
+async:../../third_party/observatory_pub_packages/packages/async/lib
+barback:../../third_party/observatory_pub_packages/packages/barback/lib
+browser:../../third_party/observatory_pub_packages/packages/browser/lib
+charcode:../../third_party/observatory_pub_packages/packages/charcode/lib
+charted:../../third_party/observatory_pub_packages/packages/charted/lib
+collection:../../third_party/observatory_pub_packages/packages/collection/lib
+csslib:../../third_party/observatory_pub_packages/packages/csslib/lib
+html:../../third_party/observatory_pub_packages/packages/html/lib
+intl:../../third_party/observatory_pub_packages/packages/intl/lib
+logging:../../third_party/observatory_pub_packages/packages/logging/lib
+matcher:../../third_party/observatory_pub_packages/packages/matcher/lib
+meta:../../third_party/observatory_pub_packages/packages/meta/lib
+observable:../../third_party/observatory_pub_packages/packages/observable/lib
+path:../../third_party/observatory_pub_packages/packages/path/lib
+pool:../../third_party/observatory_pub_packages/packages/pool/lib
+quiver:../../third_party/observatory_pub_packages/packages/quiver/lib
+source_span:../../third_party/observatory_pub_packages/packages/source_span/lib
+stack_trace:../../third_party/observatory_pub_packages/packages/stack_trace/lib
+unittest:../../third_party/observatory_pub_packages/packages/unittest/lib
+usage:../../third_party/observatory_pub_packages/packages/usage/lib
+utf:../../third_party/observatory_pub_packages/packages/utf/lib
+observatory:lib/
diff --git a/runtime/observatory/pubspec.yaml b/runtime/observatory/pubspec.yaml
deleted file mode 100644
index 4ed0d1f..0000000
--- a/runtime/observatory/pubspec.yaml
+++ /dev/null
@@ -1,60 +0,0 @@
-# Generated file DO NOT EDIT
-name: observatory
-transformers:
-- dart_to_js_script_rewriter
-- $dart2js:
- suppressWarnings: false
- commandLineOptions: [--show-package-warnings]
-dependencies:
- args: ^0.13.2
- charted: ^0.4.8
- unittest: < 0.12.0
- usage: ^1.2.0
- dart_to_js_script_rewriter: 1.0.3
-dependency_overrides:
- args:
- path: ../../third_party/observatory_pub_packages/packages/args
- async:
- path: ../../third_party/observatory_pub_packages/packages/async
- barback:
- path: ../../third_party/observatory_pub_packages/packages/barback
- browser:
- path: ../../third_party/observatory_pub_packages/packages/browser
- charcode:
- path: ../../third_party/observatory_pub_packages/packages/charcode
- charted:
- path: ../../third_party/observatory_pub_packages/packages/charted
- collection:
- path: ../../third_party/observatory_pub_packages/packages/collection
- csslib:
- path: ../../third_party/observatory_pub_packages/packages/csslib
- dart_to_js_script_rewriter:
- path: ../../third_party/observatory_pub_packages/packages/dart_to_js_script_rewriter
- html:
- path: ../../third_party/observatory_pub_packages/packages/html
- intl:
- path: ../../third_party/observatory_pub_packages/packages/intl
- logging:
- path: ../../third_party/observatory_pub_packages/packages/logging
- matcher:
- path: ../../third_party/observatory_pub_packages/packages/matcher
- meta:
- path: ../../third_party/observatory_pub_packages/packages/meta
- observable:
- path: ../../third_party/observatory_pub_packages/packages/observable
- path:
- path: ../../third_party/observatory_pub_packages/packages/path
- pool:
- path: ../../third_party/observatory_pub_packages/packages/pool
- quiver:
- path: ../../third_party/observatory_pub_packages/packages/quiver
- source_span:
- path: ../../third_party/observatory_pub_packages/packages/source_span
- stack_trace:
- path: ../../third_party/observatory_pub_packages/packages/stack_trace
- unittest:
- path: ../../third_party/observatory_pub_packages/packages/unittest
- usage:
- path: ../../third_party/observatory_pub_packages/packages/usage
- utf:
- path: ../../third_party/observatory_pub_packages/packages/utf
diff --git a/runtime/observatory/tests/observatory_ui/mocks/repositories/flag.dart b/runtime/observatory/tests/observatory_ui/mocks/repositories/flag.dart
index c6755e6..578c034 100644
--- a/runtime/observatory/tests/observatory_ui/mocks/repositories/flag.dart
+++ b/runtime/observatory/tests/observatory_ui/mocks/repositories/flag.dart
@@ -9,6 +9,7 @@
bool isListInvoked = false;
Future<Iterable<M.Flag>> list() async {
+ await null;
isListInvoked = true;
return _list;
}
diff --git a/runtime/platform/assert.cc b/runtime/platform/assert.cc
index 7929b27..fb7cc88 100644
--- a/runtime/platform/assert.cc
+++ b/runtime/platform/assert.cc
@@ -4,9 +4,9 @@
#include "platform/assert.h"
+#include "include/dart_api.h"
#include "platform/globals.h"
#include "vm/os.h"
-#include "vm/profiler.h"
namespace dart {
@@ -38,7 +38,7 @@
// until the program is exiting before producing a non-zero exit
// code through abort.
if (kind_ == ASSERT) {
- NOT_IN_PRODUCT(Profiler::DumpStackTrace());
+ NOT_IN_PRODUCT(Dart_DumpNativeStackTrace(NULL));
OS::Abort();
}
failed_ = true;
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index ef225bc..10e307c 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -245,6 +245,13 @@
#error Architecture was not detected as supported by Dart.
#endif
+#if defined(TARGET_ARCH_ARM64) || defined(TARGET_ARCH_X64)
+// On 64 bit architectures the optimizing compilers should prefer unboxed int64
+// and unboxed uint32 values, which have direct support in the instruction set.
+// We avoid the unboxed signed int32 type.
+#define AVOID_UNBOXED_INT32 1
+#endif
+
// DART_FORCE_INLINE strongly hints to the compiler that a function should
// be inlined. Your function is not guaranteed to be inlined but this is
// stronger than just using "inline".
diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h
index 2917008..c717cbc 100644
--- a/runtime/platform/utils.h
+++ b/runtime/platform/utils.h
@@ -317,7 +317,7 @@
static uword NBitMask(uint32_t n) {
ASSERT(n <= kBitsPerWord);
if (n == kBitsPerWord) {
-#if defined(TARGET_ARCH_X64)
+#if defined(ARCH_IS_64_BIT)
return 0xffffffffffffffffll;
#else
return 0xffffffff;
diff --git a/runtime/runtime_args.gni b/runtime/runtime_args.gni
index 13751eb..e88807e 100644
--- a/runtime/runtime_args.gni
+++ b/runtime/runtime_args.gni
@@ -69,4 +69,12 @@
# revision. The short git hash can be omitted by setting
# dart_version_git_info=false
dart_custom_version_for_pub = ""
+
+ # Controls whether the VM is built as a static library or a shared library.
+ if (is_fuchsia) {
+ # Allow for deduping the VM between standalone, flutter_runner and dart_runner.
+ dart_component_kind = "shared_library"
+ } else {
+ dart_component_kind = "static_library"
+ }
}
diff --git a/runtime/tests/vm/dart/error_messages_in_null_checks_test.dart b/runtime/tests/vm/dart/error_messages_in_null_checks_test.dart
new file mode 100644
index 0000000..b40c5a9
--- /dev/null
+++ b/runtime/tests/vm/dart/error_messages_in_null_checks_test.dart
@@ -0,0 +1,98 @@
+// Copyright (c) 2018, 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.
+
+// This test verifies that NoSuchMethodError thrown from null checks
+// corresponding to devirtualized calls in AOT mode have detailed messages
+// (dartbug.com/32863).
+
+import "package:expect/expect.dart";
+
+class A {
+ void foo() {
+ Expect.fail('A.foo should not be reachable');
+ }
+
+ dynamic get bar {
+ Expect.fail('A.bar should not be reachable');
+ }
+
+ set bazz(int x) {
+ Expect.fail('A.bazz should not be reachable');
+ }
+}
+
+A myNull;
+double doubleNull;
+int intNull;
+
+main(List<String> args) {
+ // Make sure value of `myNull` is not a compile-time null and
+ // devirtualization happens.
+ if (args.length > 42) {
+ myNull = new A();
+ doubleNull = 3.14;
+ intNull = 2;
+ }
+
+ Expect.throws(
+ () => myNull.foo(),
+ (e) =>
+ e is NoSuchMethodError &&
+ e.toString().startsWith(
+ 'NoSuchMethodError: The method \'foo\' was called on null.'));
+
+ Expect.throws(
+ () => myNull.foo,
+ (e) =>
+ e is NoSuchMethodError &&
+ e.toString().startsWith(
+ 'NoSuchMethodError: The getter \'foo\' was called on null.'));
+
+ Expect.throws(
+ () => myNull.bar,
+ (e) =>
+ e is NoSuchMethodError &&
+ e.toString().startsWith(
+ 'NoSuchMethodError: The getter \'bar\' was called on null.'));
+
+ Expect.throws(
+ () => myNull.bar(),
+ (e) =>
+ e is NoSuchMethodError &&
+ e.toString().startsWith(
+ 'NoSuchMethodError: The method \'bar\' was called on null.'));
+
+ Expect.throws(() {
+ myNull.bazz = 3;
+ },
+ (e) =>
+ e is NoSuchMethodError &&
+ e.toString().startsWith(
+ 'NoSuchMethodError: The setter \'bazz=\' was called on null.'));
+
+ Expect.throws(
+ () => doubleNull + 2.17,
+ (e) =>
+ e is NoSuchMethodError &&
+ e.toString().startsWith(
+ 'NoSuchMethodError: The method \'+\' was called on null.'));
+
+ Expect.throws(
+ () => 9.81 - doubleNull,
+ (e) =>
+ e is NoSuchMethodError &&
+ // If '-' is specialized.
+ (e.toString().startsWith(
+ 'NoSuchMethodError: The method \'-\' was called on null.') ||
+ // If '-' is not specialized, it calls toDouble() internally.
+ e.toString().startsWith(
+ 'NoSuchMethodError: The method \'toDouble\' was called on null.')));
+
+ Expect.throws(
+ () => intNull * 7,
+ (e) =>
+ e is NoSuchMethodError &&
+ e.toString().startsWith(
+ 'NoSuchMethodError: The method \'*\' was called on null.'));
+}
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 07ba355..26c3491 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -9,12 +9,12 @@
cc/Fail0: Fail # These tests are expected to crash on all platforms.
cc/Fail1: Fail # These tests are expected to crash on all platforms.
cc/Fail2: Fail # These tests are expected to crash on all platforms.
-cc/IsolateReload_PendingConstructorCall_AbstractToConcrete: SkipSlow # Issue 28198
-cc/IsolateReload_PendingConstructorCall_ConcreteToAbstract: SkipSlow # Issue 28198
-cc/IsolateReload_PendingStaticCall_DefinedToNSM: SkipSlow # Issue 28198
-cc/IsolateReload_PendingStaticCall_NSMToDefined: SkipSlow # Issue 28198
-cc/IsolateReload_PendingUnqualifiedCall_InstanceToStatic: SkipSlow # Issue 28198
-cc/IsolateReload_PendingUnqualifiedCall_StaticToInstance: SkipSlow # Issue 28198
+cc/IsolateReload_PendingConstructorCall_AbstractToConcrete: Fail # Issue 32981
+cc/IsolateReload_PendingConstructorCall_ConcreteToAbstract: Fail # Issue 32981
+cc/IsolateReload_PendingStaticCall_DefinedToNSM: Fail # Issue 32981
+cc/IsolateReload_PendingStaticCall_NSMToDefined: Fail # Issue 32981
+cc/IsolateReload_PendingUnqualifiedCall_InstanceToStatic: Fail # Issue 32981
+cc/IsolateReload_PendingUnqualifiedCall_StaticToInstance: Fail # Issue 32981
cc/IsolateReload_RunNewFieldInitializersWithGenerics: Fail # Issue 32299
cc/Profiler_InliningIntervalBoundry: Skip # Differences in ia32, debug, release
cc/SNPrint_BadArgs: Crash, Fail # These tests are expected to crash on all platforms.
@@ -34,6 +34,7 @@
[ $compiler == dart2js ]
dart/byte_array_optimized_test: Skip # compilers not aware of byte arrays
dart/byte_array_test: Skip # compilers not aware of byte arrays
+dart/error_messages_in_null_checks_test: SkipByDesign # Dart2js throws NullError exceptions with different messages.
dart/inline_stack_frame_test: Skip # Issue 7953, Methods can be missing in dart2js stack traces due to inlining. Also when minifying they can be renamed, which is issue 7953.
dart/optimized_stacktrace_line_and_column_test: RuntimeError # The source positions do not match with dart2js.
dart/optimized_stacktrace_line_test: RuntimeError # The source positions do not match with dart2js.
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc
index 3ac1c40..447ea45 100644
--- a/runtime/vm/class_table.cc
+++ b/runtime/vm/class_table.cc
@@ -21,27 +21,27 @@
: top_(kNumPredefinedCids),
capacity_(0),
table_(NULL),
- old_tables_(new MallocGrowableArray<RawClass**>()) {
+ old_tables_(new MallocGrowableArray<ClassAndSize*>()) {
NOT_IN_PRODUCT(class_heap_stats_table_ = NULL);
NOT_IN_PRODUCT(predefined_class_heap_stats_table_ = NULL);
if (Dart::vm_isolate() == NULL) {
capacity_ = initial_capacity_;
- table_ = reinterpret_cast<RawClass**>(
- calloc(capacity_, sizeof(RawClass*))); // NOLINT
+ table_ = reinterpret_cast<ClassAndSize*>(
+ calloc(capacity_, sizeof(ClassAndSize))); // NOLINT
} else {
// Duplicate the class table from the VM isolate.
ClassTable* vm_class_table = Dart::vm_isolate()->class_table();
capacity_ = vm_class_table->capacity_;
- table_ = reinterpret_cast<RawClass**>(
- calloc(capacity_, sizeof(RawClass*))); // NOLINT
+ table_ = reinterpret_cast<ClassAndSize*>(
+ calloc(capacity_, sizeof(ClassAndSize))); // NOLINT
for (intptr_t i = kObjectCid; i < kInstanceCid; i++) {
- table_[i] = vm_class_table->At(i);
+ table_[i] = vm_class_table->PairAt(i);
}
- table_[kTypeArgumentsCid] = vm_class_table->At(kTypeArgumentsCid);
- table_[kFreeListElement] = vm_class_table->At(kFreeListElement);
- table_[kForwardingCorpse] = vm_class_table->At(kForwardingCorpse);
- table_[kDynamicCid] = vm_class_table->At(kDynamicCid);
- table_[kVoidCid] = vm_class_table->At(kVoidCid);
+ table_[kTypeArgumentsCid] = vm_class_table->PairAt(kTypeArgumentsCid);
+ table_[kFreeListElement] = vm_class_table->PairAt(kFreeListElement);
+ table_[kForwardingCorpse] = vm_class_table->PairAt(kForwardingCorpse);
+ table_[kDynamicCid] = vm_class_table->PairAt(kDynamicCid);
+ table_[kVoidCid] = vm_class_table->PairAt(kVoidCid);
#ifndef PRODUCT
class_heap_stats_table_ = reinterpret_cast<ClassHeapStats*>(
@@ -83,7 +83,7 @@
}
}
-void ClassTable::AddOldTable(RawClass** old_table) {
+void ClassTable::AddOldTable(ClassAndSize* old_table) {
ASSERT(Thread::Current()->IsMutatorThread());
old_tables_->Add(old_table);
}
@@ -112,9 +112,9 @@
if (index != kIllegalCid) {
ASSERT(index > 0);
ASSERT(index < kNumPredefinedCids);
- ASSERT(table_[index] == 0);
+ ASSERT(table_[index].class_ == NULL);
ASSERT(index < capacity_);
- table_[index] = cls.raw();
+ table_[index] = ClassAndSize(cls.raw(), Class::instance_size(cls.raw()));
// Add the vtable for this predefined class into the static vtable registry
// if it has not been setup yet.
cpp_vtable cls_vtable = cls.handle_vtable();
@@ -128,16 +128,16 @@
// Grow the capacity of the class table.
// TODO(koda): Add ClassTable::Grow to share code.
intptr_t new_capacity = capacity_ + capacity_increment_;
- RawClass** new_table = reinterpret_cast<RawClass**>(
- malloc(new_capacity * sizeof(RawClass*))); // NOLINT
- memmove(new_table, table_, capacity_ * sizeof(RawClass*));
+ ClassAndSize* new_table = reinterpret_cast<ClassAndSize*>(
+ malloc(new_capacity * sizeof(ClassAndSize))); // NOLINT
+ memmove(new_table, table_, capacity_ * sizeof(ClassAndSize));
#ifndef PRODUCT
ClassHeapStats* new_stats_table = reinterpret_cast<ClassHeapStats*>(
realloc(class_heap_stats_table_,
new_capacity * sizeof(ClassHeapStats))); // NOLINT
#endif
for (intptr_t i = capacity_; i < new_capacity; i++) {
- new_table[i] = NULL;
+ new_table[i] = ClassAndSize(NULL, 0);
NOT_IN_PRODUCT(new_stats_table[i].Initialize());
}
capacity_ = new_capacity;
@@ -151,7 +151,7 @@
top_);
}
cls.set_id(top_);
- table_[top_] = cls.raw();
+ table_[top_] = ClassAndSize(cls.raw());
top_++; // Increment next index.
}
}
@@ -165,16 +165,16 @@
FATAL1("Fatal error in ClassTable::Register: invalid index %" Pd "\n",
index);
}
- RawClass** new_table = reinterpret_cast<RawClass**>(
- malloc(new_capacity * sizeof(RawClass*))); // NOLINT
- memmove(new_table, table_, capacity_ * sizeof(RawClass*));
+ ClassAndSize* new_table = reinterpret_cast<ClassAndSize*>(
+ malloc(new_capacity * sizeof(ClassAndSize))); // NOLINT
+ memmove(new_table, table_, capacity_ * sizeof(ClassAndSize));
#ifndef PRODUCT
ClassHeapStats* new_stats_table = reinterpret_cast<ClassHeapStats*>(
realloc(class_heap_stats_table_,
new_capacity * sizeof(ClassHeapStats))); // NOLINT
#endif
for (intptr_t i = capacity_; i < new_capacity; i++) {
- new_table[i] = NULL;
+ new_table[i] = ClassAndSize(NULL);
NOT_IN_PRODUCT(new_stats_table[i].Initialize());
}
capacity_ = new_capacity;
@@ -184,7 +184,7 @@
ASSERT(capacity_increment_ >= 1);
}
- ASSERT(table_[index] == 0);
+ ASSERT(table_[index].class_ == NULL);
if (index >= top_) {
top_ = index + 1;
}
@@ -192,14 +192,14 @@
#if defined(DEBUG)
void ClassTable::Unregister(intptr_t index) {
- table_[index] = 0;
+ table_[index] = ClassAndSize(NULL);
}
#endif
void ClassTable::Remap(intptr_t* old_to_new_cid) {
ASSERT(Thread::Current()->IsAtSafepoint());
intptr_t num_cids = NumCids();
- RawClass** cls_by_old_cid = new RawClass*[num_cids];
+ ClassAndSize* cls_by_old_cid = new ClassAndSize[num_cids];
for (intptr_t i = 0; i < num_cids; i++) {
cls_by_old_cid[i] = table_[i];
}
@@ -211,7 +211,16 @@
void ClassTable::VisitObjectPointers(ObjectPointerVisitor* visitor) {
ASSERT(visitor != NULL);
- visitor->VisitPointers(reinterpret_cast<RawObject**>(&table_[0]), top_);
+ for (intptr_t i = 0; i < top_; i++) {
+ visitor->VisitPointer(reinterpret_cast<RawObject**>(&(table_[i].class_)));
+ }
+}
+
+void ClassTable::CopySizesFromClassObjects() {
+ ASSERT(kIllegalCid == 0);
+ for (intptr_t i = 1; i < top_; i++) {
+ SetAt(i, At(i));
+ }
}
void ClassTable::Validate() {
@@ -248,6 +257,19 @@
}
}
+void ClassTable::SetAt(intptr_t index, RawClass* raw_cls) {
+ ASSERT(index < capacity_);
+ if (raw_cls == NULL) {
+ table_[index] = ClassAndSize(raw_cls, 0);
+ } else {
+ table_[index] = ClassAndSize(raw_cls, Class::instance_size(raw_cls));
+ }
+}
+
+ClassAndSize::ClassAndSize(RawClass* clazz) : class_(clazz) {
+ size_ = clazz == NULL ? 0 : Class::instance_size(clazz);
+}
+
#ifndef PRODUCT
void ClassTable::PrintToJSONObject(JSONObject* object) {
if (!FLAG_support_service) {
diff --git a/runtime/vm/class_table.h b/runtime/vm/class_table.h
index 7eae60b..560e686 100644
--- a/runtime/vm/class_table.h
+++ b/runtime/vm/class_table.h
@@ -14,6 +14,7 @@
class Class;
class ClassStats;
+class ClassTable;
class JSONArray;
class JSONObject;
class JSONStream;
@@ -22,6 +23,29 @@
class ObjectPointerVisitor;
class RawClass;
+class ClassAndSize {
+ public:
+ ClassAndSize() : class_(NULL), size_(0) {}
+ explicit ClassAndSize(RawClass* clazz);
+ ClassAndSize(RawClass* clazz, intptr_t size) : class_(clazz), size_(size) {}
+ RawClass* get_raw_class() const { return class_; }
+ intptr_t size() const { return size_; }
+
+ private:
+ RawClass* class_;
+ intptr_t size_;
+
+ friend class ClassTable;
+};
+
+#if defined(ARCH_IS_32_BIT)
+const int kSizeOfClassPairLog2 = 3;
+#else
+const int kSizeOfClassPairLog2 = 4;
+#endif
+
+COMPILE_ASSERT((1 << kSizeOfClassPairLog2) == sizeof(ClassAndSize));
+
#ifndef PRODUCT
template <typename T>
class AllocStats {
@@ -165,10 +189,20 @@
// Thread-safe.
RawClass* At(intptr_t index) const {
ASSERT(IsValidIndex(index));
+ return table_[index].class_;
+ }
+
+ intptr_t SizeAt(intptr_t index) const {
+ ASSERT(IsValidIndex(index));
+ return table_[index].size_;
+ }
+
+ ClassAndSize PairAt(intptr_t index) const {
+ ASSERT(IsValidIndex(index));
return table_[index];
}
- void SetAt(intptr_t index, RawClass* raw_cls) { table_[index] = raw_cls; }
+ void SetAt(intptr_t index, RawClass* raw_cls);
bool IsValidIndex(intptr_t index) const {
return (index > 0) && (index < top_);
@@ -176,7 +210,7 @@
bool HasValidClassAt(intptr_t index) const {
ASSERT(IsValidIndex(index));
- return table_[index] != NULL;
+ return table_[index].class_ != NULL;
}
intptr_t NumCids() const { return top_; }
@@ -199,6 +233,11 @@
void VisitObjectPointers(ObjectPointerVisitor* visitor);
+ // If a snapshot reader has populated the class table then the
+ // sizes in the class table are not correct. Iterates through the
+ // table, updating the sizes.
+ void CopySizesFromClassObjects();
+
void Validate();
void Print();
@@ -245,7 +284,7 @@
void PrintToJSONObject(JSONObject* object);
#endif // !PRODUCT
- void AddOldTable(RawClass** old_table);
+ void AddOldTable(ClassAndSize* old_table);
// Deallocates table copies. Do not call during concurrent access to table.
void FreeOldTables();
@@ -267,8 +306,8 @@
intptr_t capacity_;
// Copy-on-write is used for table_, with old copies stored in old_tables_.
- RawClass** table_;
- MallocGrowableArray<RawClass**>* old_tables_;
+ ClassAndSize* table_;
+ MallocGrowableArray<ClassAndSize*>* old_tables_;
#ifndef PRODUCT
ClassHeapStats* class_heap_stats_table_;
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 6243d52..650db2a 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -1699,18 +1699,12 @@
}
}
- RawInstructions* instr = code->ptr()->instructions_;
- int32_t text_offset = s->GetTextOffset(instr, code);
- s->Write<int32_t>(text_offset);
+ s->WriteInstructions(code->ptr()->instructions_, code);
if (s->kind() == Snapshot::kFullJIT) {
// TODO(rmacnak): Fix references to disabled code before serializing.
- if (code->ptr()->active_instructions_ != code->ptr()->instructions_) {
- // For now, we write the FixCallersTarget or equivalent stub. This
- // will cause a fixup if this code is called.
- instr = code->ptr()->active_instructions_;
- text_offset = s->GetTextOffset(instr, code);
- }
- s->Write<int32_t>(text_offset);
+ // For now, we may write the FixCallersTarget or equivalent stub. This
+ // will cause a fixup if this code is called.
+ s->WriteInstructions(code->ptr()->active_instructions_, code);
}
s->WriteRef(code->ptr()->object_pool_);
@@ -1771,8 +1765,7 @@
Deserializer::InitializeHeader(code, kCodeCid, Code::InstanceSize(0),
is_vm_object);
- int32_t text_offset = d->Read<int32_t>();
- RawInstructions* instr = d->GetInstructionsAt(text_offset);
+ RawInstructions* instr = d->ReadInstructions();
code->ptr()->entry_point_ = Instructions::UncheckedEntryPoint(instr);
code->ptr()->checked_entry_point_ =
@@ -1782,8 +1775,7 @@
#if !defined(DART_PRECOMPILED_RUNTIME)
if (d->kind() == Snapshot::kFullJIT) {
- int32_t text_offset = d->Read<int32_t>();
- RawInstructions* instr = d->GetInstructionsAt(text_offset);
+ RawInstructions* instr = d->ReadInstructions();
code->ptr()->active_instructions_ = instr;
code->ptr()->entry_point_ = Instructions::UncheckedEntryPoint(instr);
code->ptr()->checked_entry_point_ =
@@ -1993,8 +1985,6 @@
virtual ~RODataSerializationCluster() {}
void Trace(Serializer* s, RawObject* object) {
- objects_.Add(object);
-
// A string's hash must already be computed when we write it because it
// will be loaded into read-only memory. Extra bytes due to allocation
// rounding need to be deterministically set for reliable deduplication in
@@ -2004,11 +1994,30 @@
} else {
Object::FinalizeReadOnlyObject(object);
}
+
+ uint32_t ignored;
+ if (s->GetSharedDataOffset(object, &ignored)) {
+ shared_objects_.Add(object);
+ } else {
+ objects_.Add(object);
+ }
}
void WriteAlloc(Serializer* s) {
s->WriteCid(cid_);
- intptr_t count = objects_.length();
+ intptr_t count = shared_objects_.length();
+ s->WriteUnsigned(count);
+ for (intptr_t i = 0; i < count; i++) {
+ RawObject* object = shared_objects_[i];
+ uint32_t offset;
+ if (!s->GetSharedDataOffset(object, &offset)) {
+ UNREACHABLE();
+ }
+ s->WriteUnsigned(offset);
+ s->AssignRef(object);
+ }
+
+ count = objects_.length();
s->WriteUnsigned(count);
uint32_t running_offset = 0;
for (intptr_t i = 0; i < count; i++) {
@@ -2029,6 +2038,7 @@
private:
const intptr_t cid_;
GrowableArray<RawObject*> objects_;
+ GrowableArray<RawObject*> shared_objects_;
};
#endif // !DART_PRECOMPILED_RUNTIME
@@ -2039,6 +2049,12 @@
void ReadAlloc(Deserializer* d) {
intptr_t count = d->ReadUnsigned();
+ for (intptr_t i = 0; i < count; i++) {
+ uint32_t offset = d->ReadUnsigned();
+ d->AssignRef(d->GetSharedObjectAt(offset));
+ }
+
+ count = d->ReadUnsigned();
uint32_t running_offset = 0;
for (intptr_t i = 0; i < count; i++) {
running_offset += d->ReadUnsigned() << kObjectAlignmentLog2;
@@ -3054,8 +3070,7 @@
if (s->kind() == Snapshot::kFullAOT) {
RawInstructions* instr = type_testing_stubs_.LookupByAddresss(
type->ptr()->type_test_stub_entry_point_);
- const int32_t text_offset = s->GetTextOffset(instr, Code::null());
- s->Write<int32_t>(text_offset);
+ s->WriteInstructions(instr, Code::null());
}
}
count = objects_.length();
@@ -3071,8 +3086,7 @@
if (s->kind() == Snapshot::kFullAOT) {
RawInstructions* instr = type_testing_stubs_.LookupByAddresss(
type->ptr()->type_test_stub_entry_point_);
- const int32_t text_offset = s->GetTextOffset(instr, Code::null());
- s->Write<int32_t>(text_offset);
+ s->WriteInstructions(instr, Code::null());
}
}
@@ -3081,11 +3095,11 @@
if (s->kind() == Snapshot::kFullAOT && is_vm_isolate) {
RawInstructions* dynamic_instr = type_testing_stubs_.LookupByAddresss(
Type::dynamic_type().type_test_stub_entry_point());
- s->Write<int32_t>(s->GetTextOffset(dynamic_instr, Code::null()));
+ s->WriteInstructions(dynamic_instr, Code::null());
RawInstructions* void_instr = type_testing_stubs_.LookupByAddresss(
Type::void_type().type_test_stub_entry_point());
- s->Write<int32_t>(s->GetTextOffset(void_instr, Code::null()));
+ s->WriteInstructions(void_instr, Code::null());
}
}
@@ -3135,8 +3149,7 @@
type->ptr()->token_pos_ = d->ReadTokenPosition();
type->ptr()->type_state_ = d->Read<int8_t>();
if (d->kind() == Snapshot::kFullAOT) {
- const int32_t text_offset = d->Read<int32_t>();
- instr_ = d->GetInstructionsAt(text_offset);
+ instr_ = d->ReadInstructions();
type_ = type;
type_.SetTypeTestingStub(instr_);
}
@@ -3154,8 +3167,7 @@
type->ptr()->token_pos_ = d->ReadTokenPosition();
type->ptr()->type_state_ = d->Read<int8_t>();
if (d->kind() == Snapshot::kFullAOT) {
- const int32_t text_offset = d->Read<int32_t>();
- instr_ = d->GetInstructionsAt(text_offset);
+ instr_ = d->ReadInstructions();
type_ = type;
type_.SetTypeTestingStub(instr_);
}
@@ -3164,9 +3176,9 @@
// The dynamic/void objects are not serialized, so we manually send
// the type testing stub for it.
if (d->kind() == Snapshot::kFullAOT && is_vm_isolate) {
- instr_ = d->GetInstructionsAt(d->Read<int32_t>());
+ instr_ = d->ReadInstructions();
Type::dynamic_type().SetTypeTestingStub(instr_);
- instr_ = d->GetInstructionsAt(d->Read<int32_t>());
+ instr_ = d->ReadInstructions();
Type::void_type().SetTypeTestingStub(instr_);
}
}
@@ -3234,8 +3246,7 @@
if (s->kind() == Snapshot::kFullAOT) {
RawInstructions* instr = type_testing_stubs_.LookupByAddresss(
type->ptr()->type_test_stub_entry_point_);
- const int32_t text_offset = s->GetTextOffset(instr, Code::null());
- s->Write<int32_t>(text_offset);
+ s->WriteInstructions(instr, Code::null());
}
}
}
@@ -3275,8 +3286,7 @@
*p = d->ReadRef();
}
if (d->kind() == Snapshot::kFullAOT) {
- const int32_t text_offset = d->Read<int32_t>();
- instr_ = d->GetInstructionsAt(text_offset);
+ instr_ = d->ReadInstructions();
type_ = type;
type_.SetTypeTestingStub(instr_);
}
@@ -3334,8 +3344,7 @@
if (s->kind() == Snapshot::kFullAOT) {
RawInstructions* instr = type_testing_stubs_.LookupByAddresss(
type->ptr()->type_test_stub_entry_point_);
- const int32_t text_offset = s->GetTextOffset(instr, Code::null());
- s->Write<int32_t>(text_offset);
+ s->WriteInstructions(instr, Code::null());
}
}
}
@@ -3380,8 +3389,7 @@
type->ptr()->index_ = d->Read<int16_t>();
type->ptr()->type_state_ = d->Read<int8_t>();
if (d->kind() == Snapshot::kFullAOT) {
- const int32_t text_offset = d->Read<int32_t>();
- instr_ = d->GetInstructionsAt(text_offset);
+ instr_ = d->ReadInstructions();
type_ = type;
type_.SetTypeTestingStub(instr_);
}
@@ -4819,14 +4827,19 @@
#endif // !DART_PRECOMPILED_RUNTIME
}
-int32_t Serializer::GetTextOffset(RawInstructions* instr, RawCode* code) const {
+void Serializer::WriteInstructions(RawInstructions* instr, RawCode* code) {
intptr_t offset = heap_->GetObjectId(instr);
if (offset == 0) {
offset = image_writer_->GetTextOffsetFor(instr, code);
ASSERT(offset != 0);
heap_->SetObjectId(instr, offset);
}
- return offset;
+ Write<int32_t>(offset);
+}
+
+bool Serializer::GetSharedDataOffset(RawObject* object,
+ uint32_t* offset) const {
+ return image_writer_->GetSharedDataOffsetFor(object, offset);
}
uint32_t Serializer::GetDataOffset(RawObject* object) const {
@@ -5100,8 +5113,7 @@
}
intptr_t Serializer::WriteVMSnapshot(const Array& symbols,
- ZoneGrowableArray<Object*>* seed_objects,
- ZoneGrowableArray<Code*>* seed_code) {
+ ZoneGrowableArray<Object*>* seeds) {
NoSafepointScope no_safepoint;
AddVMIsolateBaseObjects();
@@ -5113,15 +5125,9 @@
Push(StubCode::EntryAt(i)->code());
}
}
- if (seed_objects != NULL) {
- for (intptr_t i = 0; i < seed_objects->length(); i++) {
- Push((*seed_objects)[i]->raw());
- }
- }
- if (seed_code != NULL) {
- for (intptr_t i = 0; i < seed_code->length(); i++) {
- Code* code = (*seed_code)[i];
- GetTextOffset(code->instructions(), code->raw());
+ if (seeds != NULL) {
+ for (intptr_t i = 0; i < seeds->length(); i++) {
+ Push((*seeds)[i]->raw());
}
}
@@ -5147,27 +5153,6 @@
return next_ref_index_ - 1;
}
-// Collects Instructions from the VM isolate and adds them to object id table
-// with offsets that will refer to the VM snapshot, causing them to be shared
-// across isolates.
-class SeedInstructionsVisitor : public ObjectVisitor {
- public:
- SeedInstructionsVisitor(uword text_base, Heap* heap)
- : text_base_(text_base), heap_(heap) {}
-
- void VisitObject(RawObject* obj) {
- if (obj->IsInstructions()) {
- uword addr = RawObject::ToAddr(obj);
- uint32_t offset = addr - text_base_;
- heap_->SetObjectId(obj, -offset);
- }
- }
-
- private:
- uword text_base_;
- Heap* heap_;
-};
-
void Serializer::WriteIsolateSnapshot(intptr_t num_base_objects,
ObjectStore* object_store) {
NoSafepointScope no_safepoint;
@@ -5178,12 +5163,6 @@
for (intptr_t i = 1; i < base_objects.Length(); i++) {
AddBaseObject(base_objects.At(i));
}
- const uint8_t* text_base = Dart::vm_snapshot_instructions();
- if (text_base != NULL) {
- SeedInstructionsVisitor visitor(reinterpret_cast<uword>(text_base),
- heap_);
- Dart::vm_isolate()->heap()->VisitObjectsImagePages(&visitor);
- }
} else {
// Base objects carried over from WriteVMIsolateSnapshot.
num_base_objects_ += num_base_objects;
@@ -5215,8 +5194,10 @@
Snapshot::Kind kind,
const uint8_t* buffer,
intptr_t size,
+ const uint8_t* data_buffer,
const uint8_t* instructions_buffer,
- const uint8_t* data_buffer)
+ const uint8_t* shared_data_buffer,
+ const uint8_t* shared_instructions_buffer)
: StackResource(thread),
heap_(thread->isolate()->heap()),
zone_(thread->zone()),
@@ -5229,7 +5210,9 @@
if (Snapshot::IncludesCode(kind)) {
ASSERT(instructions_buffer != NULL);
ASSERT(data_buffer != NULL);
- image_reader_ = new (zone_) ImageReader(instructions_buffer, data_buffer);
+ image_reader_ =
+ new (zone_) ImageReader(data_buffer, instructions_buffer,
+ shared_data_buffer, shared_instructions_buffer);
}
}
@@ -5431,7 +5414,8 @@
return ApiError::null();
}
-RawInstructions* Deserializer::GetInstructionsAt(int32_t offset) const {
+RawInstructions* Deserializer::ReadInstructions() {
+ int32_t offset = Read<int32_t>();
return image_reader_->GetInstructionsAt(offset);
}
@@ -5439,6 +5423,10 @@
return image_reader_->GetObjectAt(offset);
}
+RawObject* Deserializer::GetSharedObjectAt(uint32_t offset) const {
+ return image_reader_->GetSharedObjectAt(offset);
+}
+
void Deserializer::Prepare() {
num_base_objects_ = ReadUnsigned();
num_objects_ = ReadUnsigned();
@@ -5622,6 +5610,8 @@
refs_ = NULL;
}
+ thread()->isolate()->class_table()->CopySizesFromClassObjects();
+
#if defined(DEBUG)
Isolate* isolate = thread()->isolate();
isolate->ValidateClassTable();
@@ -5644,8 +5634,7 @@
SeedVMIsolateVisitor(Zone* zone, bool include_code)
: zone_(zone),
include_code_(include_code),
- objects_(new (zone) ZoneGrowableArray<Object*>(4 * KB)),
- codes_(new (zone) ZoneGrowableArray<Code*>(4 * KB)),
+ seeds_(new (zone) ZoneGrowableArray<Object*>(4 * KB)),
script_(Script::Handle(zone)),
code_(Code::Handle(zone)),
stack_maps_(Array::Handle(zone)),
@@ -5659,7 +5648,7 @@
}
library_ = cls.library();
- objects_->Add(&Object::Handle(zone_, library_.kernel_data()));
+ AddSeed(library_.kernel_data());
if (!include_code_) return;
@@ -5684,45 +5673,40 @@
void Visit(const Script& script) {
kernel_program_info_ = script_.kernel_program_info();
if (!kernel_program_info_.IsNull()) {
- objects_->Add(
- &Object::Handle(zone_, kernel_program_info_.string_offsets()));
- objects_->Add(&Object::Handle(zone_, kernel_program_info_.string_data()));
- objects_->Add(
- &Object::Handle(zone_, kernel_program_info_.canonical_names()));
- objects_->Add(
- &Object::Handle(zone_, kernel_program_info_.metadata_payloads()));
- objects_->Add(
- &Object::Handle(zone_, kernel_program_info_.metadata_mappings()));
- objects_->Add(&Object::Handle(zone_, kernel_program_info_.constants()));
+ AddSeed(kernel_program_info_.string_offsets());
+ AddSeed(kernel_program_info_.string_data());
+ AddSeed(kernel_program_info_.canonical_names());
+ AddSeed(kernel_program_info_.metadata_payloads());
+ AddSeed(kernel_program_info_.metadata_mappings());
+ AddSeed(kernel_program_info_.constants());
} else {
- objects_->Add(&Object::Handle(zone_, script_.tokens()));
+ AddSeed(script_.tokens());
}
}
- ZoneGrowableArray<Object*>* objects() { return objects_; }
- ZoneGrowableArray<Code*>* codes() { return codes_; }
+ ZoneGrowableArray<Object*>* seeds() { return seeds_; }
private:
void Visit(const Code& code) {
ASSERT(include_code_);
if (code.IsNull()) return;
- codes_->Add(&Code::Handle(zone_, code.raw()));
- objects_->Add(&Object::Handle(zone_, code.pc_descriptors()));
- objects_->Add(&Object::Handle(zone_, code.code_source_map()));
+ AddSeed(code.pc_descriptors());
+ AddSeed(code.code_source_map());
stack_maps_ = code_.stackmaps();
if (!stack_maps_.IsNull()) {
for (intptr_t i = 0; i < stack_maps_.Length(); i++) {
- objects_->Add(&Object::Handle(zone_, stack_maps_.At(i)));
+ AddSeed(stack_maps_.At(i));
}
}
}
+ void AddSeed(RawObject* seed) { seeds_->Add(&Object::Handle(zone_, seed)); }
+
Zone* zone_;
bool include_code_;
- ZoneGrowableArray<Object*>* objects_;
- ZoneGrowableArray<Code*>* codes_;
+ ZoneGrowableArray<Object*>* seeds_;
Script& script_;
Code& code_;
Array& stack_maps_;
@@ -5745,8 +5729,7 @@
isolate_snapshot_size_(0),
vm_image_writer_(vm_image_writer),
isolate_image_writer_(isolate_image_writer),
- seed_objects_(NULL),
- seed_code_(NULL),
+ seeds_(NULL),
saved_symbol_table_(Array::Handle(zone())),
new_vm_symbol_table_(Array::Handle(zone())),
clustered_vm_size_(0),
@@ -5777,8 +5760,7 @@
Snapshot::IncludesCode(kind));
ProgramVisitor::VisitClasses(&visitor);
ProgramVisitor::VisitFunctions(&visitor);
- seed_objects_ = visitor.objects();
- seed_code_ = visitor.codes();
+ seeds_ = visitor.seeds();
// Tuck away the current symbol table.
saved_symbol_table_ = object_store->symbol_table();
@@ -5819,9 +5801,9 @@
// VM snapshot roots are:
// - the symbol table
// - all the token streams
- // - the stub code (precompiled snapshots only)
- intptr_t num_objects = serializer.WriteVMSnapshot(new_vm_symbol_table_,
- seed_objects_, seed_code_);
+ // - the stub code (App-AOT, App-JIT or Core-JIT)
+ intptr_t num_objects =
+ serializer.WriteVMSnapshot(new_vm_symbol_table_, seeds_);
serializer.FillHeader(serializer.kind());
clustered_vm_size_ = serializer.bytes_written();
@@ -5893,30 +5875,30 @@
}
}
-static const uint8_t* DataBuffer(const Snapshot* snapshot) {
- if (Snapshot::IncludesCode(snapshot->kind())) {
- uword offset =
- Utils::RoundUp(snapshot->length(), OS::kMaxPreferredCodeAlignment);
- return snapshot->Addr() + offset;
- }
- return NULL;
-}
-
FullSnapshotReader::FullSnapshotReader(const Snapshot* snapshot,
const uint8_t* instructions_buffer,
+ const uint8_t* shared_data,
+ const uint8_t* shared_instructions,
Thread* thread)
: kind_(snapshot->kind()),
thread_(thread),
buffer_(snapshot->content()),
size_(snapshot->length()),
- instructions_buffer_(instructions_buffer),
- data_buffer_(DataBuffer(snapshot)) {
+ data_image_(snapshot->DataImage()),
+ instructions_image_(instructions_buffer) {
thread->isolate()->set_compilation_allowed(kind_ != Snapshot::kFullAOT);
+
+ if (shared_data == NULL) {
+ shared_data_image_ = NULL;
+ } else {
+ shared_data_image_ = Snapshot::SetupFromBuffer(shared_data)->DataImage();
+ }
+ shared_instructions_image_ = shared_instructions;
}
RawApiError* FullSnapshotReader::ReadVMSnapshot() {
- Deserializer deserializer(thread_, kind_, buffer_, size_,
- instructions_buffer_, data_buffer_);
+ Deserializer deserializer(thread_, kind_, buffer_, size_, data_image_,
+ instructions_image_, NULL, NULL);
RawApiError* error = deserializer.VerifyVersionAndFeatures(/*isolate=*/NULL);
if (error != ApiError::null()) {
@@ -5924,13 +5906,12 @@
}
if (Snapshot::IncludesCode(kind_)) {
- ASSERT(instructions_buffer_ != NULL);
- thread_->isolate()->SetupImagePage(instructions_buffer_,
- /* is_executable */ true);
- ASSERT(data_buffer_ != NULL);
- thread_->isolate()->SetupImagePage(data_buffer_,
+ ASSERT(data_image_ != NULL);
+ thread_->isolate()->SetupImagePage(data_image_,
/* is_executable */ false);
- Dart::set_vm_snapshot_instructions(instructions_buffer_);
+ ASSERT(instructions_image_ != NULL);
+ thread_->isolate()->SetupImagePage(instructions_image_,
+ /* is_executable */ true);
}
deserializer.ReadVMSnapshot();
@@ -5939,8 +5920,9 @@
}
RawApiError* FullSnapshotReader::ReadIsolateSnapshot() {
- Deserializer deserializer(thread_, kind_, buffer_, size_,
- instructions_buffer_, data_buffer_);
+ Deserializer deserializer(thread_, kind_, buffer_, size_, data_image_,
+ instructions_image_, shared_data_image_,
+ shared_instructions_image_);
RawApiError* error =
deserializer.VerifyVersionAndFeatures(thread_->isolate());
@@ -5949,12 +5931,20 @@
}
if (Snapshot::IncludesCode(kind_)) {
- ASSERT(instructions_buffer_ != NULL);
- thread_->isolate()->SetupImagePage(instructions_buffer_,
- /* is_executable */ true);
- ASSERT(data_buffer_ != NULL);
- thread_->isolate()->SetupImagePage(data_buffer_,
+ ASSERT(data_image_ != NULL);
+ thread_->isolate()->SetupImagePage(data_image_,
/* is_executable */ false);
+ ASSERT(instructions_image_ != NULL);
+ thread_->isolate()->SetupImagePage(instructions_image_,
+ /* is_executable */ true);
+ if (shared_data_image_ != NULL) {
+ thread_->isolate()->SetupImagePage(shared_data_image_,
+ /* is_executable */ false);
+ }
+ if (shared_instructions_image_ != NULL) {
+ thread_->isolate()->SetupImagePage(shared_instructions_image_,
+ /* is_executable */ true);
+ }
}
deserializer.ReadIsolateSnapshot(thread_->isolate()->object_store());
diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h
index c9e4970..1e2da8c 100644
--- a/runtime/vm/clustered_snapshot.h
+++ b/runtime/vm/clustered_snapshot.h
@@ -136,8 +136,7 @@
~Serializer();
intptr_t WriteVMSnapshot(const Array& symbols,
- ZoneGrowableArray<Object*>* seed_objects,
- ZoneGrowableArray<Code*>* seed_code);
+ ZoneGrowableArray<Object*>* seeds);
void WriteIsolateSnapshot(intptr_t num_base_objects,
ObjectStore* object_store);
@@ -254,7 +253,8 @@
Write<int32_t>(cid);
}
- int32_t GetTextOffset(RawInstructions* instr, RawCode* code) const;
+ void WriteInstructions(RawInstructions* instr, RawCode* code);
+ bool GetSharedDataOffset(RawObject* object, uint32_t* offset) const;
uint32_t GetDataOffset(RawObject* object) const;
intptr_t GetDataSize() const;
intptr_t GetTextSize() const;
@@ -293,8 +293,10 @@
Snapshot::Kind kind,
const uint8_t* buffer,
intptr_t size,
+ const uint8_t* data_buffer,
const uint8_t* instructions_buffer,
- const uint8_t* data_buffer);
+ const uint8_t* shared_data_buffer,
+ const uint8_t* shared_instructions_buffer);
~Deserializer();
void ReadIsolateSnapshot(ObjectStore* object_store);
@@ -350,8 +352,9 @@
return Read<int32_t>();
}
- RawInstructions* GetInstructionsAt(int32_t offset) const;
+ RawInstructions* ReadInstructions();
RawObject* GetObjectAt(uint32_t offset) const;
+ RawObject* GetSharedObjectAt(uint32_t offset) const;
RawApiError* VerifyVersionAndFeatures(Isolate* isolate);
@@ -423,8 +426,7 @@
ForwardList* forward_list_;
ImageWriter* vm_image_writer_;
ImageWriter* isolate_image_writer_;
- ZoneGrowableArray<Object*>* seed_objects_;
- ZoneGrowableArray<Code*>* seed_code_;
+ ZoneGrowableArray<Object*>* seeds_;
Array& saved_symbol_table_;
Array& new_vm_symbol_table_;
@@ -441,6 +443,8 @@
public:
FullSnapshotReader(const Snapshot* snapshot,
const uint8_t* instructions_buffer,
+ const uint8_t* shared_data,
+ const uint8_t* shared_instructions,
Thread* thread);
~FullSnapshotReader() {}
@@ -452,8 +456,10 @@
Thread* thread_;
const uint8_t* buffer_;
intptr_t size_;
- const uint8_t* instructions_buffer_;
- const uint8_t* data_buffer_;
+ const uint8_t* data_image_;
+ const uint8_t* instructions_image_;
+ const uint8_t* shared_data_image_;
+ const uint8_t* shared_instructions_image_;
DISALLOW_COPY_AND_ASSIGN(FullSnapshotReader);
};
diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc
index 1682003..206c249 100644
--- a/runtime/vm/code_descriptors.cc
+++ b/runtime/vm/code_descriptors.cc
@@ -24,13 +24,15 @@
PcDescriptors::EncodeInteger(&encoded_data_, merged_kind_try);
PcDescriptors::EncodeInteger(&encoded_data_, pc_offset - prev_pc_offset);
- PcDescriptors::EncodeInteger(&encoded_data_, deopt_id - prev_deopt_id);
- PcDescriptors::EncodeInteger(&encoded_data_,
- token_pos.value() - prev_token_pos);
-
prev_pc_offset = pc_offset;
- prev_deopt_id = deopt_id;
- prev_token_pos = token_pos.value();
+
+ if (!FLAG_precompiled_mode) {
+ PcDescriptors::EncodeInteger(&encoded_data_, deopt_id - prev_deopt_id);
+ PcDescriptors::EncodeInteger(&encoded_data_,
+ token_pos.value() - prev_token_pos);
+ prev_deopt_id = deopt_id;
+ prev_token_pos = token_pos.value();
+ }
}
}
@@ -366,6 +368,15 @@
}
}
+void CodeSourceMapBuilder::NoteNullCheck(int32_t pc_offset,
+ TokenPosition pos,
+ intptr_t name_index) {
+ BufferChangePosition(pos);
+ BufferAdvancePC(pc_offset - buffered_pc_offset_);
+ FlushBuffer();
+ WriteNullCheck(name_index);
+}
+
intptr_t CodeSourceMapBuilder::GetFunctionId(intptr_t inline_id) {
const Function& function = *inline_id_to_function_[inline_id];
for (intptr_t i = 0; i < inlined_functions_.Length(); i++) {
@@ -459,6 +470,10 @@
token_positions->RemoveLast();
break;
}
+ case CodeSourceMapBuilder::kNullCheck: {
+ stream.Read<int32_t>();
+ break;
+ }
default:
UNREACHABLE();
}
@@ -516,6 +531,10 @@
function_stack.RemoveLast();
break;
}
+ case CodeSourceMapBuilder::kNullCheck: {
+ stream.Read<int32_t>();
+ break;
+ }
default:
UNREACHABLE();
}
@@ -563,6 +582,10 @@
function_stack.RemoveLast();
break;
}
+ case CodeSourceMapBuilder::kNullCheck: {
+ stream.Read<int32_t>();
+ break;
+ }
default:
UNREACHABLE();
}
@@ -617,6 +640,13 @@
token_positions.RemoveLast();
break;
}
+ case CodeSourceMapBuilder::kNullCheck: {
+ const intptr_t name_index = stream.Read<int32_t>();
+ THR_Print("%" Px "-%" Px ": null check PP#%" Pd "\n",
+ start + current_pc_offset, start + current_pc_offset,
+ name_index);
+ break;
+ }
default:
UNREACHABLE();
}
@@ -624,4 +654,46 @@
THR_Print("}\n");
}
+intptr_t CodeSourceMapReader::GetNullCheckNameIndexAt(int32_t pc_offset) {
+ NoSafepointScope no_safepoint;
+ ReadStream stream(map_.Data(), map_.Length());
+
+ int32_t current_pc_offset = 0;
+
+ while (stream.PendingBytes() > 0) {
+ uint8_t opcode = stream.Read<uint8_t>();
+ switch (opcode) {
+ case CodeSourceMapBuilder::kChangePosition: {
+ stream.Read<int32_t>();
+ break;
+ }
+ case CodeSourceMapBuilder::kAdvancePC: {
+ int32_t delta = stream.Read<int32_t>();
+ current_pc_offset += delta;
+ RELEASE_ASSERT(current_pc_offset <= pc_offset);
+ break;
+ }
+ case CodeSourceMapBuilder::kPushFunction: {
+ stream.Read<int32_t>();
+ break;
+ }
+ case CodeSourceMapBuilder::kPopFunction: {
+ break;
+ }
+ case CodeSourceMapBuilder::kNullCheck: {
+ const int32_t name_index = stream.Read<int32_t>();
+ if (current_pc_offset == pc_offset) {
+ return name_index;
+ }
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ UNREACHABLE();
+ return -1;
+}
+
} // namespace dart
diff --git a/runtime/vm/code_descriptors.h b/runtime/vm/code_descriptors.h
index c31b4a1..6c0daab 100644
--- a/runtime/vm/code_descriptors.h
+++ b/runtime/vm/code_descriptors.h
@@ -222,6 +222,7 @@
static const uint8_t kAdvancePC = 1;
static const uint8_t kPushFunction = 2;
static const uint8_t kPopFunction = 3;
+ static const uint8_t kNullCheck = 4;
void StartInliningInterval(int32_t pc_offset, intptr_t inline_id);
void BeginCodeSourceRange(int32_t pc_offset);
@@ -229,6 +230,7 @@
void NoteDescriptor(RawPcDescriptors::Kind kind,
int32_t pc_offset,
TokenPosition pos);
+ void NoteNullCheck(int32_t pc_offset, TokenPosition pos, intptr_t name_index);
RawArray* InliningIdToFunction();
RawCodeSourceMap* Finalize();
@@ -265,6 +267,10 @@
written_inline_id_stack_.RemoveLast();
written_token_pos_stack_.RemoveLast();
}
+ void WriteNullCheck(int32_t name_index) {
+ stream_.Write<uint8_t>(kNullCheck);
+ stream_.Write<int32_t>(name_index);
+ }
void FlushBuffer();
void FlushBufferStack();
@@ -314,6 +320,8 @@
void DumpInlineIntervals(uword start);
void DumpSourcePositions(uword start);
+ intptr_t GetNullCheckNameIndexAt(int32_t pc_offset);
+
private:
const CodeSourceMap& map_;
const Array& functions_;
diff --git a/runtime/vm/compiler/aot/aot_call_specializer.cc b/runtime/vm/compiler/aot/aot_call_specializer.cc
index caedbd7..4fea9a6 100644
--- a/runtime/vm/compiler/aot/aot_call_specializer.cc
+++ b/runtime/vm/compiler/aot/aot_call_specializer.cc
@@ -289,7 +289,12 @@
ASSERT((cid == kDoubleCid) ||
(FLAG_limit_ints_to_64_bits && (cid == kMintCid)));
- AddCheckNull(input, call->deopt_id(), call->env(), call);
+ const String& function_name =
+ (call->IsInstanceCall()
+ ? call->AsInstanceCall()->function_name()
+ : String::ZoneHandle(Z, call->AsStaticCall()->function().name()));
+
+ AddCheckNull(input, function_name, call->deopt_id(), call->env(), call);
input = input->CopyWithType(Z);
diff --git a/runtime/vm/compiler/assembler/assembler_arm.cc b/runtime/vm/compiler/assembler/assembler_arm.cc
index 2d7bfca..86e7876 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm.cc
@@ -1745,7 +1745,7 @@
const intptr_t offset =
Isolate::class_table_offset() + ClassTable::table_offset();
LoadFromOffset(kWord, result, result, offset);
- ldr(result, Address(result, class_id, LSL, 2));
+ ldr(result, Address(result, class_id, LSL, kSizeOfClassPairLog2));
}
void Assembler::LoadClass(Register result, Register object, Register scratch) {
diff --git a/runtime/vm/compiler/assembler/assembler_arm.h b/runtime/vm/compiler/assembler/assembler_arm.h
index ab6f811..9b81f54 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.h
+++ b/runtime/vm/compiler/assembler/assembler_arm.h
@@ -141,6 +141,11 @@
static_cast<uint32_t>(rm);
}
+ static bool CanHold(uint32_t immediate) {
+ Operand dummy;
+ return CanHold(immediate, &dummy);
+ }
+
static bool CanHold(uint32_t immediate, Operand* o) {
// Avoid the more expensive test for frequent small immediate values.
if (immediate < (1 << kImmed8Bits)) {
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc
index e28333f..255c85b 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64.cc
@@ -660,24 +660,43 @@
blr(TMP);
}
-void Assembler::AddImmediate(Register dest, Register rn, int64_t imm) {
+void Assembler::AddImmediate(Register dest,
+ Register rn,
+ int64_t imm,
+ OperandSize sz) {
Operand op;
if (imm == 0) {
if (dest != rn) {
- mov(dest, rn);
+ if (sz == kWord) {
+ uxtw(dest, rn);
+ } else {
+ mov(dest, rn);
+ }
}
return;
}
if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) {
- add(dest, rn, op);
+ if (sz == kDoubleWord) {
+ add(dest, rn, op);
+ } else {
+ addw(dest, rn, op);
+ }
} else if (Operand::CanHold(-imm, kXRegSizeInBits, &op) ==
Operand::Immediate) {
- sub(dest, rn, op);
+ if (sz == kDoubleWord) {
+ sub(dest, rn, op);
+ } else {
+ subw(dest, rn, op);
+ }
} else {
// TODO(zra): Try adding top 12 bits, then bottom 12 bits.
ASSERT(rn != TMP2);
LoadImmediate(TMP2, imm);
- add(dest, rn, Operand(TMP2));
+ if (sz == kDoubleWord) {
+ add(dest, rn, Operand(TMP2));
+ } else {
+ addw(dest, rn, Operand(TMP2));
+ }
}
}
@@ -1030,6 +1049,8 @@
const intptr_t offset =
Isolate::class_table_offset() + ClassTable::table_offset();
LoadFromOffset(result, result, offset);
+ ASSERT(kSizeOfClassPairLog2 == 4);
+ add(class_id, class_id, Operand(class_id));
ldr(result, Address(result, class_id, UXTX, Address::Scaled));
}
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index 373f848..437c246 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -390,6 +390,17 @@
// undefined.
static bool IsImmLogical(uint64_t value, uint8_t width, Operand* imm_op);
+ static bool IsImmLogical(int64_t imm) {
+ Operand operand;
+ return IsImmLogical(imm, kXRegSizeInBits, &operand);
+ }
+
+ static bool IsImmArithmethic(int64_t imm) {
+ Operand operand;
+ CanHold(imm, kXRegSizeInBits, &operand);
+ return operand.type_ == Immediate;
+ }
+
// An immediate imm can be an operand to add/sub when the return value is
// Immediate, or a logical operation over sz bits when the return value is
// BitfieldImm. If the return value is Unknown, then the immediate can't be
@@ -1069,12 +1080,18 @@
const Register crn = ConcreteRegister(rn);
EmitFPIntCvtOp(SCVTFD, static_cast<Register>(vd), crn, kWord);
}
- void fcvtzds(Register rd, VRegister vn) {
+ void fcvtzdsx(Register rd, VRegister vn) {
ASSERT(rd != R31);
ASSERT(rd != CSP);
const Register crd = ConcreteRegister(rd);
EmitFPIntCvtOp(FCVTZDS, crd, static_cast<Register>(vn));
}
+ void fcvtzdsw(Register rd, VRegister vn) {
+ ASSERT(rd != R31);
+ ASSERT(rd != CSP);
+ const Register crd = ConcreteRegister(rd);
+ EmitFPIntCvtOp(FCVTZDS, crd, static_cast<Register>(vn), kWord);
+ }
void fmovdd(VRegister vd, VRegister vn) { EmitFPOneSourceOp(FMOVDD, vd, vn); }
void fabsd(VRegister vd, VRegister vn) { EmitFPOneSourceOp(FABSD, vd, vn); }
void fnegd(VRegister vd, VRegister vn) { EmitFPOneSourceOp(FNEGD, vd, vn); }
@@ -1365,9 +1382,17 @@
LslImmediate(dst, src, kSmiTagSize);
}
- void BranchIfNotSmi(Register reg, Label* label) { tbnz(label, reg, kSmiTag); }
+ void BranchIfNotSmi(Register reg, Label* label) {
+ ASSERT(kSmiTagMask == 1);
+ ASSERT(kSmiTag == 0);
+ tbnz(label, reg, 0);
+ }
- void BranchIfSmi(Register reg, Label* label) { tbz(label, reg, kSmiTag); }
+ void BranchIfSmi(Register reg, Label* label) {
+ ASSERT(kSmiTagMask == 1);
+ ASSERT(kSmiTag == 0);
+ tbz(label, reg, 0);
+ }
void Branch(const StubEntry& stub_entry,
Register pp,
@@ -1393,7 +1418,10 @@
// the object pool when possible. Unless you are sure that the untagged object
// pool pointer is in another register, or that it is not available at all,
// PP should be passed for pp.
- void AddImmediate(Register dest, Register rn, int64_t imm);
+ void AddImmediate(Register dest,
+ Register rn,
+ int64_t imm,
+ OperandSize sz = kDoubleWord);
void AddImmediateSetFlags(Register dest,
Register rn,
int64_t imm,
@@ -1451,6 +1479,11 @@
kValueCanBeSmi,
};
+ enum CanBeHeapPointer {
+ kValueIsNotHeapPointer,
+ kValueCanBeHeapPointer,
+ };
+
// Storing into an object.
void StoreIntoObject(Register object,
const Address& dest,
@@ -1500,6 +1533,7 @@
void CompareObject(Register reg, const Object& object);
void LoadClassId(Register result, Register object);
+ // Overwrites class_id register.
void LoadClassById(Register result, Register class_id);
void LoadClass(Register result, Register object);
void CompareClassId(Register object,
@@ -1591,6 +1625,43 @@
Register tmp,
OperandSize sz);
+ void AssertSmiInRange(
+ Register object,
+ CanBeHeapPointer can_be_heap_pointer = kValueIsNotHeapPointer) {
+#if defined(DEBUG)
+ Label ok;
+ if (can_be_heap_pointer == kValueCanBeHeapPointer) {
+ BranchIfNotSmi(object, &ok);
+ }
+ cmp(object, Operand(object, SXTW, 0));
+ b(&ok, EQ);
+ Stop("Smi out of range");
+
+ Bind(&ok);
+#endif
+ }
+
+ void AssertValidUint32(Register r) {
+#if defined(DEBUG)
+ Label ok;
+ cmp(ZR, Operand(r, LSR, 32));
+ b(&ok, EQ);
+ Stop("uint32 should be zero extended");
+ Bind(&ok);
+#endif
+ }
+
+ void AssertValidSignExtendedInt32(Register r) {
+#if defined(DEBUGFOO)
+ Label ok;
+ AsrImmediate(TMP, r, 63); // 0 or -1.
+ cmp(TMP, Operand(r, ASR, 31));
+ b(&ok, EQ);
+ Stop("int32 should be sign extended");
+ Bind(&ok);
+#endif
+ }
+
private:
AssemblerBuffer buffer_; // Contains position independent code.
ObjectPoolWrapper object_pool_wrapper_;
diff --git a/runtime/vm/compiler/assembler/assembler_arm64_test.cc b/runtime/vm/compiler/assembler/assembler_arm64_test.cc
index a41fad24..523688b 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64_test.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64_test.cc
@@ -2576,17 +2576,73 @@
EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(DoubleReturn, test->entry()));
}
-ASSEMBLER_TEST_GENERATE(Fcvtzds, assembler) {
+ASSEMBLER_TEST_GENERATE(Fcvtzdsx, assembler) {
__ LoadDImmediate(V0, 42.0);
- __ fcvtzds(R0, V0);
+ __ fcvtzdsx(R0, V0);
__ ret();
}
-ASSEMBLER_TEST_RUN(Fcvtzds, test) {
+ASSEMBLER_TEST_RUN(Fcvtzdsx, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(42, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
+ASSEMBLER_TEST_GENERATE(Fcvtzdsw, assembler) {
+ __ LoadDImmediate(V0, 42.0);
+ __ fcvtzdsw(R0, V0);
+ __ ret();
+}
+
+ASSEMBLER_TEST_RUN(Fcvtzdsw, test) {
+ typedef int64_t (*Int64Return)() DART_UNUSED;
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
+}
+
+ASSEMBLER_TEST_GENERATE(Fcvtzdsx_overflow, assembler) {
+ __ LoadDImmediate(V0, 1e20);
+ __ fcvtzdsx(R0, V0);
+ __ ret();
+}
+
+ASSEMBLER_TEST_RUN(Fcvtzdsx_overflow, test) {
+ typedef int64_t (*Int64Return)() DART_UNUSED;
+ EXPECT_EQ(kMaxInt64, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
+}
+
+ASSEMBLER_TEST_GENERATE(Fcvtzdsx_overflow_negative, assembler) {
+ __ LoadDImmediate(V0, -1e20);
+ __ fcvtzdsx(R0, V0);
+ __ ret();
+}
+
+ASSEMBLER_TEST_RUN(Fcvtzdsx_overflow_negative, test) {
+ typedef int64_t (*Int64Return)() DART_UNUSED;
+ EXPECT_EQ(kMinInt64, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
+}
+
+ASSEMBLER_TEST_GENERATE(Fcvtzdsw_overflow, assembler) {
+ __ LoadDImmediate(V0, 1e10);
+ __ fcvtzdsw(R0, V0);
+ __ ret();
+}
+
+ASSEMBLER_TEST_RUN(Fcvtzdsw_overflow, test) {
+ typedef int64_t (*Int64Return)() DART_UNUSED;
+ EXPECT_EQ(kMaxInt32, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
+}
+
+ASSEMBLER_TEST_GENERATE(Fcvtzdsw_overflow_negative, assembler) {
+ __ LoadDImmediate(V0, -1e10);
+ __ fcvtzdsw(R0, V0);
+ __ sxtw(R0, R0);
+ __ ret();
+}
+
+ASSEMBLER_TEST_RUN(Fcvtzdsw_overflow_negative, test) {
+ typedef int64_t (*Int64Return)() DART_UNUSED;
+ EXPECT_EQ(kMinInt32, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
+}
+
ASSEMBLER_TEST_GENERATE(Scvtfdx, assembler) {
__ LoadImmediate(R0, 42);
__ scvtfdx(V0, R0);
diff --git a/runtime/vm/compiler/assembler/assembler_ia32.cc b/runtime/vm/compiler/assembler/assembler_ia32.cc
index 035c00b..0ba938b 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32.cc
+++ b/runtime/vm/compiler/assembler/assembler_ia32.cc
@@ -2425,7 +2425,8 @@
const intptr_t offset =
Isolate::class_table_offset() + ClassTable::table_offset();
movl(result, Address(result, offset));
- movl(result, Address(result, class_id, TIMES_4, 0));
+ ASSERT(kSizeOfClassPairLog2 == 3);
+ movl(result, Address(result, class_id, TIMES_8, 0));
}
void Assembler::LoadClass(Register result, Register object, Register scratch) {
diff --git a/runtime/vm/compiler/assembler/assembler_x64.cc b/runtime/vm/compiler/assembler/assembler_x64.cc
index 72bbf42..e08f526 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.cc
+++ b/runtime/vm/compiler/assembler/assembler_x64.cc
@@ -1887,6 +1887,10 @@
const intptr_t offset =
Isolate::class_table_offset() + ClassTable::table_offset();
movq(result, Address(result, offset));
+ ASSERT(kSizeOfClassPairLog2 == 4);
+ // TIMES_16 is not a real scale factor on x64, so we double the class id
+ // and use TIMES_8.
+ addq(class_id, class_id);
movq(result, Address(result, class_id, TIMES_8, 0));
}
diff --git a/runtime/vm/compiler/assembler/assembler_x64.h b/runtime/vm/compiler/assembler/assembler_x64.h
index 5b85011..70c492a 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.h
+++ b/runtime/vm/compiler/assembler/assembler_x64.h
@@ -521,7 +521,10 @@
return CompareImmediate(reg, Immediate(immediate));
}
- void testl(Register reg, const Immediate& imm) { testq(reg, imm); }
+ void testl(Register reg, const Immediate& imm) {
+ Immediate imm2(imm.value() & 0xffffffffll);
+ testq(reg, imm2);
+ }
void testb(const Address& address, const Immediate& imm);
void testq(Register reg, const Immediate& imm);
@@ -710,6 +713,11 @@
kValueCanBeSmi,
};
+ enum CanBeHeapPointer {
+ kValueIsNotHeapPointer,
+ kValueCanBeHeapPointer,
+ };
+
// Destroys value.
void StoreIntoObject(Register object, // Object we are storing into.
const Address& dest, // Where we are storing into.
@@ -766,6 +774,7 @@
// Loading and comparing classes of objects.
void LoadClassId(Register result, Register object);
+ // Overwrites class_id register.
void LoadClassById(Register result, Register class_id);
void LoadClass(Register result, Register object);
@@ -939,6 +948,26 @@
Register array,
Register index);
+ void AssertSmiInRange(
+ Register object,
+ CanBeHeapPointer can_be_heap_pointer = kValueIsNotHeapPointer) {
+#if defined(DEBUG)
+ Register tmp = object == TMP ? TMP2 : TMP;
+ Label ok;
+ if (can_be_heap_pointer == kValueCanBeHeapPointer) {
+ testl(object, Immediate(kSmiTagMask));
+ ASSERT(kSmiTag == 0);
+ j(ZERO, &ok);
+ }
+ movsxd(tmp, object);
+ cmpq(tmp, object);
+ j(EQUAL, &ok);
+ Stop("Smi out of range");
+
+ Bind(&ok);
+#endif
+ }
+
static Address VMTagAddress() {
return Address(THR, Thread::vm_tag_offset());
}
@@ -948,6 +977,24 @@
static bool IsSafe(const Object& object) { return true; }
static bool IsSafeSmi(const Object& object) { return object.IsSmi(); }
+ void AssertValidUint32(Register r) {
+ Label ok;
+ movl(TMP, r);
+ cmpq(TMP, r);
+ j(EQUAL, &ok);
+ Stop("uint32 should be zero extended");
+ Bind(&ok);
+ }
+
+ void AssertValidSignExtendedInt32(Register r) {
+ Label ok;
+ movsxd(TMP, r);
+ cmpq(TMP, r);
+ j(EQUAL, &ok);
+ Stop("int32 should be sign extended");
+ Bind(&ok);
+ }
+
private:
AssemblerBuffer buffer_;
diff --git a/runtime/vm/compiler/backend/flow_graph.cc b/runtime/vm/compiler/backend/flow_graph.cc
index 499bfc7..df9fc5b 100644
--- a/runtime/vm/compiler/backend/flow_graph.cc
+++ b/runtime/vm/compiler/backend/flow_graph.cc
@@ -1643,10 +1643,14 @@
}
if (should_unbox) {
+#if defined(AVOID_UNBOXED_INT32)
+ unboxed = kUnboxedInt64;
+#else
unboxed =
RangeUtils::Fits(phi->range(), RangeBoundary::kRangeBoundaryInt32)
? kUnboxedInt32
: kUnboxedInt64;
+#endif
}
}
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index e7b1a69..199e17c 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -589,13 +589,14 @@
void FlowGraphCompiler::GenerateDeferredCode() {
for (intptr_t i = 0; i < slow_path_code_.length(); i++) {
+ SlowPathCode* const slow_path = slow_path_code_[i];
const CombinedCodeStatistics::EntryCounter stats_tag =
CombinedCodeStatistics::SlowPathCounterFor(
- slow_path_code_[i]->instruction()->tag());
+ slow_path->instruction()->tag());
SpecialStatsBegin(stats_tag);
BeginCodeSourceRange();
- slow_path_code_[i]->GenerateCode(this);
- EndCodeSourceRange(TokenPosition::kDeferredSlowPath);
+ slow_path->GenerateCode(this);
+ EndCodeSourceRange(slow_path->instruction()->token_pos());
SpecialStatsEnd(stats_tag);
}
for (intptr_t i = 0; i < deopt_infos_.length(); i++) {
@@ -641,6 +642,13 @@
CurrentTryIndex());
}
+void FlowGraphCompiler::AddNullCheck(intptr_t pc_offset,
+ TokenPosition token_pos,
+ intptr_t null_check_name_idx) {
+ code_source_map_builder_->NoteNullCheck(pc_offset, token_pos,
+ null_check_name_idx);
+}
+
void FlowGraphCompiler::AddStaticCallTarget(const Function& func) {
ASSERT(func.IsZoneHandle());
static_calls_target_table_.Add(
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index f61ef7b..b4123f2 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -572,6 +572,10 @@
TokenPosition token_pos,
intptr_t try_index);
+ void AddNullCheck(intptr_t pc_offset,
+ TokenPosition token_pos,
+ intptr_t null_check_name_idx);
+
void RecordSafepoint(LocationSummary* locs,
intptr_t slow_path_argument_count = 0);
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 4f2db6a..772b0e8 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -776,9 +776,7 @@
const Object& Value::BoundConstant() const {
ASSERT(BindsToConstant());
- ConstantInstr* constant = definition()->AsConstant();
- ASSERT(constant != NULL);
- return constant->value();
+ return definition()->AsConstant()->value();
}
GraphEntryInstr::GraphEntryInstr(const ParsedFunction& parsed_function,
@@ -1585,10 +1583,10 @@
return Utils::IsPowerOfTwo(Utils::Abs(int_value));
}
-static intptr_t RepresentationBits(Representation r) {
+static intptr_t SignificantRepresentationBits(Representation r) {
switch (r) {
case kTagged:
- return kBitsPerWord - 1;
+ return 31;
case kUnboxedInt32:
case kUnboxedUint32:
return 32;
@@ -1602,7 +1600,7 @@
static int64_t RepresentationMask(Representation r) {
return static_cast<int64_t>(static_cast<uint64_t>(-1) >>
- (64 - RepresentationBits(r)));
+ (64 - SignificantRepresentationBits(r)));
}
static bool ToIntegerConstant(Value* value, int64_t* result) {
@@ -1869,9 +1867,9 @@
case Token::kBIT_NOT:
if (value.IsSmi()) {
- result = Integer::New(~Smi::Cast(value).Value());
+ result = Integer::New(~Smi::Cast(value).Value(), Heap::kOld);
} else if (value.IsMint()) {
- result = Integer::New(~Mint::Cast(value).value());
+ result = Integer::New(~Mint::Cast(value).value(), Heap::kOld);
}
break;
@@ -2106,7 +2104,7 @@
case Token::kBIT_AND:
if (rhs == 0) {
return right()->definition();
- } else if (rhs == range_mask) {
+ } else if ((rhs & range_mask) == range_mask) {
return left()->definition();
}
break;
@@ -2163,7 +2161,8 @@
break;
case Token::kSHL: {
- const intptr_t kMaxShift = RepresentationBits(representation()) - 1;
+ const intptr_t kMaxShift =
+ SignificantRepresentationBits(representation()) - 1;
if (rhs == 0) {
return left()->definition();
} else if ((rhs < 0) || (rhs >= kMaxShift)) {
@@ -2494,9 +2493,11 @@
Definition* replacement = this;
switch (conv->from()) {
+#if !defined(AVOID_UNBOXED_INT32)
case kUnboxedInt32:
replacement = new BoxInt32Instr(conv->value()->CopyWithType());
break;
+#endif
case kUnboxedUint32:
replacement = new BoxUint32Instr(conv->value()->CopyWithType());
break;
@@ -2674,6 +2675,35 @@
return replacement;
}
+ if (value()->BindsToConstant()) {
+ const Object& input = value()->BoundConstant();
+ int64_t constant;
+ if (input.IsSmi()) {
+ constant = Smi::Cast(input).Value();
+ } else if (input.IsMint()) {
+ constant = Mint::Cast(input).value();
+ } else {
+ return this;
+ }
+ Definition* replacement = NULL;
+ if (to() == kUnboxedUint32) {
+ const Object& cast = Integer::Handle(
+ flow_graph->zone(),
+ Integer::New(static_cast<uint32_t>(constant), Heap::kOld));
+ replacement = new UnboxedConstantInstr(cast, kUnboxedUint32);
+ } else if (to() == kUnboxedInt32) {
+ const Object& cast = Integer::Handle(
+ flow_graph->zone(),
+ Integer::New(static_cast<int32_t>(constant), Heap::kOld));
+ replacement = new UnboxedConstantInstr(cast, kUnboxedUint32);
+ } else if (to() == kUnboxedInt64) {
+ replacement = new UnboxedConstantInstr(input, kUnboxedInt64);
+ }
+ if (replacement != NULL) {
+ flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue);
+ return replacement;
+ }
+ }
return this;
}
@@ -3019,8 +3049,10 @@
BoxInstr* BoxInstr::Create(Representation from, Value* value) {
switch (from) {
+#if !defined(AVOID_UNBOXED_INT32)
case kUnboxedInt32:
return new BoxInt32Instr(value);
+#endif
case kUnboxedUint32:
return new BoxUint32Instr(value);
@@ -3045,10 +3077,11 @@
intptr_t deopt_id,
SpeculativeMode speculative_mode) {
switch (to) {
+#if !defined(AVOID_UNBOXED_INT32)
case kUnboxedInt32:
return new UnboxInt32Instr(UnboxInt32Instr::kNoTruncation, value,
deopt_id, speculative_mode);
-
+#endif
case kUnboxedUint32:
return new UnboxUint32Instr(value, deopt_id, speculative_mode);
@@ -3970,6 +4003,8 @@
virtual const char* name() = 0;
+ virtual void AddMetadataForRuntimeCall(FlowGraphCompiler* compiler) {}
+
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
if (Assembler::EmittingComments()) {
__ Comment("slow path %s operation", name());
@@ -3985,6 +4020,7 @@
compiler->AddDescriptor(
RawPcDescriptors::kOther, compiler->assembler()->CodeSize(),
instruction()->deopt_id(), instruction()->token_pos(), try_index_);
+ AddMetadataForRuntimeCall(compiler);
compiler->RecordSafepoint(locs, num_args_);
Environment* env = compiler->SlowPathEnvironmentFor(instruction());
compiler->EmitCatchEntryState(env, try_index_);
@@ -4038,7 +4074,6 @@
class NullErrorSlowPath : public ThrowErrorSlowPathCode {
public:
- // TODO(dartbug.com/30480): Pass arguments for NoSuchMethodError.
static const intptr_t kNumberOfArguments = 0;
NullErrorSlowPath(CheckNullInstr* instruction, intptr_t try_index)
@@ -4047,7 +4082,15 @@
kNumberOfArguments,
try_index) {}
- virtual const char* name() { return "check null"; }
+ const char* name() override { return "check null"; }
+
+ void AddMetadataForRuntimeCall(FlowGraphCompiler* compiler) override {
+ const String& function_name = instruction()->AsCheckNull()->function_name();
+ const intptr_t name_index =
+ compiler->assembler()->object_pool_wrapper().FindObject(function_name);
+ compiler->AddNullCheck(compiler->assembler()->CodeSize(),
+ instruction()->token_pos(), name_index);
+ }
};
void CheckNullInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
@@ -4750,7 +4793,7 @@
// Make representaion from type name used by SIMD_OP_LIST.
#define REP(T) (kUnboxed##T)
static const Representation kUnboxedBool = kTagged;
-static const Representation kUnboxedInt8 = kUnboxedInt32;
+static const Representation kUnboxedInt8 = kUnboxedUint32;
#define ENCODE_INPUTS_0()
#define ENCODE_INPUTS_1(In0) REP(In0)
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 829a16e..6fd8fdd 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -2012,7 +2012,12 @@
virtual Representation representation() const { return representation_; }
- virtual void set_representation(Representation r) { representation_ = r; }
+ virtual void set_representation(Representation r) {
+#if defined(AVOID_UNBOXED_INT32)
+ ASSERT(r != kUnboxedInt32);
+#endif
+ representation_ = r;
+ }
virtual intptr_t Hashcode() const {
UNREACHABLE();
@@ -2799,13 +2804,14 @@
virtual TokenPosition token_pos() const { return token_pos_; }
- bool IsUnboxedSignedIntegerConstant() const {
- return representation() == kUnboxedInt32 ||
+ bool IsUnboxedIntegerConstant() const {
+ return representation() == kUnboxedUint32 ||
+ representation() == kUnboxedInt32 ||
representation() == kUnboxedInt64;
}
- int64_t GetUnboxedSignedIntegerConstantValue() const {
- ASSERT(IsUnboxedSignedIntegerConstant());
+ int64_t GetUnboxedIntegerConstantValue() const {
+ ASSERT(IsUnboxedIntegerConstant());
return value_.IsSmi() ? Smi::Cast(value_).Value()
: Mint::Cast(value_).value();
}
@@ -5428,7 +5434,11 @@
truncation_mode,
value,
deopt_id,
- speculative_mode) {}
+ speculative_mode) {
+#if defined(AVOID_UNBOXED_INT32)
+ UNREACHABLE();
+#endif
+ }
virtual bool ComputeCanDeoptimize() const;
@@ -6820,13 +6830,20 @@
// execution proceeds to the next instruction.
class CheckNullInstr : public TemplateInstruction<1, Throws, NoCSE> {
public:
- CheckNullInstr(Value* value, intptr_t deopt_id, TokenPosition token_pos)
- : TemplateInstruction(deopt_id), token_pos_(token_pos) {
+ CheckNullInstr(Value* value,
+ const String& function_name,
+ intptr_t deopt_id,
+ TokenPosition token_pos)
+ : TemplateInstruction(deopt_id),
+ token_pos_(token_pos),
+ function_name_(function_name) {
+ ASSERT(function_name.IsNotTemporaryScopedHandle());
SetInputAt(0, value);
}
Value* value() const { return inputs_[0]; }
virtual TokenPosition token_pos() const { return token_pos_; }
+ const String& function_name() const { return function_name_; }
DECLARE_INSTRUCTION(CheckNull)
@@ -6842,6 +6859,7 @@
private:
const TokenPosition token_pos_;
+ const String& function_name_;
DISALLOW_COPY_AND_ASSIGN(CheckNullInstr);
};
@@ -6956,10 +6974,15 @@
to_representation_(to),
is_truncating_(to == kUnboxedUint32) {
ASSERT(from != to);
+#if !defined(AVOID_UNBOXED_INT32)
ASSERT((from == kUnboxedInt64) || (from == kUnboxedUint32) ||
(from == kUnboxedInt32));
ASSERT((to == kUnboxedInt64) || (to == kUnboxedUint32) ||
(to == kUnboxedInt32));
+#else
+ ASSERT((from == kUnboxedInt64) || (from == kUnboxedUint32));
+ ASSERT((to == kUnboxedInt64) || (to == kUnboxedUint32));
+#endif
SetInputAt(0, value);
}
@@ -7067,6 +7090,12 @@
#define SIMD_CONVERSION(M, FromType, ToType) \
M(1, _, FromType##To##ToType, (FromType), ToType)
+#if defined(AVOID_UNBOXED_INT32)
+#define Int32x4Arg Uint32
+#else
+#define Int32x4Arg Int32
+#endif
+
// List of all recognized SIMD operations.
// Note: except for operations that map to operators (Add, Mul, Sub, Div,
// BitXor, BitOr) all other operations must match names used by
@@ -7092,7 +7121,8 @@
M(2, _, Float32x4LessThan, (Float32x4, Float32x4), Int32x4) \
M(2, _, Float32x4LessThanOrEqual, (Float32x4, Float32x4), Int32x4) \
M(2, _, Float32x4NotEqual, (Float32x4, Float32x4), Int32x4) \
- M(4, _, Int32x4Constructor, (Int32, Int32, Int32, Int32), Int32x4) \
+ M(4, _, Int32x4Constructor, \
+ (Int32x4Arg, Int32x4Arg, Int32x4Arg, Int32x4Arg), Int32x4) \
M(4, _, Int32x4BoolConstructor, (Bool, Bool, Bool, Bool), Int32x4) \
M(4, _, Float32x4Constructor, (Double, Double, Double, Double), Float32x4) \
M(2, _, Float64x2Constructor, (Double, Double), Float64x2) \
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 9b5729c..6e310bf 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -328,7 +328,8 @@
const Location& destination,
Register tmp) {
if (destination.IsRegister()) {
- if (representation() == kUnboxedInt32) {
+ if (representation() == kUnboxedInt32 ||
+ representation() == kUnboxedUint32) {
__ LoadImmediate(destination.reg(), Smi::Cast(value_).Value());
} else {
ASSERT(representation() == kTagged);
@@ -5985,34 +5986,45 @@
LocationSummary* summary = new (zone)
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
- summary->set_in(1, Location::RequiresRegister());
summary->set_out(0, Location::RequiresRegister());
+ ConstantInstr* right_constant = right()->definition()->AsConstant();
+ if (right_constant != NULL && op_kind() != Token::kMUL &&
+ right_constant->value().IsSmi() &&
+ Operand::CanHold(Smi::Cast(right_constant->value()).Value())) {
+ summary->set_in(1, Location::Constant(right_constant));
+ } else {
+ summary->set_in(1, Location::RequiresRegister());
+ }
return summary;
}
void BinaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register left = locs()->in(0).reg();
- Register right = locs()->in(1).reg();
Register out = locs()->out(0).reg();
ASSERT(out != left);
+ Location r = locs()->in(1);
+ if (op_kind() == Token::kMUL) {
+ __ mul(out, left, r.reg());
+ return;
+ }
+ const Operand right = r.IsRegister()
+ ? Operand(r.reg())
+ : Operand(Smi::Cast(r.constant()).Value());
switch (op_kind()) {
case Token::kBIT_AND:
- __ and_(out, left, Operand(right));
+ __ and_(out, left, right);
break;
case Token::kBIT_OR:
- __ orr(out, left, Operand(right));
+ __ orr(out, left, right);
break;
case Token::kBIT_XOR:
- __ eor(out, left, Operand(right));
+ __ eor(out, left, right);
break;
case Token::kADD:
- __ add(out, left, Operand(right));
+ __ add(out, left, right);
break;
case Token::kSUB:
- __ sub(out, left, Operand(right));
- break;
- case Token::kMUL:
- __ mul(out, left, right);
+ __ sub(out, left, right);
break;
default:
UNREACHABLE();
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 9c0a698..abafd9d 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -324,8 +324,9 @@
void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler,
const Location& destination,
Register tmp) {
+ ASSERT(representation() != kUnboxedInt32);
if (destination.IsRegister()) {
- if (representation() == kUnboxedInt32 ||
+ if (representation() == kUnboxedUint32 ||
representation() == kUnboxedInt64) {
const int64_t value = value_.IsSmi() ? Smi::Cast(value_).Value()
: Mint::Cast(value_).value();
@@ -353,11 +354,7 @@
ASSERT(destination.IsStackSlot());
ASSERT(tmp != kNoRegister);
const intptr_t dest_offset = destination.ToStackSlotOffset();
- if (value_.IsSmi() && representation() == kUnboxedInt32) {
- __ LoadImmediate(tmp, static_cast<int32_t>(Smi::Cast(value_).Value()));
- } else {
- __ LoadObject(tmp, value_);
- }
+ __ LoadObject(tmp, value_);
__ StoreToOffset(tmp, destination.base_reg(), dest_offset);
}
}
@@ -365,7 +362,7 @@
LocationSummary* UnboxedConstantInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 0;
- const intptr_t kNumTemps = IsUnboxedSignedIntegerConstant() ? 0 : 1;
+ const intptr_t kNumTemps = IsUnboxedIntegerConstant() ? 0 : 1;
LocationSummary* locs = new (zone)
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
switch (representation()) {
@@ -373,7 +370,7 @@
locs->set_out(0, Location::RequiresFpuRegister());
locs->set_temp(0, Location::RequiresRegister());
break;
- case kUnboxedInt32:
+ case kUnboxedUint32: // We don't used signed int32 on ARM64.
case kUnboxedInt64:
locs->set_out(0, Location::RequiresRegister());
break;
@@ -387,7 +384,7 @@
void UnboxedConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
if (!locs()->out(0).IsInvalid()) {
const Register scratch =
- IsUnboxedSignedIntegerConstant() ? kNoRegister : locs()->temp(0).reg();
+ IsUnboxedIntegerConstant() ? kNoRegister : locs()->temp(0).reg();
EmitMoveToLocation(compiler, locs()->out(0), scratch);
}
}
@@ -593,9 +590,9 @@
right_constant = right.constant_instruction();
}
- if (right_constant->IsUnboxedSignedIntegerConstant()) {
- __ CompareImmediate(
- left.reg(), right_constant->GetUnboxedSignedIntegerConstantValue());
+ if (right_constant->IsUnboxedIntegerConstant()) {
+ __ CompareImmediate(left.reg(),
+ right_constant->GetUnboxedIntegerConstantValue());
} else {
ASSERT(right_constant->representation() == kTagged);
__ CompareObject(left.reg(), right.constant());
@@ -997,9 +994,13 @@
case kTwoByteStringCid:
case kExternalOneByteStringCid:
case kExternalTwoByteStringCid:
+ return CompileType::FromCid(kSmiCid);
+
case kTypedDataInt32ArrayCid:
case kTypedDataUint32ArrayCid:
- return CompileType::FromCid(kSmiCid);
+ // TODO(erikcorry): Perhaps this can return a faster type. See
+ // https://github.com/dart-lang/sdk/issues/32582
+ return CompileType::Int();
default:
UNIMPLEMENTED();
@@ -1024,11 +1025,10 @@
case kExternalTwoByteStringCid:
return kTagged;
case kTypedDataInt32ArrayCid:
- return kUnboxedInt32;
- case kTypedDataUint32ArrayCid:
- return kUnboxedUint32;
case kTypedDataInt64ArrayCid:
return kUnboxedInt64;
+ case kTypedDataUint32ArrayCid:
+ return kUnboxedUint32;
case kTypedDataFloat32ArrayCid:
case kTypedDataFloat64ArrayCid:
return kUnboxedDouble;
@@ -1154,24 +1154,35 @@
return;
}
- if ((representation() == kUnboxedInt32) ||
- (representation() == kUnboxedUint32)) {
+ if (representation() == kUnboxedUint32) {
+ ASSERT(class_id() == kTypedDataUint32ArrayCid);
const Register result = locs()->out(0).reg();
+ if (aligned()) {
+ __ ldr(result, element_address, kUnsignedWord);
+ } else {
+ __ LoadUnaligned(result, address, TMP, kUnsignedWord);
+ }
+ __ AssertValidUint32(result);
+ return;
+ }
+
+ if (representation() == kUnboxedInt64) {
+ Register result = locs()->out(0).reg();
switch (class_id()) {
case kTypedDataInt32ArrayCid:
- ASSERT(representation() == kUnboxedInt32);
+ ASSERT(representation() == kUnboxedInt64);
if (aligned()) {
__ ldr(result, element_address, kWord);
} else {
__ LoadUnaligned(result, address, TMP, kWord);
}
+ __ AssertValidSignExtendedInt32(result);
break;
- case kTypedDataUint32ArrayCid:
- ASSERT(representation() == kUnboxedUint32);
+ case kTypedDataInt64ArrayCid:
if (aligned()) {
- __ ldr(result, element_address, kUnsignedWord);
+ __ ldr(result, element_address, kDoubleWord);
} else {
- __ LoadUnaligned(result, address, TMP, kUnsignedWord);
+ __ LoadUnaligned(result, address, TMP, kDoubleWord);
}
break;
default:
@@ -1180,17 +1191,6 @@
return;
}
- if (representation() == kUnboxedInt64) {
- ASSERT(class_id() == kTypedDataInt64ArrayCid);
- Register result = locs()->out(0).reg();
- if (aligned()) {
- __ ldr(result, element_address, kDoubleWord);
- } else {
- __ LoadUnaligned(result, address, TMP, kDoubleWord);
- }
- return;
- }
-
ASSERT(representation() == kTagged);
const Register result = locs()->out(0).reg();
switch (class_id()) {
@@ -1273,7 +1273,6 @@
default:
UNREACHABLE();
}
- __ SmiTag(result);
break;
case kTwoByteStringCid:
case kExternalTwoByteStringCid:
@@ -1287,12 +1286,15 @@
default:
UNREACHABLE();
}
- __ SmiTag(result);
break;
default:
UNREACHABLE();
break;
}
+ if (representation_ == kTagged) {
+ ASSERT(can_pack_into_smi());
+ __ SmiTag(result);
+ }
}
Representation StoreIndexedInstr::RequiredInputRepresentation(
@@ -1313,7 +1315,6 @@
case kTypedDataUint16ArrayCid:
return kTagged;
case kTypedDataInt32ArrayCid:
- return kUnboxedInt32;
case kTypedDataUint32ArrayCid:
return kUnboxedUint32;
case kTypedDataInt64ArrayCid:
@@ -2770,18 +2771,27 @@
if (locs.in(1).IsConstant()) {
const Object& constant = locs.in(1).constant();
ASSERT(constant.IsSmi());
- // Immediate shift operation takes 6 bits for the count.
- const intptr_t kCountLimit = 0x3F;
+ // Immediate shift operation takes 5 bits for the count.
+ const intptr_t kCountLimit = 0x1F;
+ // These should be around the same size.
+ COMPILE_ASSERT(kCountLimit + 1 == kSmiBits + 2);
const intptr_t value = Smi::Cast(constant).Value();
ASSERT((0 < value) && (value < kCountLimit));
if (shift_left->can_overflow()) {
// Check for overflow (preserve left).
- __ LslImmediate(TMP, left, value);
- __ cmp(left, Operand(TMP, ASR, value));
+ __ LslImmediate(TMP, left, value, kWord);
+ __ cmpw(left, Operand(TMP, ASR, value));
__ b(deopt, NE); // Overflow.
}
- // Shift for result now we know there is no overflow.
+ // Shift for result now we know there is no overflow. This writes the full
+ // 64 bits of the output register, but unless we are in truncating mode the
+ // top bits will just be sign extension bits.
__ LslImmediate(result, left, value);
+ if (shift_left->is_truncating()) {
+ // This preserves the invariant that Smis only use the low 32 bits of the
+ // register, the high bits being sign extension bits.
+ __ sxtw(result, result);
+ }
return;
}
@@ -2789,28 +2799,33 @@
const Register right = locs.in(1).reg();
Range* right_range = shift_left->right_range();
if (shift_left->left()->BindsToConstant() && shift_left->can_overflow()) {
- // TODO(srdjan): Implement code below for is_truncating().
// If left is constant, we know the maximal allowed size for right.
const Object& obj = shift_left->left()->BoundConstant();
- if (obj.IsSmi()) {
- const intptr_t left_int = Smi::Cast(obj).Value();
- if (left_int == 0) {
- __ CompareRegisters(right, ZR);
- __ b(deopt, MI);
- __ mov(result, ZR);
- return;
- }
- const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int);
- const bool right_needs_check =
- !RangeUtils::IsWithin(right_range, 0, max_right - 1);
- if (right_needs_check) {
- __ CompareImmediate(right,
- reinterpret_cast<int64_t>(Smi::New(max_right)));
- __ b(deopt, CS);
- }
- __ SmiUntag(TMP, right);
- __ lslv(result, left, TMP);
+ // Even though we have a non-Smi constant on the left, we might still emit
+ // a Smi op here. In that case the Smi check above will have deopted, so
+ // we can't reach this point. Emit a breakpoint to be sure.
+ if (!obj.IsSmi()) {
+ __ Breakpoint();
+ return;
}
+ const intptr_t left_int = Smi::Cast(obj).Value();
+ if (left_int == 0) {
+ __ CompareRegisters(right, ZR);
+ __ b(deopt, MI);
+ __ mov(result, ZR);
+ return;
+ }
+ const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int);
+ const bool right_needs_check =
+ !RangeUtils::IsWithin(right_range, 0, max_right - 1);
+ if (right_needs_check) {
+ __ CompareImmediate(right,
+ reinterpret_cast<int64_t>(Smi::New(max_right)));
+ __ b(deopt, CS);
+ }
+ __ SmiUntag(TMP, right);
+ __ lslv(result, left, TMP);
+ ASSERT(!shift_left->is_truncating());
return;
}
@@ -2834,7 +2849,11 @@
__ SmiUntag(TMP, right);
__ lslv(result, left, TMP);
}
+ if (shift_left->is_truncating()) {
+ __ sxtw(result, result);
+ }
} else {
+ // If we can overflow.
if (right_needs_check) {
ASSERT(shift_left->CanDeoptimize());
__ CompareImmediate(right,
@@ -2842,15 +2861,16 @@
__ b(deopt, CS);
}
// Left is not a constant.
- // Check if count too large for handling it inlined.
+ // Check if count is too large for handling it inlined.
__ SmiUntag(TMP, right);
// Overflow test (preserve left, right, and TMP);
const Register temp = locs.temp(0).reg();
- __ lslv(temp, left, TMP);
- __ asrv(TMP2, temp, TMP);
- __ CompareRegisters(left, TMP2);
+ __ lslvw(temp, left, TMP);
+ __ asrvw(TMP2, temp, TMP);
+ __ cmpw(left, Operand(TMP2));
__ b(deopt, NE); // Overflow.
- // Shift for result now we know there is no overflow.
+ // Shift for result now we know there is no overflow. This is a 64 bit
+ // operation, so no sign extension is needed.
__ lslv(result, left, TMP);
}
}
@@ -2931,18 +2951,20 @@
switch (op_kind()) {
case Token::kADD:
- __ adds(result, left, Operand(right));
+ __ addsw(result, left, Operand(right));
__ b(slow_path->entry_label(), VS);
+ __ sxtw(result, result);
break;
case Token::kSUB:
- __ subs(result, left, Operand(right));
+ __ subsw(result, left, Operand(right));
__ b(slow_path->entry_label(), VS);
+ __ sxtw(result, result);
break;
case Token::kMUL:
__ SmiUntag(TMP, left);
- __ mul(result, TMP, right);
- __ smulh(TMP, TMP, right);
- // TMP: result bits 64..127.
+ __ smull(result, TMP, right);
+ __ AsrImmediate(TMP, result, 31);
+ // TMP: result bits 31-63
__ cmp(TMP, Operand(result, ASR, 63));
__ b(slow_path->entry_label(), NE);
break;
@@ -2967,8 +2989,8 @@
__ SmiUntag(TMP, right);
__ lslv(result, left, TMP);
- __ asrv(TMP2, result, TMP);
- __ CompareRegisters(left, TMP2);
+ __ asrvw(TMP2, result, TMP);
+ __ cmp(left, Operand(TMP2, SXTW, 0));
__ b(slow_path->entry_label(), NE); // Overflow.
break;
case Token::kSHR:
@@ -2978,6 +3000,8 @@
reinterpret_cast<int64_t>(Smi::New(Smi::kBits)));
__ b(slow_path->entry_label(), CS);
+ __ AssertSmiInRange(left);
+ __ AssertSmiInRange(right);
__ SmiUntag(result, right);
__ SmiUntag(TMP, left);
__ asrv(result, TMP, result);
@@ -2987,6 +3011,7 @@
UNIMPLEMENTED();
}
__ Bind(slow_path->exit_label());
+ __ AssertSmiInRange(result, Assembler::kValueCanBeHeapPointer);
}
class CheckedSmiComparisonSlowPath
@@ -3177,20 +3202,28 @@
case Token::kADD: {
if (deopt == NULL) {
__ AddImmediate(result, left, imm);
+ if (is_truncating()) {
+ __ sxtw(result, result);
+ }
} else {
- __ AddImmediateSetFlags(result, left, imm);
+ __ AddImmediateSetFlags(result, left, imm, kWord);
__ b(deopt, VS);
+ __ sxtw(result, result);
}
break;
}
case Token::kSUB: {
if (deopt == NULL) {
__ AddImmediate(result, left, -imm);
+ if (is_truncating()) {
+ __ sxtw(result, result);
+ }
} else {
// Negating imm and using AddImmediateSetFlags would not detect the
- // overflow when imm == kMinInt64.
- __ SubImmediateSetFlags(result, left, imm);
+ // overflow when imm == kMinInt32.
+ __ SubImmediateSetFlags(result, left, imm, kWord);
__ b(deopt, VS);
+ __ sxtw(result, result);
}
break;
}
@@ -3198,12 +3231,14 @@
// Keep left value tagged and untag right value.
const intptr_t value = Smi::Cast(constant).Value();
__ LoadImmediate(TMP, value);
- __ mul(result, left, TMP);
+ __ smull(result, left, TMP);
if (deopt != NULL) {
- __ smulh(TMP, left, TMP);
- // TMP: result bits 64..127.
+ __ AsrImmediate(TMP, result, 31);
+ // TMP: result bits 31..63.
__ cmp(TMP, Operand(result, ASR, 63));
__ b(deopt, NE);
+ } else if (is_truncating()) {
+ __ sxtw(result, result);
}
break;
}
@@ -3214,9 +3249,10 @@
const intptr_t shift_count =
Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize;
ASSERT(kSmiTagSize == 1);
- __ AsrImmediate(TMP, left, 63);
+ __ AsrImmediate(TMP, left, 31); // All 1s or all 0s.
ASSERT(shift_count > 1); // 1, -1 case handled above.
const Register temp = TMP2;
+ // Adjust so that we round to 0 instead of round down.
__ add(temp, left, Operand(TMP, LSR, 64 - shift_count));
ASSERT(shift_count > 0);
__ AsrImmediate(result, temp, shift_count);
@@ -3251,6 +3287,7 @@
UNREACHABLE();
break;
}
+ __ AssertSmiInRange(result);
return;
}
@@ -3259,18 +3296,26 @@
case Token::kADD: {
if (deopt == NULL) {
__ add(result, left, Operand(right));
+ if (is_truncating()) {
+ __ sxtw(result, result);
+ }
} else {
- __ adds(result, left, Operand(right));
+ __ addsw(result, left, Operand(right));
__ b(deopt, VS);
+ __ sxtw(result, result);
}
break;
}
case Token::kSUB: {
if (deopt == NULL) {
__ sub(result, left, Operand(right));
+ if (is_truncating()) {
+ __ sxtw(result, result);
+ }
} else {
- __ subs(result, left, Operand(right));
+ __ subsw(result, left, Operand(right));
__ b(deopt, VS);
+ __ sxtw(result, result);
}
break;
}
@@ -3278,10 +3323,13 @@
__ SmiUntag(TMP, left);
if (deopt == NULL) {
__ mul(result, TMP, right);
+ if (is_truncating()) {
+ __ sxtw(result, result);
+ }
} else {
- __ mul(result, TMP, right);
- __ smulh(TMP, TMP, right);
- // TMP: result bits 64..127.
+ __ smull(result, TMP, right);
+ __ AsrImmediate(TMP, result, 31);
+ // TMP: result bits 31..63.
__ cmp(TMP, Operand(result, ASR, 63));
__ b(deopt, NE);
}
@@ -3316,7 +3364,7 @@
// Check the corner case of dividing the 'MIN_SMI' with -1, in which
// case we cannot tag the result.
- __ CompareImmediate(result, 0x4000000000000000LL);
+ __ CompareImmediate(result, 0x40000000LL);
__ b(deopt, EQ);
__ SmiTag(result);
break;
@@ -3361,8 +3409,10 @@
__ b(deopt, LT);
}
__ SmiUntag(TMP, right);
- // sarl operation masks the count to 6 bits.
- const intptr_t kCountLimit = 0x3F;
+ // The asrv operation masks the count to 6 bits, but any shift between 31
+ // and 63 gives the same result because 32 bit Smis are stored sign
+ // extended in the registers.
+ const intptr_t kCountLimit = 0x1F;
if (!RangeUtils::OnlyLessThanOrEqualTo(right_range(), kCountLimit)) {
__ LoadImmediate(TMP2, kCountLimit);
__ CompareRegisters(TMP, TMP2);
@@ -3391,6 +3441,7 @@
UNREACHABLE();
break;
}
+ __ AssertSmiInRange(result);
}
LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(Zone* zone,
@@ -3540,13 +3591,19 @@
LocationSummary* BoxInteger32Instr::MakeLocationSummary(Zone* zone,
bool opt) const {
- ASSERT((from_representation() == kUnboxedInt32) ||
- (from_representation() == kUnboxedUint32));
+ ASSERT(from_representation() == kUnboxedUint32);
const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = 0;
+ const intptr_t kNumTemps = ValueFitsSmi() ? 0 : 1;
LocationSummary* summary = new (zone)
- LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ LocationSummary(zone, kNumInputs, kNumTemps,
+ ValueFitsSmi() ? LocationSummary::kNoCall
+ : LocationSummary::kCallOnSlowPath);
+ // Get two distinct registers for input and output, plus a temp
+ // register for testing for overflow and allocating a Mint.
summary->set_in(0, Location::RequiresRegister());
+ if (!ValueFitsSmi()) {
+ summary->set_temp(0, Location::RequiresRegister());
+ }
summary->set_out(0, Location::RequiresRegister());
return summary;
}
@@ -3555,16 +3612,51 @@
Register value = locs()->in(0).reg();
Register out = locs()->out(0).reg();
ASSERT(value != out);
+ Label done;
- ASSERT(kSmiTagSize == 1);
- // TODO(vegorov) implement and use UBFM/SBFM for this.
- __ LslImmediate(out, value, 32);
if (from_representation() == kUnboxedInt32) {
- __ AsrImmediate(out, out, 32 - kSmiTagSize);
+ ASSERT(kSmiTag == 0);
+ // Signed Bitfield Insert in Zero instruction extracts the 31 significant
+ // bits from a Smi.
+ __ sbfiz(out, value, kSmiTagSize, 32 - kSmiTagSize);
+ if (ValueFitsSmi()) {
+ return;
+ }
+ Register temp = locs()->temp(0).reg();
+ __ cmp(out, Operand(value, LSL, 1));
+ __ b(&done, EQ); // Jump if the sbfiz instruction didn't lose info.
+ BoxAllocationSlowPath::Allocate(compiler, this, compiler->mint_class(), out,
+ temp);
+ __ sxtw(temp, value);
} else {
ASSERT(from_representation() == kUnboxedUint32);
- __ LsrImmediate(out, out, 32 - kSmiTagSize);
+ ASSERT(kSmiTag == 0);
+ // A 32 bit positive Smi has one tag bit and one unused sign bit,
+ // leaving only 30 bits for the payload.
+ __ ubfiz(out, value, kSmiTagSize, kSmiBits);
+ if (ValueFitsSmi()) {
+ return;
+ }
+ Register temp = locs()->temp(0).reg();
+ __ TestImmediate(value, 0xc0000000);
+ __ b(&done, EQ); // Jump if both bits are zero.
+ BoxAllocationSlowPath::Allocate(compiler, this, compiler->mint_class(), out,
+ temp);
+ __ ubfiz(temp, value, 0, 32); // Zero extend word.
}
+
+ __ StoreToOffset(locs()->temp(0).reg(), out,
+ Mint::value_offset() - kHeapObjectTag);
+
+#if defined(DEBUG)
+ Label skip_smi_test;
+ __ b(&skip_smi_test);
+ __ Bind(&done);
+ __ AssertSmiInRange(out, Assembler::kValueCanBeHeapPointer);
+ __ Bind(&skip_smi_test);
+#else
+ __ Bind(&done);
+#endif
}
LocationSummary* BoxInt64Instr::MakeLocationSummary(Zone* zone,
@@ -3592,7 +3684,8 @@
}
ASSERT(kSmiTag == 0);
- __ LslImmediate(out, in, kSmiTagSize);
+ __ LslImmediate(out, in, kSmiTagSize, kWord);
+ __ sxtw(out, out);
Label done;
__ cmp(in, Operand(out, ASR, kSmiTagSize));
__ b(&done, EQ);
@@ -3617,44 +3710,37 @@
}
void UnboxInteger32Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ // We don't use unboxed signed int32 on 64 bit platforms, so this is an
+ // unboxing to 32 bit unsigned integer, zero extended.
+ ASSERT(representation() == kUnboxedUint32);
+ ASSERT(is_truncating());
const intptr_t value_cid = value()->Type()->ToCid();
const Register out = locs()->out(0).reg();
const Register value = locs()->in(0).reg();
- Label* deopt = CanDeoptimize() ? compiler->AddDeoptStub(
- GetDeoptId(), ICData::kDeoptUnboxInteger)
- : NULL;
if (value_cid == kSmiCid) {
- __ SmiUntag(out, value);
+ ASSERT(kSmiTagSize == 1);
+ // Unsigned bitfield extract, untags the Smi, truncating to 32 bit unsigned.
+ __ ubfx(out, value, 1, 32);
} else if (value_cid == kMintCid) {
- __ LoadFieldFromOffset(out, value, Mint::value_offset());
- } else if (!CanDeoptimize()) {
- // Type information is not conclusive, but range analysis found
- // the value to be in int64 range. Therefore it must be a smi
- // or mint value.
- ASSERT(is_truncating());
- Label done;
- __ SmiUntag(out, value);
- __ BranchIfSmi(value, &done);
- __ LoadFieldFromOffset(out, value, Mint::value_offset());
- __ Bind(&done);
+ __ LoadFieldFromOffset(out, value, Mint::value_offset(), kUnsignedWord);
} else {
+ // Type information is not conclusive.
Label done;
- __ SmiUntag(out, value);
+ ASSERT(kSmiTagSize == 1);
+ // Unsigned bitfield extract, untags the Smi, truncating to 32 bit unsigned.
+ __ ubfx(out, value, 1, 32);
__ BranchIfSmi(value, &done);
- __ CompareClassId(value, kMintCid);
- __ b(deopt, NE);
- __ LoadFieldFromOffset(out, value, Mint::value_offset());
+ if (CanDeoptimize()) {
+ Label* deopt =
+ compiler->AddDeoptStub(GetDeoptId(), ICData::kDeoptUnboxInteger);
+ __ CompareClassId(value, kMintCid);
+ __ b(deopt, NE);
+ }
+ __ LoadFieldFromOffset(out, value, Mint::value_offset(), kUnsignedWord);
__ Bind(&done);
}
-
- // TODO(vegorov): as it is implemented right now truncating unboxing would
- // leave "garbage" in the higher word.
- if (!is_truncating() && (deopt != NULL)) {
- ASSERT(representation() == kUnboxedInt32);
- __ cmp(out, Operand(out, SXTW, 0));
- __ b(deopt, NE);
- }
+ __ AssertValidUint32(out);
}
LocationSummary* BinaryDoubleOpInstr::MakeLocationSummary(Zone* zone,
@@ -4333,8 +4419,9 @@
switch (op_kind()) {
case Token::kNEGATE: {
Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryOp);
- __ subs(result, ZR, Operand(value));
+ __ subsw(result, ZR, Operand(value));
__ b(deopt, VS);
+ __ sxtw(result, result);
break;
}
case Token::kBIT_NOT:
@@ -4345,6 +4432,7 @@
default:
UNREACHABLE();
}
+ __ AssertSmiInRange(result);
}
LocationSummary* UnaryDoubleOpInstr::MakeLocationSummary(Zone* zone,
@@ -4396,7 +4484,7 @@
const Register value = locs()->in(0).reg();
const VRegister result = locs()->out(0).fpu_reg();
__ SmiUntag(TMP, value);
- __ scvtfdx(result, TMP);
+ __ scvtfdw(result, TMP);
}
LocationSummary* Int64ToDoubleInstr::MakeLocationSummary(Zone* zone,
@@ -4440,12 +4528,13 @@
__ fcmpd(VTMP, VTMP);
__ b(&do_call, VS);
- __ fcvtzds(result, VTMP);
+ __ fcvtzdsx(result, VTMP);
// Overflow is signaled with minint.
// Check for overflow and that it fits into Smi.
- __ CompareImmediate(result, 0xC000000000000000);
- __ b(&do_call, MI);
+ __ AsrImmediate(TMP, result, 30);
+ __ cmp(TMP, Operand(result, ASR, 63));
+ __ b(&do_call, NE);
__ SmiTag(result);
__ b(&done);
__ Bind(&do_call);
@@ -4462,6 +4551,7 @@
args_info, locs(), ICData::Handle(),
ICData::kStatic);
__ Bind(&done);
+ __ AssertSmiInRange(result, Assembler::kValueCanBeHeapPointer);
}
LocationSummary* DoubleToSmiInstr::MakeLocationSummary(Zone* zone,
@@ -4485,11 +4575,13 @@
__ fcmpd(value, value);
__ b(deopt, VS);
- __ fcvtzds(result, value);
+ __ fcvtzdsx(result, value);
// Check for overflow and that it fits into Smi.
- __ CompareImmediate(result, 0xC000000000000000);
- __ b(deopt, MI);
+ __ AsrImmediate(TMP, result, 30);
+ __ cmp(TMP, Operand(result, ASR, 63));
+ __ b(deopt, NE);
__ SmiTag(result);
+ __ AssertSmiInRange(result);
}
LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(Zone* zone,
@@ -4758,7 +4850,7 @@
// Check the corner case of dividing the 'MIN_SMI' with -1, in which
// case we cannot tag the result.
- __ CompareImmediate(result_div, 0x4000000000000000);
+ __ CompareImmediate(result_div, 0x40000000);
__ b(deopt, EQ);
// result_mod <- left - right * result_div.
__ msub(result_mod, TMP, result_div, result_mod);
@@ -5007,8 +5099,7 @@
Register r = TMP;
if (right.IsConstant()) {
ConstantInstr* constant_instr = right.constant_instruction();
- const int64_t value =
- constant_instr->GetUnboxedSignedIntegerConstantValue();
+ const int64_t value = constant_instr->GetUnboxedIntegerConstantValue();
__ LoadImmediate(r, value);
} else {
r = right.reg();
@@ -5025,8 +5116,7 @@
if (right.IsConstant()) {
ConstantInstr* constant_instr = right.constant_instruction();
- const int64_t value =
- constant_instr->GetUnboxedSignedIntegerConstantValue();
+ const int64_t value = constant_instr->GetUnboxedIntegerConstantValue();
switch (op_kind()) {
case Token::kADD:
if (CanDeoptimize()) {
@@ -5206,37 +5296,82 @@
LocationSummary* summary = new (zone)
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
- summary->set_in(1, Location::RequiresRegister());
summary->set_out(0, Location::RequiresRegister());
+ ConstantInstr* right_constant = right()->definition()->AsConstant();
+ if (right_constant != NULL &&
+ (right_constant->value().IsSmi() || right_constant->value().IsMint())) {
+ int64_t imm = right_constant->GetUnboxedIntegerConstantValue();
+ bool is_arithmetic = op_kind() == Token::kADD || op_kind() == Token::kSUB;
+ bool is_logical = op_kind() == Token::kBIT_AND ||
+ op_kind() == Token::kBIT_OR ||
+ op_kind() == Token::kBIT_XOR;
+ if ((is_logical && Operand::IsImmLogical(imm)) ||
+ (is_arithmetic && Operand::IsImmArithmethic(imm))) {
+ summary->set_in(1, Location::Constant(right_constant));
+ return summary;
+ }
+ }
+ summary->set_in(1, Location::RequiresRegister());
return summary;
}
void BinaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ ConstantInstr* right_constant = right()->definition()->AsConstant();
Register left = locs()->in(0).reg();
- Register right = locs()->in(1).reg();
- Operand r = Operand(right);
+ Location right = locs()->in(1);
Register out = locs()->out(0).reg();
- switch (op_kind()) {
- case Token::kBIT_AND:
- __ and_(out, left, r);
- break;
- case Token::kBIT_OR:
- __ orr(out, left, r);
- break;
- case Token::kBIT_XOR:
- __ eor(out, left, r);
- break;
- case Token::kADD:
- __ addw(out, left, r);
- break;
- case Token::kSUB:
- __ subw(out, left, r);
- break;
- case Token::kMUL:
- __ mulw(out, left, right);
- break;
- default:
- UNREACHABLE();
+ int64_t imm = 0;
+ if (right_constant != NULL) {
+ const Object& constant = right_constant->value();
+ if (constant.IsSmi()) {
+ imm = Smi::Cast(constant).AsInt64Value();
+ } else {
+ imm = Mint::Cast(constant).value();
+ }
+ }
+ if (right.IsRegister()) {
+ switch (op_kind()) {
+ case Token::kBIT_AND:
+ __ and_(out, left, Operand(right.reg()));
+ break;
+ case Token::kBIT_OR:
+ __ orr(out, left, Operand(right.reg()));
+ break;
+ case Token::kBIT_XOR:
+ __ eor(out, left, Operand(right.reg()));
+ break;
+ case Token::kADD:
+ __ addw(out, left, Operand(right.reg()));
+ break;
+ case Token::kSUB:
+ __ subw(out, left, Operand(right.reg()));
+ break;
+ case Token::kMUL:
+ __ mulw(out, left, right.reg());
+ break;
+ default:
+ UNREACHABLE();
+ }
+ } else {
+ switch (op_kind()) {
+ case Token::kBIT_AND:
+ __ andi(out, left, Immediate(imm));
+ break;
+ case Token::kBIT_OR:
+ __ orri(out, left, Immediate(imm));
+ break;
+ case Token::kBIT_XOR:
+ __ eori(out, left, Immediate(imm));
+ break;
+ case Token::kADD:
+ __ AddImmediate(out, left, imm, kWord);
+ break;
+ case Token::kSUB:
+ __ AddImmediate(out, left, -imm, kWord);
+ break;
+ default:
+ UNREACHABLE();
+ }
}
}
@@ -5287,6 +5422,10 @@
Register shifter = locs()->in(1).reg();
// TODO(johnmccutchan): Use range information to avoid these checks.
+ // Assert this is a legitimate Smi in debug mode, but does not assert
+ // anything about the range relative to the bit width.
+ __ AssertSmiInRange(shifter);
+
__ SmiUntag(TMP, shifter);
__ CompareImmediate(TMP, 0);
// If shift value is < 0, deoptimize.
@@ -5306,7 +5445,7 @@
__ CompareImmediate(TMP, kShifterLimit);
// If shift value is > 31, return zero.
- __ csel(out, out, ZR, GT);
+ __ csel(out, ZR, out, GT);
}
LocationSummary* UnaryUint32OpInstr::MakeLocationSummary(Zone* zone,
@@ -5337,19 +5476,14 @@
LocationSummary* summary = new (zone)
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
if (from() == kUnboxedInt64) {
- ASSERT((to() == kUnboxedUint32) || (to() == kUnboxedInt32));
- } else if (to() == kUnboxedInt64) {
- ASSERT((from() == kUnboxedUint32) || (from() == kUnboxedInt32));
+ ASSERT(to() == kUnboxedUint32); // No unboxed int32 on ARM64.
} else {
- ASSERT((to() == kUnboxedUint32) || (to() == kUnboxedInt32));
- ASSERT((from() == kUnboxedUint32) || (from() == kUnboxedInt32));
+ ASSERT(to() == kUnboxedInt64);
+ ASSERT(from() == kUnboxedUint32); // No unboxed int32 on ARM64.
}
+ ASSERT(!CanDeoptimize());
summary->set_in(0, Location::RequiresRegister());
- if (CanDeoptimize()) {
- summary->set_out(0, Location::RequiresRegister());
- } else {
- summary->set_out(0, Location::SameAsFirstInput());
- }
+ summary->set_out(0, Location::SameAsFirstInput());
return summary;
}
@@ -5357,52 +5491,16 @@
ASSERT(from() != to()); // We don't convert from a representation to itself.
const Register value = locs()->in(0).reg();
const Register out = locs()->out(0).reg();
- Label* deopt = !CanDeoptimize() ? NULL
- : compiler->AddDeoptStub(
- deopt_id(), ICData::kDeoptUnboxInteger);
- if (from() == kUnboxedInt32 && to() == kUnboxedUint32) {
- if (CanDeoptimize()) {
- __ tbnz(deopt, value,
- 31); // If sign bit is set it won't fit in a uint32.
- }
- if (out != value) {
- __ mov(out, value); // For positive values the bits are the same.
- }
- } else if (from() == kUnboxedUint32 && to() == kUnboxedInt32) {
- if (CanDeoptimize()) {
- __ tbnz(deopt, value,
- 31); // If high bit is set it won't fit in an int32.
- }
- if (out != value) {
- __ mov(out, value); // For 31 bit values the bits are the same.
- }
- } else if (from() == kUnboxedInt64) {
- if (to() == kUnboxedInt32) {
- if (is_truncating() || out != value) {
- __ sxtw(out, value); // Signed extension 64->32.
- }
- } else {
- ASSERT(to() == kUnboxedUint32);
- if (is_truncating() || out != value) {
- __ uxtw(out, value); // Unsigned extension 64->32.
- }
- }
- if (CanDeoptimize()) {
- ASSERT(to() == kUnboxedInt32);
- __ cmp(out, Operand(value));
- __ b(deopt, NE); // Value cannot be held in Int32, deopt.
- }
- } else if (to() == kUnboxedInt64) {
- if (from() == kUnboxedUint32) {
- if (out != value) {
- __ mov(out, value);
- }
- } else {
- ASSERT(from() == kUnboxedInt32);
- __ sxtw(out, value); // Signed extension 32->64.
- }
+ ASSERT(!CanDeoptimize());
+ if (from() == kUnboxedInt64) {
+ ASSERT(to() == kUnboxedUint32);
+ __ uxtw(out, value); // Zero the top bits.
} else {
- UNREACHABLE();
+ ASSERT(from() == kUnboxedUint32);
+ ASSERT(to() == kUnboxedInt64);
+ if (out != value) {
+ __ mov(out, value); // Bits are the same.
+ }
}
}
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index c92b517..4505c0f 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -187,7 +187,8 @@
if (destination.IsRegister()) {
if (value_.IsSmi() && Smi::Cast(value_).Value() == 0) {
__ xorl(destination.reg(), destination.reg());
- } else if (value_.IsSmi() && (representation() == kUnboxedInt32)) {
+ } else if (value_.IsSmi() && (representation() == kUnboxedInt32 ||
+ representation() == kUnboxedUint32)) {
__ movl(destination.reg(), Immediate(Smi::Cast(value_).Value()));
} else {
ASSERT(representation() == kTagged);
@@ -3236,6 +3237,16 @@
bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = (op_kind() == Token::kMUL) ? 1 : 0;
+ ConstantInstr* right_constant = right()->definition()->AsConstant();
+ if (right_constant != NULL && right_constant->value().IsSmi() &&
+ op_kind() != Token::kMUL) {
+ LocationSummary* summary = new (zone)
+ LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresRegister());
+ summary->set_in(1, Location::Constant(right_constant));
+ summary->set_out(0, Location::SameAsFirstInput());
+ return summary;
+ }
LocationSummary* summary = new (zone)
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
if (op_kind() == Token::kMUL) {
@@ -3251,25 +3262,33 @@
void BinaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register left = locs()->in(0).reg();
- Register right = locs()->in(1).reg();
Register out = locs()->out(0).reg();
ASSERT(out == left);
- switch (op_kind()) {
- case Token::kBIT_AND:
- case Token::kBIT_OR:
- case Token::kBIT_XOR:
- case Token::kADD:
- case Token::kSUB:
- EmitIntegerArithmetic(compiler, op_kind(), left, right, NULL);
- return;
+ if (locs()->in(1).IsRegister()) {
+ Register right = locs()->in(1).reg();
+ switch (op_kind()) {
+ case Token::kBIT_AND:
+ case Token::kBIT_OR:
+ case Token::kBIT_XOR:
+ case Token::kADD:
+ case Token::kSUB:
+ EmitIntegerArithmetic(compiler, op_kind(), left, right, NULL);
+ return;
- case Token::kMUL:
- __ mull(right); // Result in EDX:EAX.
- ASSERT(out == EAX);
- ASSERT(locs()->temp(0).reg() == EDX);
- break;
- default:
- UNREACHABLE();
+ case Token::kMUL:
+ __ mull(right); // Result in EDX:EAX.
+ ASSERT(out == EAX);
+ ASSERT(locs()->temp(0).reg() == EDX);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ } else {
+ ASSERT(locs()->in(1).IsConstant());
+ ConstantInstr* right_constant = right()->definition()->AsConstant();
+ const Object& constant = right_constant->value();
+ int64_t imm = Smi::Cast(constant).AsInt64Value();
+ EmitIntegerArithmetic(compiler, op_kind(), left, Immediate(imm), NULL);
}
}
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index b44d650..a564b48 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -287,7 +287,7 @@
const Location& destination,
Register tmp) {
if (destination.IsRegister()) {
- if (representation() == kUnboxedInt32 ||
+ if (representation() == kUnboxedUint32 ||
representation() == kUnboxedInt64) {
const int64_t value = value_.IsSmi() ? Smi::Cast(value_).Value()
: Mint::Cast(value_).value();
@@ -320,19 +320,14 @@
__ movsd(destination.ToStackSlotAddress(), XMM0);
} else {
ASSERT(destination.IsStackSlot());
- if (value_.IsSmi() && representation() == kUnboxedInt32) {
- __ movl(destination.ToStackSlotAddress(),
- Immediate(Smi::Cast(value_).Value()));
- } else {
- __ StoreObject(destination.ToStackSlotAddress(), value_);
- }
+ __ StoreObject(destination.ToStackSlotAddress(), value_);
}
}
LocationSummary* UnboxedConstantInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 0;
- const intptr_t kNumTemps = IsUnboxedSignedIntegerConstant() ? 0 : 1;
+ const intptr_t kNumTemps = IsUnboxedIntegerConstant() ? 0 : 1;
LocationSummary* locs = new (zone)
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
switch (representation()) {
@@ -340,7 +335,7 @@
locs->set_out(0, Location::RequiresFpuRegister());
locs->set_temp(0, Location::RequiresRegister());
break;
- case kUnboxedInt32:
+ case kUnboxedUint32:
case kUnboxedInt64:
locs->set_out(0, Location::RequiresRegister());
break;
@@ -355,7 +350,7 @@
// The register allocator drops constant definitions that have no uses.
if (!locs()->out(0).IsInvalid()) {
const Register scratch =
- IsUnboxedSignedIntegerConstant() ? kNoRegister : locs()->temp(0).reg();
+ IsUnboxedIntegerConstant() ? kNoRegister : locs()->temp(0).reg();
EmitMoveToLocation(compiler, locs()->out(0), scratch);
}
}
@@ -609,9 +604,9 @@
constant = right.constant_instruction();
}
- if (constant->IsUnboxedSignedIntegerConstant()) {
+ if (constant->IsUnboxedIntegerConstant()) {
__ cmpq(left.reg(),
- Immediate(constant->GetUnboxedSignedIntegerConstantValue()));
+ Immediate(constant->GetUnboxedIntegerConstantValue()));
} else {
ASSERT(constant->representation() == kTagged);
__ CompareObject(left.reg(), right.constant());
@@ -1074,11 +1069,13 @@
case kTwoByteStringCid:
case kExternalOneByteStringCid:
case kExternalTwoByteStringCid:
- case kTypedDataInt32ArrayCid:
- case kTypedDataUint32ArrayCid:
return CompileType::FromCid(kSmiCid);
+ case kTypedDataInt32ArrayCid:
+ case kTypedDataUint32ArrayCid:
case kTypedDataInt64ArrayCid:
+ // TODO(erikcorry): Perhaps this can return a faster type. See
+ // https://github.com/dart-lang/sdk/issues/32582
return CompileType::Int();
default:
@@ -1103,10 +1100,9 @@
case kExternalOneByteStringCid:
case kExternalTwoByteStringCid:
return kTagged;
- case kTypedDataInt32ArrayCid:
- return kUnboxedInt32;
case kTypedDataUint32ArrayCid:
return kUnboxedUint32;
+ case kTypedDataInt32ArrayCid:
case kTypedDataInt64ArrayCid:
return kUnboxedInt64;
case kTypedDataFloat32ArrayCid:
@@ -1191,20 +1187,31 @@
return;
}
- if ((representation() == kUnboxedUint32) ||
- (representation() == kUnboxedInt32)) {
+ if ((representation() == kUnboxedUint32)) {
+ ASSERT(class_id() == kTypedDataUint32ArrayCid);
+ if ((index_scale() == 1) && index.IsRegister()) {
+ __ SmiUntag(index.reg());
+ }
+ Register result = locs()->out(0).reg();
+ __ movl(result, element_address);
+ return;
+ }
+
+ if (representation() == kUnboxedInt64) {
if ((index_scale() == 1) && index.IsRegister()) {
__ SmiUntag(index.reg());
}
Register result = locs()->out(0).reg();
switch (class_id()) {
case kTypedDataInt32ArrayCid:
- ASSERT(representation() == kUnboxedInt32);
- __ movsxd(result, element_address);
- break;
- case kTypedDataUint32ArrayCid:
- ASSERT(representation() == kUnboxedUint32);
+ ASSERT(representation() == kUnboxedInt64);
__ movl(result, element_address);
+ __ movsxd(result, result);
+ __ AssertValidSignExtendedInt32(result);
+ break;
+ case kTypedDataInt64ArrayCid:
+ ASSERT(representation() == kUnboxedInt64);
+ __ movq(result, element_address);
break;
default:
UNREACHABLE();
@@ -1212,16 +1219,6 @@
return;
}
- if (representation() == kUnboxedInt64) {
- ASSERT(class_id() == kTypedDataInt64ArrayCid);
- if ((index_scale() == 1) && index.IsRegister()) {
- __ SmiUntag(index.reg());
- }
- Register result = locs()->out(0).reg();
- __ movq(result, element_address);
- return;
- }
-
ASSERT(representation() == kTagged);
if ((index_scale() == 1) && index.IsRegister()) {
@@ -1261,16 +1258,24 @@
LocationSummary* LoadCodeUnitsInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
+ const bool might_box = (representation() == kTagged) && !can_pack_into_smi();
const intptr_t kNumInputs = 2;
- const intptr_t kNumTemps = 0;
- LocationSummary* summary = new (zone)
- LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ const intptr_t kNumTemps = might_box ? 2 : 0;
+ LocationSummary* summary = new (zone) LocationSummary(
+ zone, kNumInputs, kNumTemps,
+ might_box ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
// The smi index is either untagged (element size == 1), or it is left smi
// tagged (for all element sizes > 1).
summary->set_in(1, index_scale() == 1 ? Location::WritableRegister()
: Location::RequiresRegister());
summary->set_out(0, Location::RequiresRegister());
+
+ if (might_box) {
+ summary->set_temp(0, Location::RequiresRegister());
+ summary->set_temp(1, Location::RequiresRegister());
+ }
+
return summary;
}
@@ -1302,7 +1307,6 @@
default:
UNREACHABLE();
}
- __ SmiTag(result);
break;
case kTwoByteStringCid:
case kExternalTwoByteStringCid:
@@ -1316,12 +1320,34 @@
default:
UNREACHABLE();
}
- __ SmiTag(result);
break;
default:
UNREACHABLE();
break;
}
+ if (representation_ == kTagged) {
+ if (can_pack_into_smi()) {
+ __ SmiTag(result);
+ } else {
+ // If the value cannot fit in a smi then allocate a mint box for it.
+ Register temp = locs()->temp(0).reg();
+ Register temp2 = locs()->temp(1).reg();
+ // Temp register needs to be manually preserved on allocation slow-path.
+ locs()->live_registers()->Add(locs()->temp(0), kUnboxedInt32);
+
+ ASSERT(temp != result);
+ __ MoveRegister(temp, result);
+ __ SmiTag(result);
+
+ Label done;
+ __ TestImmediate(temp, Immediate(0xc0000000ll));
+ __ j(ZERO, &done);
+ BoxAllocationSlowPath::Allocate(compiler, this, compiler->mint_class(),
+ result, temp2);
+ __ movq(FieldAddress(result, Mint::value_offset()), temp);
+ __ Bind(&done);
+ }
+ }
}
Representation StoreIndexedInstr::RequiredInputRepresentation(
@@ -1340,10 +1366,9 @@
case kTypedDataInt16ArrayCid:
case kTypedDataUint16ArrayCid:
return kTagged;
- case kTypedDataInt32ArrayCid:
- return kUnboxedInt32;
case kTypedDataUint32ArrayCid:
return kUnboxedUint32;
+ case kTypedDataInt32ArrayCid:
case kTypedDataInt64ArrayCid:
return kUnboxedInt64;
case kTypedDataFloat32ArrayCid:
@@ -2711,27 +2736,32 @@
if (locs.in(1).IsConstant()) {
const Object& constant = locs.in(1).constant();
ASSERT(constant.IsSmi());
- // shlq operation masks the count to 6 bits.
- const intptr_t kCountLimit = 0x3F;
+ // shll operation masks the count to 5 bits.
+ const intptr_t kCountLimit = 0x1F;
const intptr_t value = Smi::Cast(constant).Value();
ASSERT((0 < value) && (value < kCountLimit));
if (shift_left->can_overflow()) {
if (value == 1) {
// Use overflow flag.
- __ shlq(left, Immediate(1));
+ __ shll(left, Immediate(1));
__ j(OVERFLOW, deopt);
+ __ movsxd(left, left);
return;
}
// Check for overflow.
Register temp = locs.temp(0).reg();
__ movq(temp, left);
- __ shlq(left, Immediate(value));
- __ sarq(left, Immediate(value));
+ __ shll(left, Immediate(value));
+ __ sarl(left, Immediate(value));
+ __ movsxd(left, left);
__ cmpq(left, temp);
__ j(NOT_EQUAL, deopt); // Overflow.
}
// Shift for result now we know there is no overflow.
__ shlq(left, Immediate(value));
+ if (shift_left->is_truncating()) {
+ __ movsxd(left, left);
+ }
return;
}
@@ -2742,23 +2772,32 @@
// TODO(srdjan): Implement code below for is_truncating().
// If left is constant, we know the maximal allowed size for right.
const Object& obj = shift_left->left()->BoundConstant();
- if (obj.IsSmi()) {
- const intptr_t left_int = Smi::Cast(obj).Value();
- if (left_int == 0) {
- __ CompareImmediate(right, Immediate(0));
- __ j(NEGATIVE, deopt);
- return;
- }
- const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int);
- const bool right_needs_check =
- !RangeUtils::IsWithin(right_range, 0, max_right - 1);
- if (right_needs_check) {
- __ CompareImmediate(
- right, Immediate(reinterpret_cast<int64_t>(Smi::New(max_right))));
- __ j(ABOVE_EQUAL, deopt);
- }
- __ SmiUntag(right);
- __ shlq(left, right);
+ // Even though we have a non-Smi constant on the left, we might still emit
+ // a Smi op here. In that case the Smi check above will have deopted, so
+ // we can't reach this point. Emit a breakpoint to be sure.
+ if (!obj.IsSmi()) {
+ __ int3();
+ return;
+ }
+ const intptr_t left_int = Smi::Cast(obj).Value();
+ if (left_int == 0) {
+ __ CompareImmediate(right, Immediate(0));
+ __ j(NEGATIVE, deopt);
+ return;
+ }
+ const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int);
+ const bool right_needs_check =
+ !RangeUtils::IsWithin(right_range, 0, max_right - 1);
+ if (right_needs_check) {
+ __ CompareImmediate(
+ right, Immediate(reinterpret_cast<int64_t>(Smi::New(max_right))));
+ __ j(ABOVE_EQUAL, deopt);
+ }
+ __ AssertSmiInRange(right);
+ __ SmiUntag(right);
+ __ shlq(left, right);
+ if (shift_left->is_truncating()) {
+ __ movsxd(left, left);
}
return;
}
@@ -2782,13 +2821,18 @@
__ xorq(left, left);
__ jmp(&done, Assembler::kNearJump);
__ Bind(&is_not_zero);
+ __ AssertSmiInRange(right);
__ SmiUntag(right);
__ shlq(left, right);
__ Bind(&done);
} else {
+ __ AssertSmiInRange(right);
__ SmiUntag(right);
__ shlq(left, right);
}
+ if (shift_left->is_truncating()) {
+ __ movsxd(left, left);
+ }
} else {
if (right_needs_check) {
ASSERT(shift_left->CanDeoptimize());
@@ -2798,16 +2842,18 @@
}
// Left is not a constant.
Register temp = locs.temp(0).reg();
- // Check if count too large for handling it inlined.
- __ movq(temp, left);
+ // Check if count is too large for handling it inlined.
+ __ movl(temp, left);
+ __ AssertSmiInRange(right);
__ SmiUntag(right);
// Overflow test (preserve temp and right);
- __ shlq(left, right);
- __ sarq(left, right);
- __ cmpq(left, temp);
+ __ shll(temp, right);
+ __ sarl(temp, right);
+ __ cmpl(temp, left);
__ j(NOT_EQUAL, deopt); // Overflow.
// Shift for result now we know there is no overflow.
__ shlq(left, right);
+ ASSERT(!shift_left->is_truncating());
}
}
@@ -2907,19 +2953,23 @@
switch (op_kind()) {
case Token::kADD:
__ movq(result, left);
- __ addq(result, right);
+ __ addl(result, right);
__ j(OVERFLOW, slow_path->entry_label());
+ __ movsxd(result, result);
break;
case Token::kSUB:
__ movq(result, left);
- __ subq(result, right);
+ __ subl(result, right);
__ j(OVERFLOW, slow_path->entry_label());
+ __ movsxd(result, result);
break;
case Token::kMUL:
__ movq(result, left);
+ __ AssertSmiInRange(result);
__ SmiUntag(result);
- __ imulq(result, right);
+ __ imull(result, right);
__ j(OVERFLOW, slow_path->entry_label());
+ __ movsxd(result, result);
break;
case Token::kBIT_OR:
ASSERT(left == result);
@@ -2940,13 +2990,15 @@
__ j(ABOVE_EQUAL, slow_path->entry_label());
__ movq(RCX, right);
+ __ AssertSmiInRange(RCX);
__ SmiUntag(RCX);
__ movq(result, left);
- __ shlq(result, RCX);
+ __ shll(result, RCX);
__ movq(TMP, result);
- __ sarq(TMP, RCX);
- __ cmpq(TMP, left);
+ __ sarl(TMP, RCX);
+ __ cmpl(TMP, left);
__ j(NOT_EQUAL, slow_path->entry_label());
+ __ movsxd(result, result);
break;
case Token::kSHR: {
Label shift_count_ok;
@@ -2955,6 +3007,8 @@
__ cmpq(right, Immediate(Smi::RawValue(Smi::kBits)));
__ j(ABOVE_EQUAL, slow_path->entry_label());
+ __ AssertSmiInRange(left);
+ __ AssertSmiInRange(right);
__ movq(RCX, right);
__ SmiUntag(RCX);
__ movq(result, left);
@@ -3103,6 +3157,16 @@
Immediate(reinterpret_cast<int64_t>(constant.raw())).is_int32();
}
+static bool CanBeUint32Immediate(const Object& constant) {
+ if (constant.IsSmi()) {
+ return Immediate(Smi::Cast(constant).Value()).is_uint32();
+ }
+ if (constant.IsMint()) {
+ return Immediate(Mint::Cast(constant).value()).is_uint32();
+ }
+ return false;
+}
+
static bool IsSmiValue(const Object& constant, intptr_t value) {
return constant.IsSmi() && (Smi::Cast(constant).Value() == value);
}
@@ -3212,20 +3276,41 @@
const int64_t imm = reinterpret_cast<int64_t>(constant.raw());
switch (op_kind()) {
case Token::kADD: {
- __ AddImmediate(left, Immediate(imm));
- if (deopt != NULL) __ j(OVERFLOW, deopt);
+ if (deopt != NULL) {
+ __ AddImmediate(left, Immediate(imm), Assembler::k32Bit);
+ __ j(OVERFLOW, deopt);
+ } else {
+ __ AddImmediate(left, Immediate(imm), Assembler::k64Bit);
+ }
+ if (deopt != NULL || is_truncating()) {
+ __ movsxd(left, left);
+ }
break;
}
case Token::kSUB: {
- __ SubImmediate(left, Immediate(imm));
- if (deopt != NULL) __ j(OVERFLOW, deopt);
+ if (deopt != NULL) {
+ __ SubImmediate(left, Immediate(imm), Assembler::k32Bit);
+ __ j(OVERFLOW, deopt);
+ } else {
+ __ SubImmediate(left, Immediate(imm), Assembler::k64Bit);
+ }
+ if (deopt != NULL || is_truncating()) {
+ __ movsxd(left, left);
+ }
break;
}
case Token::kMUL: {
// Keep left value tagged and untag right value.
const intptr_t value = Smi::Cast(constant).Value();
- __ MulImmediate(left, Immediate(value));
- if (deopt != NULL) __ j(OVERFLOW, deopt);
+ if (deopt != NULL) {
+ __ MulImmediate(left, Immediate(value), Assembler::k32Bit);
+ __ j(OVERFLOW, deopt);
+ } else {
+ __ MulImmediate(left, Immediate(value), Assembler::k64Bit);
+ }
+ if (deopt != NULL || is_truncating()) {
+ __ movsxd(left, left);
+ }
break;
}
case Token::kTRUNCDIV: {
@@ -3237,7 +3322,9 @@
ASSERT(kSmiTagSize == 1);
Register temp = locs()->temp(0).reg();
__ movq(temp, left);
- __ sarq(temp, Immediate(63));
+ // Since Smis are sign extended this is enough shift to put all-1s or
+ // all-0s in the temp register.
+ __ sarq(temp, Immediate(31));
ASSERT(shift_count > 1); // 1, -1 case handled above.
__ shrq(temp, Immediate(64 - shift_count));
__ addq(left, temp);
@@ -3266,8 +3353,10 @@
}
case Token::kSHR: {
- // sarq operation masks the count to 6 bits.
- const intptr_t kCountLimit = 0x3F;
+ // The sarq operation masks the count to 6 bits, but any shift between
+ // 31 and 63 gives the same result because 32 bit Smis are stored sign
+ // extended in the registers.
+ const intptr_t kCountLimit = 0x1F;
const intptr_t value = Smi::Cast(constant).Value();
__ sarq(left,
Immediate(Utils::Minimum(value + kSmiTagSize, kCountLimit)));
@@ -3279,6 +3368,7 @@
UNREACHABLE();
break;
}
+ __ AssertSmiInRange(left);
return;
} // locs()->in(1).IsConstant().
@@ -3286,19 +3376,40 @@
const Address& right = locs()->in(1).ToStackSlotAddress();
switch (op_kind()) {
case Token::kADD: {
- __ addq(left, right);
- if (deopt != NULL) __ j(OVERFLOW, deopt);
+ if (deopt != NULL) {
+ __ addl(left, right);
+ __ j(OVERFLOW, deopt);
+ } else {
+ __ addq(left, right);
+ }
+ if (deopt != NULL || is_truncating()) {
+ __ movsxd(left, left);
+ }
break;
}
case Token::kSUB: {
- __ subq(left, right);
- if (deopt != NULL) __ j(OVERFLOW, deopt);
+ if (deopt != NULL) {
+ __ subl(left, right);
+ __ j(OVERFLOW, deopt);
+ } else {
+ __ subq(left, right);
+ }
+ if (deopt != NULL || is_truncating()) {
+ __ movsxd(left, left);
+ }
break;
}
case Token::kMUL: {
__ SmiUntag(left);
- __ imulq(left, right);
- if (deopt != NULL) __ j(OVERFLOW, deopt);
+ if (deopt != NULL) {
+ __ imull(left, right);
+ __ j(OVERFLOW, deopt);
+ } else {
+ __ imulq(left, right);
+ }
+ if (deopt != NULL || is_truncating()) {
+ __ movsxd(left, left);
+ }
break;
}
case Token::kBIT_AND: {
@@ -3327,19 +3438,40 @@
Register right = locs()->in(1).reg();
switch (op_kind()) {
case Token::kADD: {
- __ addq(left, right);
- if (deopt != NULL) __ j(OVERFLOW, deopt);
+ if (deopt != NULL) {
+ __ addl(left, right);
+ __ j(OVERFLOW, deopt);
+ } else {
+ __ addq(left, right);
+ }
+ if (deopt != NULL || is_truncating()) {
+ __ movsxd(left, left);
+ }
break;
}
case Token::kSUB: {
- __ subq(left, right);
- if (deopt != NULL) __ j(OVERFLOW, deopt);
+ if (deopt != NULL) {
+ __ subl(left, right);
+ __ j(OVERFLOW, deopt);
+ } else {
+ __ subq(left, right);
+ }
+ if (deopt != NULL || is_truncating()) {
+ __ movsxd(left, left);
+ }
break;
}
case Token::kMUL: {
__ SmiUntag(left);
- __ imulq(left, right);
- if (deopt != NULL) __ j(OVERFLOW, deopt);
+ if (deopt != NULL) {
+ __ imull(left, right);
+ __ j(OVERFLOW, deopt);
+ } else {
+ __ imulq(left, right);
+ }
+ if (deopt != NULL || is_truncating()) {
+ __ movsxd(left, left);
+ }
break;
}
case Token::kBIT_AND: {
@@ -3358,8 +3490,6 @@
break;
}
case Token::kTRUNCDIV: {
- Label not_32bit, done;
-
Register temp = locs()->temp(0).reg();
ASSERT(left == RAX);
ASSERT((right != RDX) && (right != RAX));
@@ -3370,43 +3500,20 @@
__ testq(right, right);
__ j(ZERO, deopt);
}
- // Check if both operands fit into 32bits as idiv with 64bit operands
- // requires twice as many cycles and has much higher latency.
- // We are checking this before untagging them to avoid corner case
- // dividing INT_MAX by -1 that raises exception because quotient is
- // too large for 32bit register.
- __ movsxd(temp, left);
- __ cmpq(temp, left);
- __ j(NOT_EQUAL, ¬_32bit);
- __ movsxd(temp, right);
- __ cmpq(temp, right);
- __ j(NOT_EQUAL, ¬_32bit);
-
// Both operands are 31bit smis. Divide using 32bit idiv.
__ SmiUntag(left);
__ SmiUntag(right);
__ cdq();
__ idivl(right);
- __ movsxd(result, result);
- __ jmp(&done);
-
- // Divide using 64bit idiv.
- __ Bind(¬_32bit);
- __ SmiUntag(left);
- __ SmiUntag(right);
- __ cqo(); // Sign extend RAX -> RDX:RAX.
- __ idivq(right); // RAX: quotient, RDX: remainder.
// Check the corner case of dividing the 'MIN_SMI' with -1, in which
// case we cannot tag the result.
- __ CompareImmediate(result, Immediate(0x4000000000000000));
+ __ cmpl(result, Immediate(0x40000000));
__ j(EQUAL, deopt);
- __ Bind(&done);
+ __ movsxd(result, result);
__ SmiTag(result);
break;
}
case Token::kMOD: {
- Label not_32bit, div_done;
-
Register temp = locs()->temp(0).reg();
ASSERT(left == RDX);
ASSERT((right != RDX) && (right != RAX));
@@ -3417,17 +3524,6 @@
__ testq(right, right);
__ j(ZERO, deopt);
}
- // Check if both operands fit into 32bits as idiv with 64bit operands
- // requires twice as many cycles and has much higher latency.
- // We are checking this before untagging them to avoid corner case
- // dividing INT_MAX by -1 that raises exception because quotient is
- // too large for 32bit register.
- __ movsxd(temp, left);
- __ cmpq(temp, left);
- __ j(NOT_EQUAL, ¬_32bit);
- __ movsxd(temp, right);
- __ cmpq(temp, right);
- __ j(NOT_EQUAL, ¬_32bit);
// Both operands are 31bit smis. Divide using 32bit idiv.
__ SmiUntag(left);
__ SmiUntag(right);
@@ -3435,16 +3531,7 @@
__ cdq();
__ idivl(right);
__ movsxd(result, result);
- __ jmp(&div_done);
- // Divide using 64bit idiv.
- __ Bind(¬_32bit);
- __ SmiUntag(left);
- __ SmiUntag(right);
- __ movq(RAX, RDX);
- __ cqo(); // Sign extend RAX -> RDX:RAX.
- __ idivq(right); // RAX: quotient, RDX: remainder.
- __ Bind(&div_done);
// res = left % right;
// if (res < 0) {
// if (right < 0) {
@@ -3482,7 +3569,10 @@
__ j(LESS, deopt);
}
__ SmiUntag(right);
- // sarq operation masks the count to 6 bits.
+ // The sarq operation masks the count to 6 bits, but any shift between 31
+ // and 63 gives the same result because 32 bit Smis are stored sign
+ // extended in the registers. We check for 63 in order to take the branch
+ // more predictably.
const intptr_t kCountLimit = 0x3F;
if (!RangeUtils::OnlyLessThanOrEqualTo(right_range(), kCountLimit)) {
__ CompareImmediate(right, Immediate(kCountLimit));
@@ -3681,7 +3771,12 @@
LocationSummary* summary = new (zone)
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
- summary->set_out(0, Location::SameAsFirstInput());
+ const intptr_t value_cid = value()->Type()->ToCid();
+ if (value_cid == kSmiCid || value_cid == kMintCid) {
+ summary->set_out(0, Location::SameAsFirstInput());
+ } else {
+ summary->set_out(0, Location::RequiresRegister());
+ }
if (kNumTemps > 0) {
summary->set_temp(0, Location::RequiresRegister());
}
@@ -3689,75 +3784,88 @@
}
void UnboxInteger32Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ // We don't use unboxed signed int32 on 64 bit platforms, so this is an
+ // unboxing to 32 bit unsigned integer, zero extended.
+ ASSERT(representation() == kUnboxedUint32);
+ ASSERT(is_truncating());
const intptr_t value_cid = value()->Type()->ToCid();
const Register value = locs()->in(0).reg();
- Label* deopt = CanDeoptimize() ? compiler->AddDeoptStub(
- GetDeoptId(), ICData::kDeoptUnboxInteger)
- : NULL;
- ASSERT(value == locs()->out(0).reg());
+ const Register out = locs()->out(0).reg();
+ Label done_and_no_need_to_check_range;
if (value_cid == kSmiCid) {
- __ SmiUntag(value);
+ ASSERT(value == out);
+ __ AssertSmiInRange(value);
+ // A 32 bit Smi (31 bits plus tag) can just be made into a uint32 with a 32
+ // bit sar operation.
+ __ sarl(value, Immediate(kSmiTagShift));
} else if (value_cid == kMintCid) {
- __ movq(value, FieldAddress(value, Mint::value_offset()));
- } else if (!CanDeoptimize()) {
- // Type information is not conclusive, but range analysis found
- // the value to be in int64 range. Therefore it must be a smi
- // or mint value.
- ASSERT(is_truncating());
- Label done;
- __ SmiUntag(value);
- __ j(NOT_CARRY, &done, Assembler::kNearJump);
- __ movq(value, Address(value, TIMES_2, Mint::value_offset()));
- __ Bind(&done);
- return;
+ ASSERT(value == out);
+ __ movl(value, FieldAddress(value, Mint::value_offset()));
} else {
Label done;
- // Optimistically untag value.
- __ SmiUntagOrCheckClass(value, kMintCid, &done);
- __ j(NOT_EQUAL, deopt);
- // Undo untagging by multiplying value with 2.
- __ movq(value, Address(value, TIMES_2, Mint::value_offset()));
+ ASSERT(out != value);
+ __ movl(out, value);
+ __ sarl(out, Immediate(kSmiTagShift)); // See sarl comment above.
+ ASSERT(kSmiTag == 0);
+ __ j(NOT_CARRY, &done, Assembler::kNearJump);
+ if (CanDeoptimize()) {
+ Label* deopt =
+ compiler->AddDeoptStub(GetDeoptId(), ICData::kDeoptUnboxInteger);
+ __ LoadClassId(TMP, value);
+ __ cmpl(TMP, Immediate(kMintCid));
+ __ j(NOT_EQUAL, deopt);
+ }
+ __ movl(out, FieldAddress(value, Mint::value_offset()));
__ Bind(&done);
}
-
- // TODO(vegorov): as it is implemented right now truncating unboxing would
- // leave "garbage" in the higher word.
- if (!is_truncating() && (deopt != NULL)) {
- ASSERT(representation() == kUnboxedInt32);
- Register temp = locs()->temp(0).reg();
- __ movsxd(temp, value);
- __ cmpq(temp, value);
- __ j(NOT_EQUAL, deopt);
- }
+ __ AssertValidUint32(locs()->out(0).reg());
}
LocationSummary* BoxInteger32Instr::MakeLocationSummary(Zone* zone,
bool opt) const {
- ASSERT((from_representation() == kUnboxedInt32) ||
- (from_representation() == kUnboxedUint32));
+ ASSERT(from_representation() == kUnboxedUint32);
const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = 0;
+ const intptr_t kNumTemps = ValueFitsSmi() ? 0 : 1;
LocationSummary* summary = new (zone)
- LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
- summary->set_in(0, Location::RequiresRegister());
- summary->set_out(0, Location::RequiresRegister());
+ LocationSummary(zone, kNumInputs, kNumTemps,
+ ValueFitsSmi() ? LocationSummary::kNoCall
+ : LocationSummary::kCallOnSlowPath);
+ const bool needs_writable_input =
+ ValueFitsSmi() || (from_representation() == kUnboxedUint32);
+ summary->set_in(0, needs_writable_input ? Location::RequiresRegister()
+ : Location::WritableRegister());
+ if (!ValueFitsSmi()) {
+ summary->set_temp(0, Location::RequiresRegister());
+ }
+ summary->set_out(0, ValueFitsSmi() ? Location::SameAsFirstInput()
+ : Location::RequiresRegister());
return summary;
}
void BoxInteger32Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Register value = locs()->in(0).reg();
const Register out = locs()->out(0).reg();
- ASSERT(value != out);
- ASSERT(kSmiTagSize == 1);
- if (from_representation() == kUnboxedInt32) {
- __ movsxd(out, value);
- } else {
- ASSERT(from_representation() == kUnboxedUint32);
- __ movl(out, value);
+ // Unsigned unboxed 32 bit to sign extended 31 bit Smi.
+ __ leaq(out, Address(value, value, TIMES_1, 0));
+
+ if (!ValueFitsSmi()) {
+ Label done;
+ ASSERT(value != out);
+ __ TestImmediate(value, Immediate(0xc0000000ll));
+ __ j(ZERO, &done);
+
+ // Allocate a mint.
+ // Value input is a writable register and we have to inform the compiler of
+ // the type so it can be preserved untagged on the slow path
+ locs()->live_registers()->Add(locs()->in(0), kUnboxedInt32);
+ BoxAllocationSlowPath::Allocate(compiler, this, compiler->mint_class(), out,
+ locs()->temp(0).reg());
+ __ AssertValidUint32(value);
+ __ movq(FieldAddress(out, Mint::value_offset()), value);
+ __ Bind(&done);
}
- __ SmiTag(out);
}
LocationSummary* BoxInt64Instr::MakeLocationSummary(Zone* zone,
@@ -3779,15 +3887,20 @@
void BoxInt64Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Register out = locs()->out(0).reg();
const Register value = locs()->in(0).reg();
- __ MoveRegister(out, value);
- __ SmiTag(out);
+ __ leaq(out, Address(value, value, TIMES_1, 0));
if (!ValueFitsSmi()) {
const Register temp = locs()->temp(0).reg();
Label done;
- __ j(NO_OVERFLOW, &done);
+ __ movq(temp, value);
+ __ sarq(temp, Immediate(30));
+ __ addq(temp, Immediate(1));
+ __ cmpq(temp, Immediate(2));
+ __ j(BELOW, &done);
+
BoxAllocationSlowPath::Allocate(compiler, this, compiler->mint_class(), out,
temp);
__ movq(FieldAddress(out, Mint::value_offset()), value);
+
__ Bind(&done);
}
}
@@ -4349,8 +4462,9 @@
switch (op_kind()) {
case Token::kNEGATE: {
Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryOp);
+ __ cmpq(value, Immediate(-0x80000000ll));
+ __ j(EQUAL, deopt);
__ negq(value);
- __ j(OVERFLOW, deopt);
break;
}
case Token::kBIT_NOT:
@@ -4499,6 +4613,7 @@
void SmiToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register value = locs()->in(0).reg();
FpuRegister result = locs()->out(0).fpu_reg();
+ __ AssertSmiInRange(value);
__ SmiUntag(value);
__ cvtsi2sdq(result, value);
}
@@ -4528,14 +4643,15 @@
ASSERT(result != value_obj);
ASSERT(result != temp);
__ movsd(value_double, FieldAddress(value_obj, Double::value_offset()));
- __ cvttsd2siq(result, value_double);
+ __ cvttsd2sil(result, value_double);
// Overflow is signalled with minint.
Label do_call, done;
// Check for overflow and that it fits into Smi.
- __ movq(temp, result);
- __ shlq(temp, Immediate(1));
+ __ movl(temp, result);
+ __ shll(temp, Immediate(1));
__ j(OVERFLOW, &do_call, Assembler::kNearJump);
- __ SmiTag(result);
+ ASSERT(kSmiTagShift == 1 && kSmiTag == 0);
+ __ movsxd(result, temp);
__ jmp(&done);
__ Bind(&do_call);
__ pushq(value_obj);
@@ -4571,14 +4687,15 @@
XmmRegister value = locs()->in(0).fpu_reg();
Register temp = locs()->temp(0).reg();
- __ cvttsd2siq(result, value);
+ __ cvttsd2sil(result, value);
// Overflow is signalled with minint.
Label do_call, done;
// Check for overflow and that it fits into Smi.
- __ movq(temp, result);
- __ shlq(temp, Immediate(1));
+ __ movl(temp, result);
+ __ shll(temp, Immediate(1));
__ j(OVERFLOW, deopt);
- __ SmiTag(result);
+ ASSERT(kSmiTagShift == 1 && kSmiTag == 0);
+ __ movsxd(result, temp);
}
LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(Zone* zone,
@@ -4877,6 +4994,7 @@
// Both inputs must be writable because they will be untagged.
summary->set_in(0, Location::RegisterLocation(RAX));
summary->set_in(1, Location::WritableRegister());
+ // Output is a pair of registers.
summary->set_out(0, Location::Pair(Location::RegisterLocation(RAX),
Location::RegisterLocation(RDX)));
return summary;
@@ -4891,50 +5009,26 @@
PairLocation* pair = locs()->out(0).AsPairLocation();
Register result1 = pair->At(0).reg();
Register result2 = pair->At(1).reg();
- Label not_32bit, done;
- Register temp = RDX;
- ASSERT(left == RAX);
- ASSERT((right != RDX) && (right != RAX));
- ASSERT(result1 == RAX);
- ASSERT(result2 == RDX);
if (RangeUtils::CanBeZero(divisor_range())) {
// Handle divide by zero in runtime.
__ testq(right, right);
__ j(ZERO, deopt);
}
- // Check if both operands fit into 32bits as idiv with 64bit operands
- // requires twice as many cycles and has much higher latency.
- // We are checking this before untagging them to avoid corner case
- // dividing INT_MAX by -1 that raises exception because quotient is
- // too large for 32bit register.
- __ movsxd(temp, left);
- __ cmpq(temp, left);
- __ j(NOT_EQUAL, ¬_32bit);
- __ movsxd(temp, right);
- __ cmpq(temp, right);
- __ j(NOT_EQUAL, ¬_32bit);
-
+ ASSERT(left == RAX);
+ ASSERT((right != RDX) && (right != RAX));
+ ASSERT(result1 == RAX);
+ ASSERT(result2 == RDX);
// Both operands are 31bit smis. Divide using 32bit idiv.
__ SmiUntag(left);
__ SmiUntag(right);
__ cdq();
__ idivl(right);
- __ movsxd(RAX, RAX);
- __ movsxd(RDX, RDX);
- __ jmp(&done);
-
- // Divide using 64bit idiv.
- __ Bind(¬_32bit);
- __ SmiUntag(left);
- __ SmiUntag(right);
- __ cqo(); // Sign extend RAX -> RDX:RAX.
- __ idivq(right); // RAX: quotient, RDX: remainder.
// Check the corner case of dividing the 'MIN_SMI' with -1, in which
// case we cannot tag the result.
- __ CompareImmediate(RAX, Immediate(0x4000000000000000));
+ __ cmpl(RAX, Immediate(0x40000000));
__ j(EQUAL, deopt);
- __ Bind(&done);
-
+ __ movsxd(RAX, RAX);
+ __ movsxd(RDX, RDX);
// Modulo correction (RDX).
// res = left % right;
// if (res < 0) {
@@ -4944,16 +5038,16 @@
// res = res + right;
// }
// }
- Label all_done;
+ Label done;
__ cmpq(RDX, Immediate(0));
- __ j(GREATER_EQUAL, &all_done, Assembler::kNearJump);
+ __ j(GREATER_EQUAL, &done, Assembler::kNearJump);
// Result is negative, adjust it.
if ((divisor_range() == NULL) || divisor_range()->Overlaps(-1, 1)) {
Label subtract;
__ cmpq(right, Immediate(0));
__ j(LESS, &subtract, Assembler::kNearJump);
__ addq(RDX, right);
- __ jmp(&all_done, Assembler::kNearJump);
+ __ jmp(&done, Assembler::kNearJump);
__ Bind(&subtract);
__ subq(RDX, right);
} else if (divisor_range()->IsPositive()) {
@@ -4963,7 +5057,7 @@
// Right is negative.
__ subq(RDX, right);
}
- __ Bind(&all_done);
+ __ Bind(&done);
__ SmiTag(RAX);
__ SmiTag(RDX);
@@ -5221,8 +5315,7 @@
if (right.IsConstant()) {
ConstantInstr* constant_instr = right.constant_instruction();
- const int64_t value =
- constant_instr->GetUnboxedSignedIntegerConstantValue();
+ const int64_t value = constant_instr->GetUnboxedIntegerConstantValue();
EmitInt64Arithmetic(compiler, op_kind(), left.reg(), Immediate(value),
deopt);
} else {
@@ -5305,6 +5398,7 @@
// Code for a variable shift amount.
// Deoptimize if shift count is > 63 or negative.
// Sarq and shlq instructions mask the count to 6 bits.
+ __ AssertSmiInRange(RCX);
__ SmiUntag(RCX);
if (!IsShiftCountInRange()) {
__ cmpq(RCX, Immediate(kMintShiftCountLimit));
@@ -5337,21 +5431,31 @@
}
CompileType BinaryUint32OpInstr::ComputeType() const {
- return CompileType::FromCid(kSmiCid);
+ return CompileType::Int();
}
CompileType ShiftUint32OpInstr::ComputeType() const {
- return CompileType::FromCid(kSmiCid);
+ return CompileType::Int();
}
CompileType UnaryUint32OpInstr::ComputeType() const {
- return CompileType::FromCid(kSmiCid);
+ return CompileType::Int();
}
LocationSummary* BinaryUint32OpInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
+ ConstantInstr* right_constant = right()->definition()->AsConstant();
+ if (right_constant != NULL && op_kind() != Token::kMUL &&
+ CanBeUint32Immediate(right_constant->value())) {
+ LocationSummary* summary = new (zone)
+ LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresRegister());
+ summary->set_in(1, Location::Constant(right_constant));
+ summary->set_out(0, Location::SameAsFirstInput());
+ return summary;
+ }
LocationSummary* summary = new (zone)
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
@@ -5365,6 +5469,7 @@
Token::Kind op_kind,
Register left,
const OperandType& right) {
+ __ AssertValidUint32(left);
switch (op_kind) {
case Token::kADD:
__ addl(left, right);
@@ -5387,24 +5492,21 @@
default:
UNREACHABLE();
}
+ __ AssertValidUint32(left);
}
void BinaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register left = locs()->in(0).reg();
- Register right = locs()->in(1).reg();
Register out = locs()->out(0).reg();
ASSERT(out == left);
- switch (op_kind()) {
- case Token::kBIT_AND:
- case Token::kBIT_OR:
- case Token::kBIT_XOR:
- case Token::kADD:
- case Token::kSUB:
- case Token::kMUL:
- EmitIntegerArithmetic(compiler, op_kind(), left, right);
- return;
- default:
- UNREACHABLE();
+ if (locs()->in(1).IsRegister()) {
+ Register right = locs()->in(1).reg();
+ EmitIntegerArithmetic(compiler, op_kind(), left, right);
+ } else {
+ ASSERT(locs()->in(1).IsConstant());
+ ConstantInstr* right_constant = right()->definition()->AsConstant();
+ int32_t imm = right_constant->GetUnboxedIntegerConstantValue();
+ EmitIntegerArithmetic(compiler, op_kind(), left, Immediate(imm));
}
}
@@ -5460,6 +5562,7 @@
Label zero;
// TODO(johnmccutchan): Use range information to avoid these checks.
+ __ AssertSmiInRange(shifter);
__ SmiUntag(shifter);
__ cmpq(shifter, Immediate(0));
// If shift value is < 0, deoptimize.
@@ -5484,13 +5587,14 @@
__ Bind(&zero);
// Shift was greater than 31 bits, just return zero.
- __ xorq(left, left);
+ __ xorl(left, left);
// Exit path.
__ Bind(&done);
}
DEFINE_BACKEND(UnaryUint32Op, (SameAsFirstInput, Register value)) {
+ __ AssertValidUint32(value);
__ notl(value);
}
@@ -5525,8 +5629,8 @@
const Register out = locs()->out(0).reg();
// Representations are bitwise equivalent but we want to normalize
// upperbits for safety reasons.
- // TODO(vegorov) if we ensure that we never use upperbits we could
- // avoid this.
+ // TODO(vegorov) if we ensure that we never leave garbage in the upper bits
+ // we could avoid this.
__ movl(out, value);
} else if (from() == kUnboxedUint32 && to() == kUnboxedInt32) {
// Representations are bitwise equivalent.
diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc
index e137fad..5db455b 100644
--- a/runtime/vm/compiler/backend/inliner.cc
+++ b/runtime/vm/compiler/backend/inliner.cc
@@ -2478,13 +2478,16 @@
DoubleToFloatInstr(new (Z) Value(stored_value), call->deopt_id());
cursor =
flow_graph->AppendTo(cursor, stored_value, NULL, FlowGraph::kValue);
+#if !defined(AVOID_UNBOXED_INT32)
} else if (array_cid == kTypedDataInt32ArrayCid) {
stored_value =
new (Z) UnboxInt32Instr(UnboxInt32Instr::kTruncate,
new (Z) Value(stored_value), call->deopt_id());
cursor = flow_graph->AppendTo(cursor, stored_value, call->env(),
FlowGraph::kValue);
- } else if (array_cid == kTypedDataUint32ArrayCid) {
+#endif
+ } else if (array_cid == kTypedDataUint32ArrayCid ||
+ array_cid == kTypedDataInt32ArrayCid) {
stored_value =
new (Z) UnboxUint32Instr(new (Z) Value(stored_value), call->deopt_id());
ASSERT(stored_value->AsUnboxInteger()->is_truncating());
@@ -2786,13 +2789,16 @@
DoubleToFloatInstr(new (Z) Value(stored_value), call->deopt_id());
cursor =
flow_graph->AppendTo(cursor, stored_value, NULL, FlowGraph::kValue);
+#if !defined(AVOID_UNBOXED_INT32)
} else if (view_cid == kTypedDataInt32ArrayCid) {
stored_value =
new (Z) UnboxInt32Instr(UnboxInt32Instr::kTruncate,
new (Z) Value(stored_value), call->deopt_id());
cursor = flow_graph->AppendTo(cursor, stored_value, call->env(),
FlowGraph::kValue);
- } else if (view_cid == kTypedDataUint32ArrayCid) {
+#endif
+ } else if (view_cid == kTypedDataInt32ArrayCid || // Again, outside ifdef.
+ view_cid == kTypedDataUint32ArrayCid) {
stored_value =
new (Z) UnboxUint32Instr(new (Z) Value(stored_value), call->deopt_id());
ASSERT(stored_value->AsUnboxInteger()->is_truncating());
diff --git a/runtime/vm/compiler/backend/range_analysis_test.cc b/runtime/vm/compiler/backend/range_analysis_test.cc
index 081c7e8..175b42b 100644
--- a/runtime/vm/compiler/backend/range_analysis_test.cc
+++ b/runtime/vm/compiler/backend/range_analysis_test.cc
@@ -66,17 +66,10 @@
RangeBoundary::PositiveInfinity());
TEST_RANGE_OP(Range::Shl, -1, 1, 63, 63, RangeBoundary(kMinInt64),
RangeBoundary::PositiveInfinity());
- if (kBitsPerWord == 64) {
- TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 62, 62, RangeBoundary(kSmiMin),
- RangeBoundary(kSmiMax));
- TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 30, 30, RangeBoundary(-(1 << 30)),
- RangeBoundary(1 << 30));
- } else {
- TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 30, 30, RangeBoundary(kSmiMin),
- RangeBoundary(kSmiMax));
- TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 62, 62, RangeBoundary(kSmiMin),
- RangeBoundary(kSmiMax));
- }
+ TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 30, 30, RangeBoundary(kSmiMin),
+ RangeBoundary(kSmiMax));
+ TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 62, 62, RangeBoundary(kSmiMin),
+ RangeBoundary(kSmiMax));
TEST_RANGE_OP(Range::Shl, 0, 100, 0, 64, RangeBoundary(0),
RangeBoundary::PositiveInfinity());
TEST_RANGE_OP(Range::Shl, -100, 0, 0, 64, RangeBoundary::NegativeInfinity(),
diff --git a/runtime/vm/compiler/call_specializer.cc b/runtime/vm/compiler/call_specializer.cc
index 30e0407..870884e 100644
--- a/runtime/vm/compiler/call_specializer.cc
+++ b/runtime/vm/compiler/call_specializer.cc
@@ -349,13 +349,15 @@
}
void CallSpecializer::AddCheckNull(Value* to_check,
+ const String& function_name,
intptr_t deopt_id,
Environment* deopt_environment,
Instruction* insert_before) {
ASSERT(I->strong() && FLAG_use_strong_mode_types);
if (to_check->Type()->is_nullable()) {
- CheckNullInstr* check_null = new (Z) CheckNullInstr(
- to_check->CopyWithType(Z), deopt_id, insert_before->token_pos());
+ CheckNullInstr* check_null =
+ new (Z) CheckNullInstr(to_check->CopyWithType(Z), function_name,
+ deopt_id, insert_before->token_pos());
if (FLAG_trace_strong_mode_types) {
THR_Print("[Strong mode] Inserted %s\n", check_null->ToCString());
}
@@ -1558,10 +1560,10 @@
}
void CallSpecializer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) {
-// TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized.
-#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM)
+ // Note that on ARM64 the result can always be packed into a Smi, so this
+ // is never triggered.
+ // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized.
if (!instr->can_pack_into_smi()) instr->set_representation(kUnboxedInt64);
-#endif
}
static bool CidTestResultsContains(const ZoneGrowableArray<intptr_t>& results,
diff --git a/runtime/vm/compiler/call_specializer.h b/runtime/vm/compiler/call_specializer.h
index d74784e..04bf617 100644
--- a/runtime/vm/compiler/call_specializer.h
+++ b/runtime/vm/compiler/call_specializer.h
@@ -93,6 +93,7 @@
// Insert a null check if needed.
void AddCheckNull(Value* to_check,
+ const String& function_name,
intptr_t deopt_id,
Environment* deopt_environment,
Instruction* insert_before);
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 4b86b49..82d89d1 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -6985,8 +6985,9 @@
}
Fragment StreamingFlowGraphBuilder::CheckNull(TokenPosition position,
- LocalVariable* receiver) {
- return flow_graph_builder_->CheckNull(position, receiver);
+ LocalVariable* receiver,
+ const String& function_name) {
+ return flow_graph_builder_->CheckNull(position, receiver, function_name);
}
Fragment StreamingFlowGraphBuilder::StaticCall(TokenPosition position,
@@ -7427,7 +7428,7 @@
}
if (direct_call.check_receiver_for_null_) {
- instructions += CheckNull(TokenPosition::kNoSource, receiver);
+ instructions += CheckNull(position, receiver, getter_name);
}
if (!direct_call.target_.IsNull()) {
@@ -7489,7 +7490,7 @@
}
if (direct_call.check_receiver_for_null_) {
- instructions += CheckNull(position, receiver);
+ instructions += CheckNull(position, receiver, setter_name);
}
if (!direct_call.target_.IsNull()) {
@@ -8045,7 +8046,7 @@
}
if (direct_call.check_receiver_for_null_) {
- instructions += CheckNull(position, receiver_temp);
+ instructions += CheckNull(position, receiver_temp, name);
}
if (!direct_call.target_.IsNull()) {
@@ -10884,6 +10885,35 @@
temp_instance_ = H.Canonicalize(temp_instance_);
break;
}
+ case kPartialInstantiationConstant: {
+ const intptr_t entry_index = builder_.ReadUInt();
+ temp_object_ = constants.At(entry_index);
+
+ const intptr_t number_of_type_arguments = builder_.ReadUInt();
+ if (temp_class_.NumTypeArguments() > 0) {
+ temp_type_arguments_ =
+ TypeArguments::New(number_of_type_arguments, Heap::kOld);
+ for (intptr_t j = 0; j < number_of_type_arguments; ++j) {
+ temp_type_arguments_.SetTypeAt(j, type_translator_.BuildType());
+ }
+ } else {
+ ASSERT(number_of_type_arguments == 0);
+ temp_type_arguments_ = TypeArguments::null();
+ }
+
+ // Make a copy of the old closure, with the delayed type arguments
+ // set to [temp_type_arguments_].
+ temp_closure_ = Closure::RawCast(temp_object_.raw());
+ temp_function_ = temp_closure_.function();
+ temp_type_arguments2_ = temp_closure_.instantiator_type_arguments();
+ temp_type_arguments3_ = temp_closure_.function_type_arguments();
+ temp_context_ = temp_closure_.context();
+ temp_closure_ = Closure::New(
+ temp_type_arguments2_, Object::null_type_arguments(),
+ temp_type_arguments_, temp_function_, temp_context_, Heap::kOld);
+ temp_instance_ = H.Canonicalize(temp_closure_);
+ break;
+ }
case kTearOffConstant: {
const NameIndex index = builder_.ReadCanonicalNameReference();
NameIndex lib_index = index;
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index 337c045d6..b4c4b83 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -1357,7 +1357,9 @@
Fragment Constant(const Object& value);
Fragment IntConstant(int64_t value);
Fragment LoadStaticField();
- Fragment CheckNull(TokenPosition position, LocalVariable* receiver);
+ Fragment CheckNull(TokenPosition position,
+ LocalVariable* receiver,
+ const String& function_name);
Fragment StaticCall(TokenPosition position,
const Function& target,
intptr_t argument_count,
@@ -1680,12 +1682,16 @@
zone_(zone),
temp_type_(AbstractType::Handle(zone)),
temp_type_arguments_(TypeArguments::Handle(zone)),
+ temp_type_arguments2_(TypeArguments::Handle(zone)),
+ temp_type_arguments3_(TypeArguments::Handle(zone)),
temp_object_(Object::Handle(zone)),
temp_array_(Array::Handle(zone)),
temp_instance_(Instance::Handle(zone)),
temp_field_(Field::Handle(zone)),
temp_class_(Class::Handle(zone)),
temp_function_(Function::Handle(zone)),
+ temp_closure_(Closure::Handle(zone)),
+ temp_context_(Context::Handle(zone)),
temp_integer_(Integer::Handle(zone)) {}
// Reads the constant table from the binary.
@@ -1707,12 +1713,16 @@
Zone* zone_;
AbstractType& temp_type_;
TypeArguments& temp_type_arguments_;
+ TypeArguments& temp_type_arguments2_;
+ TypeArguments& temp_type_arguments3_;
Object& temp_object_;
Array& temp_array_;
Instance& temp_instance_;
Field& temp_field_;
Class& temp_class_;
Function& temp_function_;
+ Closure& temp_closure_;
+ Context& temp_context_;
Integer& temp_integer_;
};
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 5d91b40..93ce810 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -1565,11 +1565,12 @@
}
Fragment FlowGraphBuilder::CheckNull(TokenPosition position,
- LocalVariable* receiver) {
+ LocalVariable* receiver,
+ const String& function_name) {
Fragment instructions = LoadLocal(receiver);
CheckNullInstr* check_null =
- new (Z) CheckNullInstr(Pop(), GetNextDeoptId(), position);
+ new (Z) CheckNullInstr(Pop(), function_name, GetNextDeoptId(), position);
instructions <<= check_null;
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.h b/runtime/vm/compiler/frontend/kernel_to_il.h
index abdf092..1aa740d 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.h
+++ b/runtime/vm/compiler/frontend/kernel_to_il.h
@@ -763,7 +763,9 @@
Fragment LoadStaticField();
Fragment NativeCall(const String* name, const Function* function);
Fragment Return(TokenPosition position);
- Fragment CheckNull(TokenPosition position, LocalVariable* receiver);
+ Fragment CheckNull(TokenPosition position,
+ LocalVariable* receiver,
+ const String& function_name);
void SetResultTypeForStaticCall(StaticCallInstr* call,
const Function& target,
intptr_t argument_count,
diff --git a/runtime/vm/compiler/intrinsifier.cc b/runtime/vm/compiler/intrinsifier.cc
index 654d33c..8ea16bb 100644
--- a/runtime/vm/compiler/intrinsifier.cc
+++ b/runtime/vm/compiler/intrinsifier.cc
@@ -373,6 +373,9 @@
}
Definition* AddUnboxInstr(Representation rep, Value* value, bool is_checked) {
+#if defined(AVOID_UNBOXED_INT32)
+ ASSERT(rep != kUnboxedInt32);
+#endif
Definition* unboxed_value =
AddDefinition(UnboxInstr::Create(rep, value, Thread::kNoDeoptId));
if (is_checked) {
@@ -455,7 +458,11 @@
case kTypedDataInt32ArrayCid:
case kExternalTypedDataInt32ArrayCid:
result = builder.AddDefinition(
+#if defined(AVOID_UNBOXED_INT32)
+ BoxInstr::Create(kUnboxedInt64, new Value(result)));
+#else
BoxInstr::Create(kUnboxedInt32, new Value(result)));
+#endif
break;
case kTypedDataUint32ArrayCid:
case kExternalTypedDataUint32ArrayCid:
diff --git a/runtime/vm/compiler/intrinsifier_arm.cc b/runtime/vm/compiler/intrinsifier_arm.cc
index 1fa171f..9b0c63b 100644
--- a/runtime/vm/compiler/intrinsifier_arm.cc
+++ b/runtime/vm/compiler/intrinsifier_arm.cc
@@ -1647,7 +1647,7 @@
__ Ret();
__ Bind(&use_canonical_type);
- __ LoadClassById(R2, R1);
+ __ LoadClassById(R2, R1); // Overwrites R1.
__ ldrh(R3, FieldAddress(R2, Class::num_type_arguments_offset()));
__ CompareImmediate(R3, 0);
__ b(&fall_through, NE);
diff --git a/runtime/vm/compiler/intrinsifier_arm64.cc b/runtime/vm/compiler/intrinsifier_arm64.cc
index 4da90f0..2102c93 100644
--- a/runtime/vm/compiler/intrinsifier_arm64.cc
+++ b/runtime/vm/compiler/intrinsifier_arm64.cc
@@ -265,8 +265,9 @@
void Intrinsifier::Integer_addFromInteger(Assembler* assembler) {
Label fall_through;
TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis.
- __ adds(R0, R0, Operand(R1)); // Adds.
+ __ addsw(R0, R0, Operand(R1)); // Adds.
__ b(&fall_through, VS); // Fall-through on overflow.
+ __ sxtw(R0, R0); // Sign extend - flags not affected.
__ ret();
__ Bind(&fall_through);
}
@@ -278,8 +279,9 @@
void Intrinsifier::Integer_subFromInteger(Assembler* assembler) {
Label fall_through;
TestBothArgumentsSmis(assembler, &fall_through);
- __ subs(R0, R0, Operand(R1)); // Subtract.
- __ b(&fall_through, VS); // Fall-through on overflow.
+ __ subsw(R0, R0, Operand(R1)); // Subtract.
+ __ b(&fall_through, VS); // Fall-through on overflow.
+ __ sxtw(R0, R0); // Sign extend - flags not affected.
__ ret();
__ Bind(&fall_through);
}
@@ -287,8 +289,9 @@
void Intrinsifier::Integer_sub(Assembler* assembler) {
Label fall_through;
TestBothArgumentsSmis(assembler, &fall_through);
- __ subs(R0, R1, Operand(R0)); // Subtract.
- __ b(&fall_through, VS); // Fall-through on overflow.
+ __ subsw(R0, R1, Operand(R0)); // Subtract.
+ __ b(&fall_through, VS); // Fall-through on overflow.
+ __ sxtw(R0, R0); // Sign extend - flags not affected.
__ ret();
__ Bind(&fall_through);
}
@@ -299,9 +302,9 @@
TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
__ SmiUntag(R0); // Untags R6. We only want result shifted by one.
- __ mul(TMP, R0, R1);
- __ smulh(TMP2, R0, R1);
- // TMP: result bits 64..127.
+ __ smull(TMP, R0, R1);
+ __ AsrImmediate(TMP2, TMP, 31);
+ // TMP: result bits 31..63.
__ cmp(TMP2, Operand(TMP, ASR, 63));
__ b(&fall_through, NE);
__ mov(R0, TMP);
@@ -417,7 +420,7 @@
// Check the corner case of dividing the 'MIN_SMI' with -1, in which case we
// cannot tag the result.
- __ CompareImmediate(R0, 0x4000000000000000);
+ __ CompareImmediate(R0, 0x40000000);
__ b(&fall_through, EQ);
__ SmiTag(R0); // Not equal. Okay to tag and return.
__ ret(); // Return.
@@ -428,8 +431,9 @@
Label fall_through;
__ ldr(R0, Address(SP, +0 * kWordSize)); // Grab first argument.
__ BranchIfNotSmi(R0, &fall_through);
- __ negs(R0, R0);
+ __ negsw(R0, R0);
__ b(&fall_through, VS);
+ __ sxtw(R0, R0); // Sign extend - flags not affected.
__ ret();
__ Bind(&fall_through);
}
@@ -488,9 +492,9 @@
// Check if count too large for handling it inlined.
__ SmiUntag(TMP, right); // SmiUntag right into TMP.
// Overflow test (preserve left, right, and TMP);
- __ lslv(temp, left, TMP);
- __ asrv(TMP2, temp, TMP);
- __ CompareRegisters(left, TMP2);
+ __ lslvw(temp, left, TMP);
+ __ asrvw(TMP2, temp, TMP);
+ __ cmpw(left, Operand(TMP2));
__ b(&fall_through, NE); // Overflow.
// Shift for result now we know there is no overflow.
__ lslv(result, left, TMP);
@@ -563,6 +567,7 @@
__ CompareClassId(R0, kDoubleCid);
__ b(&fall_through, EQ);
+ __ AssertSmiInRange(R1);
__ LoadObject(R0, Bool::False()); // Smi == Mint -> false.
__ ret();
@@ -573,6 +578,7 @@
__ b(&fall_through, NE);
// Receiver is Mint, return false if right is Smi.
__ BranchIfNotSmi(R0, &fall_through);
+ __ AssertSmiInRange(R0);
__ LoadObject(R0, Bool::False());
__ ret();
// TODO(srdjan): Implement Mint == Mint comparison.
@@ -1495,11 +1501,12 @@
__ fcmpd(V0, V0);
__ b(&fall_through, VS);
- __ fcvtzds(R0, V0);
+ __ fcvtzdsx(R0, V0);
// Overflow is signaled with minint.
// Check for overflow and that it fits into Smi.
- __ CompareImmediate(R0, 0xC000000000000000);
- __ b(&fall_through, MI);
+ __ AsrImmediate(TMP, R0, 30);
+ __ cmp(TMP, Operand(R0, ASR, 63));
+ __ b(&fall_through, NE);
__ SmiTag(R0);
__ ret();
__ Bind(&fall_through);
@@ -1516,10 +1523,10 @@
__ fcmpd(V0, V0);
__ b(&double_hash, VS);
- // Convert double value to signed 64-bit int in R0 and back to a
+ // Convert double value to signed 32-bit int in R0 and back to a
// double value in V1.
- __ fcvtzds(R0, V0);
- __ scvtfdx(V1, R0);
+ __ fcvtzdsw(R0, V0);
+ __ scvtfdw(V1, R0);
// Tag the int as a Smi, making sure that it fits; this checks for
// overflow in the conversion from double to int. Conversion
@@ -1527,8 +1534,9 @@
// INT64_MAX or INT64_MIN (saturation).
Label fall_through;
ASSERT(kSmiTag == 0 && kSmiTagShift == 1);
- __ adds(R0, R0, Operand(R0));
+ __ addsw(R0, R0, Operand(R0));
__ b(&fall_through, VS);
+ __ sxtw(R0, R0); // Sign extend - flags not affected.
// Compare the two double values. If they are equal, we return the
// Smi tagged result immediately as the hash code.
@@ -1702,7 +1710,7 @@
__ ret();
__ Bind(&use_canonical_type);
- __ LoadClassById(R2, R1);
+ __ LoadClassById(R2, R1); // Overwrites R1.
__ ldr(R3, FieldAddress(R2, Class::num_type_arguments_offset()), kHalfword);
__ CompareImmediate(R3, 0);
__ b(&fall_through, NE);
@@ -1736,7 +1744,7 @@
// Objects have the same class and neither is a closure.
// Check if there are no type arguments. In this case we can return true.
// Otherwise fall through into the runtime to handle comparison.
- __ LoadClassById(R3, R1);
+ __ LoadClassById(R3, R1); // Overwrites R1.
__ ldr(R3, FieldAddress(R3, Class::num_type_arguments_offset()), kHalfword);
__ CompareImmediate(R3, 0);
__ b(&fall_through, NE);
diff --git a/runtime/vm/compiler/intrinsifier_x64.cc b/runtime/vm/compiler/intrinsifier_x64.cc
index 1e2574c..c8ddf76 100644
--- a/runtime/vm/compiler/intrinsifier_x64.cc
+++ b/runtime/vm/compiler/intrinsifier_x64.cc
@@ -269,8 +269,10 @@
Label fall_through;
TestBothArgumentsSmis(assembler, &fall_through);
// RAX contains right argument.
- __ addq(RAX, Address(RSP, +2 * kWordSize));
+ __ AssertSmiInRange(RAX);
+ __ addl(RAX, Address(RSP, +2 * kWordSize));
__ j(OVERFLOW, &fall_through, Assembler::kNearJump);
+ __ movsxd(RAX, RAX);
// Result is in RAX.
__ ret();
__ Bind(&fall_through);
@@ -284,8 +286,10 @@
Label fall_through;
TestBothArgumentsSmis(assembler, &fall_through);
// RAX contains right argument, which is the actual minuend of subtraction.
- __ subq(RAX, Address(RSP, +2 * kWordSize));
+ __ AssertSmiInRange(RAX);
+ __ subl(RAX, Address(RSP, +2 * kWordSize));
__ j(OVERFLOW, &fall_through, Assembler::kNearJump);
+ __ movsxd(RAX, RAX);
// Result is in RAX.
__ ret();
__ Bind(&fall_through);
@@ -295,10 +299,13 @@
Label fall_through;
TestBothArgumentsSmis(assembler, &fall_through);
// RAX contains right argument, which is the actual subtrahend of subtraction.
+ __ AssertSmiInRange(RAX);
__ movq(RCX, RAX);
__ movq(RAX, Address(RSP, +2 * kWordSize));
- __ subq(RAX, RCX);
+ __ AssertSmiInRange(RAX);
+ __ subl(RAX, RCX);
__ j(OVERFLOW, &fall_through, Assembler::kNearJump);
+ __ movsxd(RAX, RAX);
// Result is in RAX.
__ ret();
__ Bind(&fall_through);
@@ -308,10 +315,12 @@
Label fall_through;
TestBothArgumentsSmis(assembler, &fall_through);
// RAX is the right argument.
+ __ AssertSmiInRange(RAX);
ASSERT(kSmiTag == 0); // Adjust code below if not the case.
__ SmiUntag(RAX);
- __ imulq(RAX, Address(RSP, +2 * kWordSize));
+ __ imull(RAX, Address(RSP, +2 * kWordSize));
__ j(OVERFLOW, &fall_through, Assembler::kNearJump);
+ __ movsxd(RAX, RAX);
// Result is in RAX.
__ ret();
__ Bind(&fall_through);
@@ -333,7 +342,9 @@
// RAX: Untagged fallthrough result (remainder to be adjusted), or
// RAX: Tagged return result (remainder).
static void EmitRemainderOperation(Assembler* assembler) {
- Label return_zero, try_modulo, not_32bit, done;
+ Label return_zero, try_modulo, not_32bit;
+ __ AssertSmiInRange(RAX);
+ __ AssertSmiInRange(RCX);
// Check for quick zero results.
__ cmpq(RAX, Immediate(0));
__ j(EQUAL, &return_zero, Assembler::kNearJump);
@@ -355,33 +366,12 @@
__ Bind(&try_modulo);
- // Check if both operands fit into 32bits as idiv with 64bit operands
- // requires twice as many cycles and has much higher latency. We are checking
- // this before untagging them to avoid corner case dividing INT_MAX by -1 that
- // raises exception because quotient is too large for 32bit register.
- __ movsxd(RBX, RAX);
- __ cmpq(RBX, RAX);
- __ j(NOT_EQUAL, ¬_32bit, Assembler::kNearJump);
- __ movsxd(RBX, RCX);
- __ cmpq(RBX, RCX);
- __ j(NOT_EQUAL, ¬_32bit, Assembler::kNearJump);
-
// Both operands are 31bit smis. Divide using 32bit idiv.
__ SmiUntag(RAX);
__ SmiUntag(RCX);
__ cdq();
__ idivl(RCX);
__ movsxd(RAX, RDX);
- __ jmp(&done, Assembler::kNearJump);
-
- // Divide using 64bit idiv.
- __ Bind(¬_32bit);
- __ SmiUntag(RAX);
- __ SmiUntag(RCX);
- __ cqo();
- __ idivq(RCX);
- __ movq(RAX, RDX);
- __ Bind(&done);
}
// Implementation:
@@ -396,7 +386,9 @@
void Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) {
Label fall_through, negative_result;
TestBothArgumentsSmis(assembler, &fall_through);
+ __ AssertSmiInRange(RAX);
__ movq(RCX, Address(RSP, +2 * kWordSize));
+ __ AssertSmiInRange(RCX);
// RAX: Tagged left (dividend).
// RCX: Tagged right (divisor).
__ cmpq(RCX, Immediate(0));
@@ -430,21 +422,17 @@
Label fall_through, not_32bit;
TestBothArgumentsSmis(assembler, &fall_through);
// RAX: right argument (divisor)
+ __ AssertSmiInRange(RAX);
__ cmpq(RAX, Immediate(0));
__ j(EQUAL, &fall_through, Assembler::kNearJump);
__ movq(RCX, RAX);
__ movq(RAX, Address(RSP, +2 * kWordSize)); // Left argument (dividend).
+ __ AssertSmiInRange(RAX);
- // Check if both operands fit into 32bits as idiv with 64bit operands
- // requires twice as many cycles and has much higher latency. We are checking
- // this before untagging them to avoid corner case dividing INT_MAX by -1 that
- // raises exception because quotient is too large for 32bit register.
- __ movsxd(RBX, RAX);
- __ cmpq(RBX, RAX);
- __ j(NOT_EQUAL, ¬_32bit);
- __ movsxd(RBX, RCX);
- __ cmpq(RBX, RCX);
- __ j(NOT_EQUAL, ¬_32bit);
+ // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we
+ // cannot tag the result.
+ __ cmpq(RAX, Immediate(-0x80000000ll));
+ __ j(EQUAL, &fall_through);
// Both operands are 31bit smis. Divide using 32bit idiv.
__ SmiUntag(RAX);
@@ -454,21 +442,6 @@
__ movsxd(RAX, RAX);
__ SmiTag(RAX); // Result is guaranteed to fit into a smi.
__ ret();
-
- // Divide using 64bit idiv.
- __ Bind(¬_32bit);
- __ SmiUntag(RAX);
- __ SmiUntag(RCX);
- __ pushq(RDX); // Preserve RDX in case of 'fall_through'.
- __ cqo();
- __ idivq(RCX);
- __ popq(RDX);
- // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we
- // cannot tag the result.
- __ cmpq(RAX, Immediate(0x4000000000000000));
- __ j(EQUAL, &fall_through);
- __ SmiTag(RAX);
- __ ret();
__ Bind(&fall_through);
}
@@ -477,8 +450,10 @@
__ movq(RAX, Address(RSP, +1 * kWordSize));
__ testq(RAX, Immediate(kSmiTagMask));
__ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi value.
+ __ AssertSmiInRange(RAX);
+ __ cmpq(RAX, Immediate(-0x80000000ll));
+ __ j(EQUAL, &fall_through, Assembler::kNearJump);
__ negq(RAX);
- __ j(OVERFLOW, &fall_through, Assembler::kNearJump);
// Result is in RAX.
__ ret();
__ Bind(&fall_through);
@@ -487,6 +462,7 @@
void Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) {
Label fall_through;
TestBothArgumentsSmis(assembler, &fall_through);
+ __ AssertSmiInRange(RAX);
// RAX is the right argument.
__ andq(RAX, Address(RSP, +2 * kWordSize));
// Result is in RAX.
@@ -502,6 +478,7 @@
Label fall_through;
TestBothArgumentsSmis(assembler, &fall_through);
// RAX is the right argument.
+ __ AssertSmiInRange(RAX);
__ orq(RAX, Address(RSP, +2 * kWordSize));
// Result is in RAX.
__ ret();
@@ -517,6 +494,7 @@
TestBothArgumentsSmis(assembler, &fall_through);
// RAX is the right argument.
__ xorq(RAX, Address(RSP, +2 * kWordSize));
+ __ AssertSmiInRange(RAX);
// Result is in RAX.
__ ret();
__ Bind(&fall_through);
@@ -532,28 +510,32 @@
Label fall_through, overflow;
TestBothArgumentsSmis(assembler, &fall_through);
// Shift value is in RAX. Compare with tagged Smi.
+ __ AssertSmiInRange(RAX);
__ cmpq(RAX, Immediate(Smi::RawValue(Smi::kBits)));
__ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump);
__ SmiUntag(RAX);
__ movq(RCX, RAX); // Shift amount must be in RCX.
__ movq(RAX, Address(RSP, +2 * kWordSize)); // Value.
+ __ AssertSmiInRange(RAX);
// Overflow test - all the shifted-out bits must be same as the sign bit.
__ movq(RDI, RAX);
- __ shlq(RAX, RCX);
- __ sarq(RAX, RCX);
+ __ shll(RAX, RCX);
+ __ sarl(RAX, RCX);
+ __ movsxd(RAX, RAX);
__ cmpq(RAX, RDI);
__ j(NOT_EQUAL, &overflow, Assembler::kNearJump);
- __ shlq(RAX, RCX); // Shift for result now we know there is no overflow.
+ __ shlq(RDI, RCX); // Shift for result now we know there is no overflow.
+ __ movq(RAX, RDI);
// RAX is a correctly tagged Smi.
__ ret();
__ Bind(&overflow);
- // Mint is rarely used on x64 (only for integers requiring 64 bit instead of
- // 63 bits as represented by Smi).
+ // Mint is used on x64 for integers requiring 64 bit instead of 31 bits as
+ // represented by Smi.
__ Bind(&fall_through);
}
@@ -561,6 +543,7 @@
Label fall_through, true_label;
TestBothArgumentsSmis(assembler, &fall_through);
// RAX contains the right argument.
+ __ AssertSmiInRange(RAX);
__ cmpq(Address(RSP, +2 * kWordSize), RAX);
__ j(true_condition, &true_label, Assembler::kNearJump);
__ LoadObject(RAX, Bool::False());
@@ -606,6 +589,9 @@
__ orq(RAX, RCX);
__ testq(RAX, Immediate(kSmiTagMask));
__ j(NOT_ZERO, &check_for_mint, Assembler::kNearJump);
+ // Or-ing them together should still leave them both as compressible smis.
+ __ AssertSmiInRange(RAX);
+ __ AssertSmiInRange(RCX);
// Both arguments are smi, '===' is good enough.
__ LoadObject(RAX, Bool::False());
__ ret();
@@ -623,9 +609,21 @@
// Left (receiver) is Smi, return false if right is not Double.
// Note that an instance of Mint or Bigint never contains a value that can be
// represented by Smi.
+ __ AssertSmiInRange(RAX);
__ movq(RAX, Address(RSP, +kArgumentOffset * kWordSize));
__ CompareClassId(RAX, kDoubleCid);
__ j(EQUAL, &fall_through);
+#if defined(DEBUG)
+ Label ok;
+ __ CompareClassId(RAX, kMintCid);
+ __ j(NOT_EQUAL, &ok);
+ __ movq(RAX, FieldAddress(RAX, Mint::value_offset()));
+ __ sarq(RCX, Immediate(1));
+ __ cmpq(RAX, RCX);
+ __ j(NOT_EQUAL, &ok);
+ __ Stop("Smi wrapped in a Mint");
+ __ Bind(&ok);
+#endif
__ LoadObject(RAX, Bool::False());
__ ret();
@@ -637,6 +635,7 @@
__ movq(RAX, Address(RSP, +kArgumentOffset * kWordSize));
__ testq(RAX, Immediate(kSmiTagMask));
__ j(NOT_ZERO, &fall_through);
+ __ AssertSmiInRange(RAX);
// Smi == Mint -> false.
__ LoadObject(RAX, Bool::False());
__ ret();
@@ -666,6 +665,7 @@
__ Bind(&shift_count_ok);
__ movq(RCX, RAX); // Shift amount must be in RCX.
__ movq(RAX, Address(RSP, +2 * kWordSize)); // Value.
+ __ AssertSmiInRange(RAX);
__ SmiUntag(RAX); // Value.
__ sarq(RAX, RCX);
__ SmiTag(RAX);
@@ -676,6 +676,7 @@
// Argument is Smi (receiver).
void Intrinsifier::Smi_bitNegate(Assembler* assembler) {
__ movq(RAX, Address(RSP, +1 * kWordSize)); // Index.
+ __ AssertSmiInRange(RAX);
__ notq(RAX);
__ andq(RAX, Immediate(~kSmiTagMask)); // Remove inverted smi-tag.
__ ret();
@@ -684,6 +685,7 @@
void Intrinsifier::Smi_bitLength(Assembler* assembler) {
ASSERT(kSmiTagShift == 1);
__ movq(RAX, Address(RSP, +1 * kWordSize)); // Index.
+ __ AssertSmiInRange(RAX);
// XOR with sign bit to complement bits if value is negative.
__ movq(RCX, RAX);
__ sarq(RCX, Immediate(63)); // All 0 or all 1.
@@ -709,6 +711,7 @@
__ subq(R8, Immediate(2)); // x_used > 0, Smi. R8 = x_used - 1, round up.
__ sarq(R8, Immediate(2)); // R8 + 1 = number of digit pairs to read.
__ movq(RCX, Address(RSP, 2 * kWordSize)); // n is Smi
+ __ AssertSmiInRange(RCX);
__ SmiUntag(RCX);
__ movq(RBX, Address(RSP, 1 * kWordSize)); // r_digits
__ movq(RSI, RCX);
@@ -744,6 +747,7 @@
__ movq(RDI, Address(RSP, 4 * kWordSize)); // x_digits
__ movq(RCX, Address(RSP, 2 * kWordSize)); // n is Smi
+ __ AssertSmiInRange(RCX);
__ SmiUntag(RCX);
__ movq(RBX, Address(RSP, 1 * kWordSize)); // r_digits
__ movq(RDX, RCX);
@@ -1231,6 +1235,7 @@
__ LoadObject(RAX, Bool::True());
__ ret();
__ Bind(&is_smi);
+ __ AssertSmiInRange(RAX);
__ SmiUntag(RAX);
__ cvtsi2sdq(XMM1, RAX);
__ jmp(&double_op);
@@ -1291,6 +1296,7 @@
__ movsd(FieldAddress(RAX, Double::value_offset()), XMM0);
__ ret();
__ Bind(&is_smi);
+ __ AssertSmiInRange(RAX);
__ SmiUntag(RAX);
__ cvtsi2sdq(XMM1, RAX);
__ jmp(&double_op);
@@ -1320,6 +1326,7 @@
__ testq(RAX, Immediate(kSmiTagMask));
__ j(NOT_ZERO, &fall_through);
// Is Smi.
+ __ AssertSmiInRange(RAX);
__ SmiUntag(RAX);
__ cvtsi2sdq(XMM1, RAX);
__ movq(RAX, Address(RSP, +2 * kWordSize));
@@ -1342,6 +1349,7 @@
__ testq(RAX, Immediate(kSmiTagMask));
__ j(NOT_ZERO, &fall_through);
// Is Smi.
+ __ AssertSmiInRange(RAX);
__ SmiUntag(RAX);
__ cvtsi2sdq(XMM0, RAX);
const Class& double_class =
@@ -1412,14 +1420,15 @@
void Intrinsifier::DoubleToInteger(Assembler* assembler) {
__ movq(RAX, Address(RSP, +1 * kWordSize));
__ movsd(XMM0, FieldAddress(RAX, Double::value_offset()));
- __ cvttsd2siq(RAX, XMM0);
+ __ cvttsd2sil(RAX, XMM0);
// Overflow is signalled with minint.
Label fall_through;
// Check for overflow and that it fits into Smi.
__ movq(RCX, RAX);
- __ shlq(RCX, Immediate(1));
+ __ shll(RCX, Immediate(1));
__ j(OVERFLOW, &fall_through, Assembler::kNearJump);
- __ SmiTag(RAX);
+ ASSERT(kSmiTagShift == 1 && kSmiTag == 0);
+ __ movsxd(RAX, RCX);
__ ret();
__ Bind(&fall_through);
}
@@ -1431,16 +1440,17 @@
// back to a double in XMM1.
__ movq(RCX, Address(RSP, +1 * kWordSize));
__ movsd(XMM0, FieldAddress(RCX, Double::value_offset()));
- __ cvttsd2siq(RAX, XMM0);
- __ cvtsi2sdq(XMM1, RAX);
+ __ cvttsd2sil(RAX, XMM0);
+ __ cvtsi2sdl(XMM1, RAX);
// Tag the int as a Smi, making sure that it fits; this checks for
// overflow and NaN in the conversion from double to int. Conversion
- // overflow from cvttsd2si is signalled with an INT64_MIN value.
+ // overflow from cvttsd2sil is signalled with an INT32_MIN value.
Label fall_through;
ASSERT(kSmiTag == 0 && kSmiTagShift == 1);
- __ addq(RAX, RAX);
+ __ addl(RAX, RAX);
__ j(OVERFLOW, &fall_through, Assembler::kNearJump);
+ __ movsxd(RAX, RAX);
// Compare the two double values. If they are equal, we return the
// Smi tagged result immediately as the hash code.
@@ -1478,6 +1488,7 @@
__ movsd(FieldAddress(RAX, Double::value_offset()), XMM0);
__ ret();
__ Bind(&is_smi);
+ __ AssertSmiInRange(RAX);
__ SmiUntag(RAX);
__ cvtsi2sdq(XMM1, RAX);
__ jmp(&double_op);
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index 9fc7a63..8be187e 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -40,8 +40,8 @@
// Stack alignment: 4 bytes always, 8 bytes at public interfaces
// Linux (Debian armhf) and Android also differ in whether floating point
-// arguments are passed in registers. Linux uses hardfp and Android uses
-// softfp. See TargetCPUFeatures::hardfp_supported().
+// arguments are passed in floating point registers. Linux uses hardfp and
+// Android uses softfp. See TargetCPUFeatures::hardfp_supported().
// iOS ABI
// See "iOS ABI Function Call Guide"
@@ -56,7 +56,7 @@
// R15: Program counter
// Stack alignment: 4 bytes always, 4 bytes at public interfaces
-// iOS passes floating point arguments in registers (hardfp)
+// iOS passes floating point arguments in integer registers (softfp)
enum Register {
R0 = 0,
diff --git a/runtime/vm/constants_arm64.h b/runtime/vm/constants_arm64.h
index 95b3f87..cbf0db4 100644
--- a/runtime/vm/constants_arm64.h
+++ b/runtime/vm/constants_arm64.h
@@ -708,14 +708,14 @@
enum Extend {
kNoExtend = -1,
- UXTB = 0,
- UXTH = 1,
- UXTW = 2,
- UXTX = 3,
- SXTB = 4,
- SXTH = 5,
- SXTW = 6,
- SXTX = 7,
+ UXTB = 0, // Zero extend byte.
+ UXTH = 1, // Zero extend halfword (16 bits).
+ UXTW = 2, // Zero extend word (32 bits).
+ UXTX = 3, // Zero extend doubleword (64 bits).
+ SXTB = 4, // Sign extend byte.
+ SXTH = 5, // Sign extend halfword (16 bits).
+ SXTW = 6, // Sign extend word (32 bits).
+ SXTX = 7, // Sign extend doubleword (64 bits).
kMaxExtend = 8,
};
diff --git a/runtime/vm/cpu_arm.cc b/runtime/vm/cpu_arm.cc
index 4988b21..052f5ed 100644
--- a/runtime/vm/cpu_arm.cc
+++ b/runtime/vm/cpu_arm.cc
@@ -82,7 +82,8 @@
#endif
#if defined(USING_SIMULATOR)
-#if defined(TARGET_ARCH_ARM_5TE) || defined(TARGET_OS_ANDROID)
+#if defined(TARGET_ARCH_ARM_5TE) || defined(TARGET_OS_ANDROID) \
+ || defined(TARGET_OS_IOS)
DEFINE_FLAG(bool, sim_use_hardfp, false, "Use the hardfp ABI.");
#else
DEFINE_FLAG(bool, sim_use_hardfp, true, "Use the hardfp ABI.");
@@ -150,7 +151,7 @@
vfp_supported_ = FLAG_use_vfp;
integer_division_supported_ = FLAG_use_integer_division;
neon_supported_ = FLAG_use_neon;
- hardfp_supported_ = true;
+ hardfp_supported_ = false;
#if defined(DEBUG)
initialized_ = true;
#endif
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index fb393bd..4efa972 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -50,7 +50,6 @@
DebugInfo* Dart::pprof_symbol_generator_ = NULL;
ReadOnlyHandles* Dart::predefined_handles_ = NULL;
Snapshot::Kind Dart::vm_snapshot_kind_ = Snapshot::kInvalid;
-const uint8_t* Dart::vm_snapshot_instructions_ = NULL;
Dart_ThreadExitCallback Dart::thread_exit_callback_ = NULL;
Dart_FileOpenCallback Dart::file_open_callback_ = NULL;
Dart_FileReadCallback Dart::file_read_callback_ = NULL;
@@ -229,7 +228,7 @@
} else {
return strdup("Invalid vm isolate snapshot seen");
}
- FullSnapshotReader reader(snapshot, instructions_snapshot, T);
+ FullSnapshotReader reader(snapshot, instructions_snapshot, NULL, NULL, T);
const Error& error = Error::Handle(reader.ReadVMSnapshot());
if (!error.IsNull()) {
// Must copy before leaving the zone.
@@ -503,6 +502,8 @@
RawError* Dart::InitializeIsolate(const uint8_t* snapshot_data,
const uint8_t* snapshot_instructions,
+ const uint8_t* shared_data,
+ const uint8_t* shared_instructions,
intptr_t snapshot_length,
kernel::Program* kernel_program,
void* data) {
@@ -547,7 +548,8 @@
if (FLAG_trace_isolates) {
OS::Print("Size of isolate snapshot = %" Pd "\n", snapshot->length());
}
- FullSnapshotReader reader(snapshot, snapshot_instructions, T);
+ FullSnapshotReader reader(snapshot, snapshot_instructions, shared_data,
+ shared_instructions, T);
const Error& error = Error::Handle(reader.ReadIsolateSnapshot());
if (!error.IsNull()) {
return error.raw();
diff --git a/runtime/vm/dart.h b/runtime/vm/dart.h
index 5c8177c..ce8b5e0 100644
--- a/runtime/vm/dart.h
+++ b/runtime/vm/dart.h
@@ -48,6 +48,8 @@
// from_kernel. Otherwise, initialize from sources.
static RawError* InitializeIsolate(const uint8_t* snapshot_data,
const uint8_t* snapshot_instructions,
+ const uint8_t* shared_data,
+ const uint8_t* shared_instructions,
intptr_t snapshot_length,
kernel::Program* kernel_program,
void* data);
@@ -78,12 +80,6 @@
bool is_vm_snapshot,
Snapshot::Kind kind);
static Snapshot::Kind vm_snapshot_kind() { return vm_snapshot_kind_; }
- static const uint8_t* vm_snapshot_instructions() {
- return vm_snapshot_instructions_;
- }
- static void set_vm_snapshot_instructions(const uint8_t* buffer) {
- vm_snapshot_instructions_ = buffer;
- }
static Dart_ThreadExitCallback thread_exit_callback() {
return thread_exit_callback_;
@@ -131,7 +127,6 @@
static DebugInfo* pprof_symbol_generator_;
static ReadOnlyHandles* predefined_handles_;
static Snapshot::Kind vm_snapshot_kind_;
- static const uint8_t* vm_snapshot_instructions_;
static Dart_ThreadExitCallback thread_exit_callback_;
static Dart_FileOpenCallback file_open_callback_;
static Dart_FileReadCallback file_read_callback_;
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 43db729..8ae8279 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1090,6 +1090,8 @@
const char* main,
const uint8_t* snapshot_data,
const uint8_t* snapshot_instructions,
+ const uint8_t* shared_data,
+ const uint8_t* shared_instructions,
intptr_t snapshot_length,
kernel::Program* kernel_program,
Dart_IsolateFlags* flags,
@@ -1122,8 +1124,9 @@
Dart_EnterScope();
const Error& error_obj =
Error::Handle(Z, Dart::InitializeIsolate(
- snapshot_data, snapshot_instructions,
- snapshot_length, kernel_program, callback_data));
+ snapshot_data, snapshot_instructions, shared_data,
+ shared_instructions, snapshot_length,
+ kernel_program, callback_data));
if (error_obj.IsNull()) {
#if defined(DART_NO_SNAPSHOT) && !defined(PRODUCT)
if (FLAG_check_function_fingerprints && kernel_program == NULL) {
@@ -1162,12 +1165,15 @@
const char* main,
const uint8_t* snapshot_data,
const uint8_t* snapshot_instructions,
+ const uint8_t* shared_data,
+ const uint8_t* shared_instructions,
Dart_IsolateFlags* flags,
void* callback_data,
char** error) {
API_TIMELINE_DURATION(Thread::Current());
return CreateIsolate(script_uri, main, snapshot_data, snapshot_instructions,
- -1, NULL, flags, callback_data, error);
+ shared_data, shared_instructions, -1, NULL, flags,
+ callback_data, error);
}
DART_EXPORT Dart_Isolate Dart_CreateIsolateFromKernel(const char* script_uri,
@@ -1184,7 +1190,7 @@
flags = &api_flags;
}
flags->use_dart_frontend = true;
- return CreateIsolate(script_uri, main, NULL, NULL, -1,
+ return CreateIsolate(script_uri, main, NULL, NULL, NULL, NULL, -1,
reinterpret_cast<kernel::Program*>(kernel_program),
flags, callback_data, error);
}
@@ -6526,7 +6532,7 @@
NOT_IN_PRODUCT(TimelineDurationScope tds2(T, Timeline::GetIsolateStream(),
"WriteAppAOTSnapshot"));
- AssemblyImageWriter image_writer(callback, callback_data);
+ AssemblyImageWriter image_writer(callback, callback_data, NULL, NULL);
uint8_t* vm_snapshot_data_buffer = NULL;
uint8_t* isolate_snapshot_data_buffer = NULL;
FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data_buffer,
@@ -6557,7 +6563,7 @@
NOT_IN_PRODUCT(TimelineDurationScope tds2(T, Timeline::GetIsolateStream(),
"WriteVMAOTSnapshot"));
- AssemblyImageWriter image_writer(callback, callback_data);
+ AssemblyImageWriter image_writer(callback, callback_data, NULL, NULL);
uint8_t* vm_snapshot_data_buffer = NULL;
FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data_buffer, NULL,
ApiReallocate, &image_writer, NULL);
@@ -6576,7 +6582,9 @@
uint8_t** isolate_snapshot_data_buffer,
intptr_t* isolate_snapshot_data_size,
uint8_t** isolate_snapshot_instructions_buffer,
- intptr_t* isolate_snapshot_instructions_size) {
+ intptr_t* isolate_snapshot_instructions_size,
+ const uint8_t* shared_data,
+ const uint8_t* shared_instructions) {
#if defined(TARGET_ARCH_IA32)
return Api::NewError("AOT compilation is not supported on IA32.");
#elif defined(TARGET_ARCH_DBC)
@@ -6584,9 +6592,6 @@
#elif !defined(DART_PRECOMPILER)
return Api::NewError(
"This VM was built without support for AOT compilation.");
-#elif defined(TARGET_OS_FUCHSIA)
- return Api::NewError(
- "AOT as blobs is not supported on Fuchsia; use dylibs instead.");
#else
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
@@ -6606,13 +6611,20 @@
CHECK_NULL(isolate_snapshot_instructions_buffer);
CHECK_NULL(isolate_snapshot_instructions_size);
+ const void* shared_data_image = NULL;
+ if (shared_data != NULL) {
+ shared_data_image = Snapshot::SetupFromBuffer(shared_data)->DataImage();
+ }
+ const void* shared_instructions_image = shared_instructions;
+
NOT_IN_PRODUCT(TimelineDurationScope tds2(T, Timeline::GetIsolateStream(),
"WriteAppAOTSnapshot"));
BlobImageWriter vm_image_writer(vm_snapshot_instructions_buffer,
- ApiReallocate, 2 * MB /* initial_size */);
- BlobImageWriter isolate_image_writer(isolate_snapshot_instructions_buffer,
- ApiReallocate,
- 2 * MB /* initial_size */);
+ ApiReallocate, 2 * MB /* initial_size */,
+ NULL, NULL);
+ BlobImageWriter isolate_image_writer(
+ isolate_snapshot_instructions_buffer, ApiReallocate,
+ 2 * MB /* initial_size */, shared_data_image, shared_instructions_image);
FullSnapshotWriter writer(Snapshot::kFullAOT, vm_snapshot_data_buffer,
isolate_snapshot_data_buffer, ApiReallocate,
&vm_image_writer, &isolate_image_writer);
@@ -6670,10 +6682,11 @@
NOT_IN_PRODUCT(TimelineDurationScope tds2(T, Timeline::GetIsolateStream(),
"WriteCoreJITSnapshot"));
BlobImageWriter vm_image_writer(vm_snapshot_instructions_buffer,
- ApiReallocate, 2 * MB /* initial_size */);
+ ApiReallocate, 2 * MB /* initial_size */,
+ NULL, NULL);
BlobImageWriter isolate_image_writer(isolate_snapshot_instructions_buffer,
- ApiReallocate,
- 2 * MB /* initial_size */);
+ ApiReallocate, 2 * MB /* initial_size */,
+ NULL, NULL);
FullSnapshotWriter writer(Snapshot::kFullJIT, vm_snapshot_data_buffer,
isolate_snapshot_data_buffer, ApiReallocate,
&vm_image_writer, &isolate_image_writer);
@@ -6723,8 +6736,8 @@
NOT_IN_PRODUCT(TimelineDurationScope tds2(T, Timeline::GetIsolateStream(),
"WriteAppJITSnapshot"));
BlobImageWriter isolate_image_writer(isolate_snapshot_instructions_buffer,
- ApiReallocate,
- 2 * MB /* initial_size */);
+ ApiReallocate, 2 * MB /* initial_size */,
+ NULL, NULL);
FullSnapshotWriter writer(Snapshot::kFullJIT, NULL,
isolate_snapshot_data_buffer, ApiReallocate, NULL,
&isolate_image_writer);
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index a7d2eb9..377cff0 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -137,7 +137,7 @@
TEST_CASE(DartAPI_DeepStackTraceInfo) {
const char* kScriptChars =
"foo(n) => n == 1 ? throw new Error() : foo(n-1);\n"
- "testMain() => foo(50);\n";
+ "testMain() => foo(100);\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle error = Dart_Invoke(lib, NewString("testMain"), 0, NULL);
@@ -151,10 +151,10 @@
intptr_t frame_count = 0;
result = Dart_StackTraceLength(stacktrace, &frame_count);
EXPECT_VALID(result);
- EXPECT_EQ(51, frame_count);
+ EXPECT_EQ(101, frame_count);
// Test something bigger than the preallocated size to verify nothing was
// truncated.
- EXPECT(51 > StackTrace::kPreallocatedStackdepth);
+ EXPECT(101 > StackTrace::kPreallocatedStackdepth);
Dart_Handle function_name;
Dart_Handle script_url;
@@ -320,10 +320,10 @@
intptr_t frame_count = 0;
result = Dart_StackTraceLength(stacktrace, &frame_count);
EXPECT_VALID(result);
- EXPECT_EQ(52, frame_count);
+ EXPECT_EQ(102, frame_count);
// Test something bigger than the preallocated size to verify nothing was
// truncated.
- EXPECT(52 > StackTrace::kPreallocatedStackdepth);
+ EXPECT(102 > StackTrace::kPreallocatedStackdepth);
Dart_Handle function_name;
Dart_Handle script_url;
@@ -412,7 +412,7 @@
const char* kScriptChars =
"inspectStack() native 'CurrentStackTraceNatve';\n"
"foo(n) => n == 1 ? inspectStack() : foo(n-1);\n"
- "testMain() => foo(50);\n";
+ "testMain() => foo(100);\n";
Dart_Handle lib =
TestCase::LoadTestScript(kScriptChars, &CurrentStackTraceNativeLookup);
@@ -3385,9 +3385,10 @@
api_flags.enable_error_on_bad_override = true;
api_flags.use_dart_frontend = FLAG_use_dart_frontend;
char* err;
- Dart_Isolate isolate = Dart_CreateIsolate(
- NULL, NULL, bin::core_isolate_snapshot_data,
- bin::core_isolate_snapshot_instructions, &api_flags, NULL, &err);
+ Dart_Isolate isolate =
+ Dart_CreateIsolate(NULL, NULL, bin::core_isolate_snapshot_data,
+ bin::core_isolate_snapshot_instructions, NULL, NULL,
+ &api_flags, NULL, &err);
if (isolate == NULL) {
OS::PrintErr("Creation of isolate failed '%s'\n", err);
free(err);
@@ -5003,7 +5004,6 @@
TEST_CASE(DartAPI_InvokeNoSuchMethod) {
const char* kScriptChars =
- "import 'dart:_internal' as _internal;\n"
"class Expect {\n"
" static equals(a, b) {\n"
" if (a != b) {\n"
@@ -5014,7 +5014,11 @@
"class TestClass {\n"
" static int fld1 = 0;\n"
" void noSuchMethod(Invocation invocation) {\n"
- " var name = _internal.Symbol.getName(invocation.memberName);\n"
+ // This relies on the Symbol.toString() method returning a String of the
+ // form 'Symbol("name")'. This is to avoid having to import
+ // dart:_internal just to get access to the name of the symbol.
+ " var name = invocation.memberName.toString();\n"
+ " name = name.split('\"')[1];\n"
" if (name == 'fld') {\n"
" Expect.equals(true, invocation.isGetter);\n"
" Expect.equals(false, invocation.isMethod);\n"
diff --git a/runtime/vm/dwarf.cc b/runtime/vm/dwarf.cc
index fc48ab7..8b2b14c 100644
--- a/runtime/vm/dwarf.cc
+++ b/runtime/vm/dwarf.cc
@@ -405,6 +405,10 @@
token_positions.RemoveLast();
break;
}
+ case CodeSourceMapBuilder::kNullCheck: {
+ stream.Read<int32_t>();
+ break;
+ }
default:
UNREACHABLE();
}
@@ -618,6 +622,10 @@
token_positions.RemoveLast();
break;
}
+ case CodeSourceMapBuilder::kNullCheck: {
+ stream.Read<int32_t>();
+ break;
+ }
default:
UNREACHABLE();
}
diff --git a/runtime/vm/gc_compactor.cc b/runtime/vm/gc_compactor.cc
index c35f86c..4aec300 100644
--- a/runtime/vm/gc_compactor.cc
+++ b/runtime/vm/gc_compactor.cc
@@ -69,15 +69,6 @@
0;
}
- // Marks all bits after a given address. This is used to ensure that some
- // objects do not move (classes).
- void MarkAllFrom(uword start_addr) {
- uword block_offset = start_addr & ~kBlockMask;
- intptr_t first_unit_position = block_offset >> kObjectAlignmentLog2;
- ASSERT(first_unit_position < kBitsPerWord);
- live_bitvector_ = static_cast<uword>(-1) << first_unit_position;
- }
-
uword new_address() const { return new_address_; }
void set_new_address(uword value) { new_address_ = value; }
@@ -147,9 +138,7 @@
void SlidePage(HeapPage* page);
uword PlanBlock(uword first_object, ForwardingPage* forwarding_page);
uword SlideBlock(uword first_object, ForwardingPage* forwarding_page);
- void PlanMoveToExactAddress(uword addr);
void PlanMoveToContiguousSize(intptr_t size);
- void SlideFreeUpTo(uword addr);
Isolate* isolate_;
GCCompactor* compactor_;
@@ -393,6 +382,9 @@
}
}
+// Plans the destination for a set of live objects starting with the first
+// live object that starts in a block, up to and including the last live
+// object that starts in that block.
uword CompactorTask::PlanBlock(uword first_object,
ForwardingPage* forwarding_page) {
uword block_start = first_object & kBlockMask;
@@ -400,7 +392,6 @@
ForwardingBlock* forwarding_block = forwarding_page->BlockFor(first_object);
// 1. Compute bitvector of surviving allocation units in the block.
- bool has_class = false;
intptr_t block_live_size = 0;
intptr_t block_dead_size = 0;
uword current = first_object;
@@ -408,9 +399,6 @@
RawObject* obj = RawObject::FromAddr(current);
intptr_t size = obj->Size();
if (obj->IsMarked()) {
- if (obj->GetClassId() == kClassCid) {
- has_class = true;
- }
forwarding_block->RecordLive(current, size);
ASSERT(static_cast<intptr_t>(forwarding_block->Lookup(current)) ==
block_live_size);
@@ -421,26 +409,11 @@
current += size;
}
- // 2. Find the next contiguous space that can fit the block.
- if (has_class) {
- // This will waste the space used by dead objects that are before the class
- // object.
- PlanMoveToExactAddress(first_object);
- ASSERT(free_current_ == first_object);
-
- // This is not MarkAll because the first part of a block might
- // be the tail end of an object belonging to the previous block
- // or the page header.
- forwarding_block->MarkAllFrom(first_object);
- ASSERT(forwarding_block->Lookup(first_object) == 0);
-
- forwarding_block->set_new_address(free_current_);
- free_current_ += block_live_size + block_dead_size;
- } else {
- PlanMoveToContiguousSize(block_live_size);
- forwarding_block->set_new_address(free_current_);
- free_current_ += block_live_size;
- }
+ // 2. Find the next contiguous space that can fit the live objects that
+ // start in the block.
+ PlanMoveToContiguousSize(block_live_size);
+ forwarding_block->set_new_address(free_current_);
+ free_current_ += block_live_size;
return current; // First object in the next block
}
@@ -451,23 +424,34 @@
uword block_end = block_start + kBlockSize;
ForwardingBlock* forwarding_block = forwarding_page->BlockFor(first_object);
- // Add any space wasted at the end of a page or due to class pinning to the
- // free list.
- SlideFreeUpTo(forwarding_block->new_address());
-
uword old_addr = first_object;
while (old_addr < block_end) {
RawObject* old_obj = RawObject::FromAddr(old_addr);
intptr_t size = old_obj->Size();
if (old_obj->IsMarked()) {
uword new_addr = forwarding_block->Lookup(old_addr);
+ if (new_addr != free_current_) {
+ // The only situation where these two don't match is if we are moving
+ // to a new page. But if we exactly hit the end of the previous page
+ // then free_current could be at the start of the next page, so we
+ // subtract 1.
+ ASSERT(HeapPage::Of(free_current_ - 1) != HeapPage::Of(new_addr));
+ intptr_t free_remaining = free_end_ - free_current_;
+ // Add any leftover at the end of a page to the free list.
+ if (free_remaining > 0) {
+ freelist_->Free(free_current_, free_remaining);
+ }
+ free_page_ = free_page_->next();
+ ASSERT(free_page_ != NULL);
+ free_current_ = free_page_->object_start();
+ free_end_ = free_page_->object_end();
+ ASSERT(free_current_ == new_addr);
+ }
RawObject* new_obj = RawObject::FromAddr(new_addr);
// Fast path for no movement. There's often a large block of objects at
// the beginning that don't move.
if (new_addr != old_addr) {
- ASSERT(old_obj->GetClassId() != kClassCid);
-
// Slide the object down.
memmove(reinterpret_cast<void*>(new_addr),
reinterpret_cast<void*>(old_addr), size);
@@ -477,11 +461,8 @@
ASSERT(free_current_ == new_addr);
free_current_ += size;
- } else if (forwarding_block->IsLive(old_addr)) {
- // Gap we're keeping to prevent class movement.
- ASSERT(free_current_ == old_addr);
- freelist_->Free(old_addr, size);
- free_current_ += size;
+ } else {
+ ASSERT(!forwarding_block->IsLive(old_addr));
}
old_addr += size;
}
@@ -489,56 +470,6 @@
return old_addr; // First object in the next block.
}
-void CompactorTask::SlideFreeUpTo(uword addr) {
- if (free_current_ == addr) return;
-
- // Skip pages until class's page.
- ASSERT(free_page_ != NULL);
- while (!free_page_->Contains(addr)) {
- intptr_t free_remaining = free_end_ - free_current_;
- if (free_remaining != 0) {
- // Note we aren't bothering to check for a whole page to release.
- freelist_->Free(free_current_, free_remaining);
- }
- // And advance to the next free page.
- free_page_ = free_page_->next();
- ASSERT(free_page_ != NULL);
- free_current_ = free_page_->object_start();
- free_end_ = free_page_->object_end();
- }
-
- // Skip within page until class's address.
- intptr_t free_skip = addr - free_current_;
- if (free_skip != 0) {
- freelist_->Free(free_current_, free_skip);
- free_current_ += free_skip;
- }
-
- // Class object won't move.
- ASSERT(free_current_ == addr);
-}
-
-void CompactorTask::PlanMoveToExactAddress(uword addr) {
- // Skip space to ensure class objects do not move. Computing the size
- // of larger objects requires consulting their class, whose old body
- // might be overwritten during the sliding.
- // TODO(rmacnak): Keep class sizes off heap or class objects in
- // non-moving pages.
-
- // Skip pages until class's page.
- ASSERT(free_page_ != NULL);
- while (!free_page_->Contains(addr)) {
- // And advance to the next free page.
- free_page_ = free_page_->next();
- ASSERT(free_page_ != NULL);
- free_current_ = free_page_->object_start();
- free_end_ = free_page_->object_end();
- }
-
- // Skip within page until class's address.
- free_current_ = addr;
-}
-
void CompactorTask::PlanMoveToContiguousSize(intptr_t size) {
// Move the free cursor to ensure 'size' bytes of contiguous space.
ASSERT(size <= kPageSize);
diff --git a/runtime/vm/gc_compactor.h b/runtime/vm/gc_compactor.h
index 6fe1f1c..7ae687f 100644
--- a/runtime/vm/gc_compactor.h
+++ b/runtime/vm/gc_compactor.h
@@ -44,9 +44,9 @@
uword base;
uword size;
};
- // There are up to 4 images to consider:
- // {instructions, data} x {vm isolate, current isolate}
- static const intptr_t kMaxImagePages = 4;
+ // There are up to 6 images to consider:
+ // {instructions, data} x {vm isolate, current isolate, shared}
+ static const intptr_t kMaxImagePages = 6;
ImagePageRange image_page_ranges_[kMaxImagePages];
};
diff --git a/runtime/vm/globals.h b/runtime/vm/globals.h
index 4fa43f2..c15516d 100644
--- a/runtime/vm/globals.h
+++ b/runtime/vm/globals.h
@@ -21,9 +21,8 @@
#undef OVERFLOW // From math.h conflicts in constants_ia32.h
namespace dart {
-// Smi value range is from -(2^N) to (2^N)-1.
-// N=30 (32-bit build) or N=62 (64-bit build).
-const intptr_t kSmiBits = kBitsPerWord - 2;
+// Smi value range is from -(2^N) to (2^N)-1. N=30
+const intptr_t kSmiBits = 30;
const intptr_t kSmiMax = (static_cast<intptr_t>(1) << kSmiBits) - 1;
const intptr_t kSmiMin = -(static_cast<intptr_t>(1) << kSmiBits);
diff --git a/runtime/vm/hash.h b/runtime/vm/hash.h
new file mode 100644
index 0000000..aa9c28d
--- /dev/null
+++ b/runtime/vm/hash.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2018, 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.
+
+#ifndef RUNTIME_VM_HASH_H_
+#define RUNTIME_VM_HASH_H_
+
+namespace dart {
+
+static uint32_t CombineHashes(uint32_t hash, uint32_t other_hash) {
+ hash += other_hash;
+ hash += hash << 10;
+ hash ^= hash >> 6; // Logical shift, unsigned hash.
+ return hash;
+}
+
+static uint32_t FinalizeHash(uint32_t hash, intptr_t hashbits) {
+ hash += hash << 3;
+ hash ^= hash >> 11; // Logical shift, unsigned hash.
+ hash += hash << 15;
+ // FinalizeHash gets called with values for hashbits that are bigger than 31
+ // (like kBitsPerWord - 1). Therefore we are careful to use a type
+ // (uintptr_t) big enough to avoid undefined behavior with the left shift.
+ hash &= (static_cast<uintptr_t>(1) << hashbits) - 1;
+ return (hash == 0) ? 1 : hash;
+}
+
+} // namespace dart
+
+#endif // RUNTIME_VM_HASH_H_
diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc
index 89186a4..4210097 100644
--- a/runtime/vm/image_snapshot.cc
+++ b/runtime/vm/image_snapshot.cc
@@ -7,6 +7,8 @@
#include "platform/assert.h"
#include "vm/compiler/backend/code_statistics.h"
#include "vm/dwarf.h"
+#include "vm/hash.h"
+#include "vm/hash_map.h"
#include "vm/heap.h"
#include "vm/json_writer.h"
#include "vm/object.h"
@@ -28,8 +30,84 @@
"Print sizes of all instruction objects to the given file");
#endif
+intptr_t ObjectOffsetTrait::Hashcode(Key key) {
+ RawObject* obj = key;
+ ASSERT(!obj->IsSmi());
+
+ uword body = RawObject::ToAddr(obj) + sizeof(RawObject);
+ uword end = RawObject::ToAddr(obj) + obj->Size();
+
+ uint32_t hash = obj->GetClassId();
+ // Don't include the header. Objects in the image are pre-marked, but objects
+ // in the current isolate are not.
+ for (uword cursor = body; cursor < end; cursor += sizeof(uint32_t)) {
+ hash = CombineHashes(hash, *reinterpret_cast<uint32_t*>(cursor));
+ }
+
+ return FinalizeHash(hash, 30);
+}
+
+bool ObjectOffsetTrait::IsKeyEqual(Pair pair, Key key) {
+ RawObject* a = pair.object;
+ RawObject* b = key;
+ ASSERT(!a->IsSmi());
+ ASSERT(!b->IsSmi());
+
+ if (a->GetClassId() != b->GetClassId()) {
+ return false;
+ }
+
+ intptr_t heap_size = a->Size();
+ if (b->Size() != heap_size) {
+ return false;
+ }
+
+ // Don't include the header. Objects in the image are pre-marked, but objects
+ // in the current isolate are not.
+ uword body_a = RawObject::ToAddr(a) + sizeof(RawObject);
+ uword body_b = RawObject::ToAddr(b) + sizeof(RawObject);
+ uword body_size = heap_size - sizeof(RawObject);
+ return 0 == memcmp(reinterpret_cast<const void*>(body_a),
+ reinterpret_cast<const void*>(body_b), body_size);
+}
+
+ImageWriter::ImageWriter(const void* shared_objects,
+ const void* shared_instructions)
+ : next_data_offset_(0), next_text_offset_(0), objects_(), instructions_() {
+ ResetOffsets();
+ SetupShared(&shared_objects_, shared_objects);
+ SetupShared(&shared_instructions_, shared_instructions);
+}
+
+void ImageWriter::SetupShared(ObjectOffsetMap* map, const void* shared_image) {
+ if (shared_image == NULL) {
+ return;
+ }
+ Image image(shared_image);
+ uword obj_addr = reinterpret_cast<uword>(image.object_start());
+ uword end_addr = obj_addr + image.object_size();
+ while (obj_addr < end_addr) {
+ int32_t offset = obj_addr - reinterpret_cast<uword>(shared_image);
+ RawObject* raw_obj = RawObject::FromAddr(obj_addr);
+ ObjectOffsetPair pair;
+ pair.object = raw_obj;
+ pair.offset = offset;
+ map->Insert(pair);
+ obj_addr += raw_obj->Size();
+ }
+ ASSERT(obj_addr == end_addr);
+}
+
int32_t ImageWriter::GetTextOffsetFor(RawInstructions* instructions,
RawCode* code) {
+ ObjectOffsetPair* pair = shared_instructions_.Lookup(instructions);
+ if (pair != NULL) {
+ // Negative offsets tell the reader the offset is w/r/t the shared
+ // instructions image instead of the app-specific instructions image.
+ // Compare ImageReader::GetInstructionsAt.
+ return -pair->offset;
+ }
+
intptr_t heap_size = instructions->Size();
intptr_t offset = next_text_offset_;
next_text_offset_ += heap_size;
@@ -37,6 +115,16 @@
return offset;
}
+bool ImageWriter::GetSharedDataOffsetFor(RawObject* raw_object,
+ uint32_t* offset) {
+ ObjectOffsetPair* pair = shared_objects_.Lookup(raw_object);
+ if (pair == NULL) {
+ return false;
+ }
+ *offset = pair->offset;
+ return true;
+}
+
uint32_t ImageWriter::GetDataOffsetFor(RawObject* raw_object) {
intptr_t heap_size = raw_object->Size();
intptr_t offset = next_data_offset_;
@@ -136,10 +224,9 @@
ASSERT(data.raw_code_ != NULL);
data.code_ = &Code::Handle(zone, data.raw_code_);
- // Update object id table with offsets that will refer to the VM snapshot,
- // causing a subsequently written isolate snapshot to share instructions
- // with the VM snapshot.
- heap->SetObjectId(data.insns_->raw(), -data.offset_);
+ // Reset object id as an isolate snapshot after a VM snapshot will not use
+ // the VM snapshot's text image.
+ heap->SetObjectId(data.insns_->raw(), 0);
}
for (intptr_t i = 0; i < objects_.length(); i++) {
ObjectData& data = objects_[i];
@@ -187,8 +274,10 @@
}
AssemblyImageWriter::AssemblyImageWriter(Dart_StreamingWriteCallback callback,
- void* callback_data)
- : ImageWriter(),
+ void* callback_data,
+ const void* shared_objects,
+ const void* shared_instructions)
+ : ImageWriter(shared_objects, shared_instructions),
assembly_stream_(512 * KB, callback, callback_data),
dwarf_(NULL) {
#if defined(DART_PRECOMPILER)
@@ -432,6 +521,15 @@
}
}
+BlobImageWriter::BlobImageWriter(uint8_t** instructions_blob_buffer,
+ ReAlloc alloc,
+ intptr_t initial_size,
+ const void* shared_objects,
+ const void* shared_instructions)
+ : ImageWriter(shared_objects, shared_instructions),
+ instructions_blob_stream_(instructions_blob_buffer, alloc, initial_size) {
+}
+
void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
// This header provides the gap to make the instructions snapshot look like a
// HeapPage.
@@ -475,40 +573,54 @@
}
}
-ImageReader::ImageReader(const uint8_t* instructions_buffer,
- const uint8_t* data_buffer)
- : instructions_buffer_(instructions_buffer), data_buffer_(data_buffer) {
- ASSERT(instructions_buffer != NULL);
- ASSERT(data_buffer != NULL);
- ASSERT(Utils::IsAligned(reinterpret_cast<uword>(instructions_buffer),
+ImageReader::ImageReader(const uint8_t* data_image,
+ const uint8_t* instructions_image,
+ const uint8_t* shared_data_image,
+ const uint8_t* shared_instructions_image)
+ : data_image_(data_image),
+ instructions_image_(instructions_image),
+ shared_data_image_(shared_data_image),
+ shared_instructions_image_(shared_instructions_image) {
+ ASSERT(data_image != NULL);
+ ASSERT(instructions_image != NULL);
+ ASSERT(Utils::IsAligned(reinterpret_cast<uword>(instructions_image),
OS::PreferredCodeAlignment()));
- vm_instructions_buffer_ = Dart::vm_snapshot_instructions();
+ ASSERT(Utils::IsAligned(reinterpret_cast<uword>(shared_instructions_image),
+ OS::PreferredCodeAlignment()));
}
RawInstructions* ImageReader::GetInstructionsAt(int32_t offset) const {
ASSERT(Utils::IsAligned(offset, OS::PreferredCodeAlignment()));
- RawInstructions* result;
+ RawObject* result;
if (offset < 0) {
- result = reinterpret_cast<RawInstructions*>(
- reinterpret_cast<uword>(vm_instructions_buffer_) - offset +
- kHeapObjectTag);
+ result = RawObject::FromAddr(
+ reinterpret_cast<uword>(shared_instructions_image_) - offset);
} else {
- result = reinterpret_cast<RawInstructions*>(
- reinterpret_cast<uword>(instructions_buffer_) + offset +
- kHeapObjectTag);
+ result = RawObject::FromAddr(reinterpret_cast<uword>(instructions_image_) +
+ offset);
}
ASSERT(result->IsInstructions());
ASSERT(result->IsMarked());
+ return Instructions::RawCast(result);
+}
+
+RawObject* ImageReader::GetObjectAt(uint32_t offset) const {
+ ASSERT(Utils::IsAligned(offset, kObjectAlignment));
+
+ RawObject* result =
+ RawObject::FromAddr(reinterpret_cast<uword>(data_image_) + offset);
+ ASSERT(result->IsMarked());
+
return result;
}
-RawObject* ImageReader::GetObjectAt(uint32_t offset) const {
- ASSERT(Utils::IsAligned(offset, kWordSize));
+RawObject* ImageReader::GetSharedObjectAt(uint32_t offset) const {
+ ASSERT(Utils::IsAligned(offset, kObjectAlignment));
- RawObject* result = reinterpret_cast<RawObject*>(
- reinterpret_cast<uword>(data_buffer_) + offset + kHeapObjectTag);
+ RawObject* result =
+ RawObject::FromAddr(reinterpret_cast<uword>(shared_data_image_) + offset);
ASSERT(result->IsMarked());
return result;
diff --git a/runtime/vm/image_snapshot.h b/runtime/vm/image_snapshot.h
index 5e9fe3d..99a3e02 100644
--- a/runtime/vm/image_snapshot.h
+++ b/runtime/vm/image_snapshot.h
@@ -10,6 +10,7 @@
#include "vm/datastream.h"
#include "vm/globals.h"
#include "vm/growable_array.h"
+#include "vm/hash_map.h"
namespace dart {
@@ -48,42 +49,68 @@
class ImageReader : public ZoneAllocated {
public:
- ImageReader(const uint8_t* instructions_buffer, const uint8_t* data_buffer);
+ ImageReader(const uint8_t* data_image,
+ const uint8_t* instructions_image,
+ const uint8_t* shared_data_image,
+ const uint8_t* shared_instructions_image);
RawInstructions* GetInstructionsAt(int32_t offset) const;
RawObject* GetObjectAt(uint32_t offset) const;
+ RawObject* GetSharedObjectAt(uint32_t offset) const;
private:
- const uint8_t* instructions_buffer_;
- const uint8_t* data_buffer_;
- const uint8_t* vm_instructions_buffer_;
+ const uint8_t* data_image_;
+ const uint8_t* instructions_image_;
+ const uint8_t* shared_data_image_;
+ const uint8_t* shared_instructions_image_;
DISALLOW_COPY_AND_ASSIGN(ImageReader);
};
-class ImageWriter : public ZoneAllocated {
+struct ObjectOffsetPair {
public:
- ImageWriter()
- : next_text_offset_(0),
- next_data_offset_(0),
- instructions_(),
- objects_() {
- ResetOffsets();
- }
+ ObjectOffsetPair() : ObjectOffsetPair(NULL, 0) {}
+ ObjectOffsetPair(RawObject* obj, int32_t off) : object(obj), offset(off) {}
+
+ RawObject* object;
+ int32_t offset;
+};
+
+class ObjectOffsetTrait {
+ public:
+ // Typedefs needed for the DirectChainedHashMap template.
+ typedef RawObject* Key;
+ typedef int32_t Value;
+ typedef ObjectOffsetPair Pair;
+
+ static Key KeyOf(Pair kv) { return kv.object; }
+ static Value ValueOf(Pair kv) { return kv.offset; }
+ static intptr_t Hashcode(Key key);
+ static inline bool IsKeyEqual(Pair pair, Key key);
+};
+
+typedef DirectChainedHashMap<ObjectOffsetTrait> ObjectOffsetMap;
+
+class ImageWriter : public ValueObject {
+ public:
+ ImageWriter(const void* shared_objects, const void* shared_instructions);
virtual ~ImageWriter() {}
+ void SetupShared(ObjectOffsetMap* map, const void* shared_image);
void ResetOffsets() {
- next_text_offset_ = Image::kHeaderSize;
next_data_offset_ = Image::kHeaderSize;
- instructions_.Clear();
+ next_text_offset_ = Image::kHeaderSize;
objects_.Clear();
+ instructions_.Clear();
}
+
int32_t GetTextOffsetFor(RawInstructions* instructions, RawCode* code);
+ bool GetSharedDataOffsetFor(RawObject* raw_object, uint32_t* offset);
uint32_t GetDataOffsetFor(RawObject* raw_object);
void Write(WriteStream* clustered_stream, bool vm);
- intptr_t text_size() const { return next_text_offset_; }
intptr_t data_size() const { return next_data_offset_; }
+ intptr_t text_size() const { return next_text_offset_; }
void DumpStatistics();
@@ -120,10 +147,12 @@
};
};
- intptr_t next_text_offset_;
intptr_t next_data_offset_;
- GrowableArray<InstructionsData> instructions_;
+ intptr_t next_text_offset_;
GrowableArray<ObjectData> objects_;
+ GrowableArray<InstructionsData> instructions_;
+ ObjectOffsetMap shared_objects_;
+ ObjectOffsetMap shared_instructions_;
private:
DISALLOW_COPY_AND_ASSIGN(ImageWriter);
@@ -132,7 +161,9 @@
class AssemblyImageWriter : public ImageWriter {
public:
AssemblyImageWriter(Dart_StreamingWriteCallback callback,
- void* callback_data);
+ void* callback_data,
+ const void* shared_objects,
+ const void* shared_instructions);
void Finalize();
virtual void WriteText(WriteStream* clustered_stream, bool vm);
@@ -160,11 +191,9 @@
public:
BlobImageWriter(uint8_t** instructions_blob_buffer,
ReAlloc alloc,
- intptr_t initial_size)
- : ImageWriter(),
- instructions_blob_stream_(instructions_blob_buffer,
- alloc,
- initial_size) {}
+ intptr_t initial_size,
+ const void* shared_objects,
+ const void* shared_instructions);
virtual void WriteText(WriteStream* clustered_stream, bool vm);
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 4fe67e6..b444072 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -1979,6 +1979,18 @@
return raw_class;
}
+intptr_t Isolate::GetClassSizeForHeapWalkAt(intptr_t cid) {
+#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
+ if (IsReloading()) {
+ return reload_context()->GetClassSizeForHeapWalkAt(cid);
+ } else {
+ return class_table()->SizeAt(cid);
+ }
+#else
+ return class_table()->SizeAt(cid);
+#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
+}
+
void Isolate::AddPendingDeopt(uword fp, uword pc) {
// GrowableArray::Add is not atomic and may be interrupt by a profiler
// stack walk.
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index b3a69f1..0febbfe 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -211,6 +211,7 @@
// Prefers old classes when we are in the middle of a reload.
RawClass* GetClassForHeapWalkAt(intptr_t cid);
+ intptr_t GetClassSizeForHeapWalkAt(intptr_t cid);
static intptr_t ic_miss_code_offset() {
return OFFSET_OF(Isolate, ic_miss_code_);
@@ -623,7 +624,6 @@
ASSERT(value >= 0);
return value > 0;
}
-
void IncrTopLevelParsingCount() {
AtomicOperations::IncrementBy(&top_level_parsing_count_, 1);
}
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index eb78a50..8dcf7d8 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -918,15 +918,15 @@
saved_num_cids_ = I->class_table()->NumCids();
// Copy of the class table.
- RawClass** local_saved_class_table =
- reinterpret_cast<RawClass**>(malloc(sizeof(RawClass*) * saved_num_cids_));
+ ClassAndSize* local_saved_class_table = reinterpret_cast<ClassAndSize*>(
+ malloc(sizeof(ClassAndSize) * saved_num_cids_));
Class& cls = Class::Handle();
UnorderedHashSet<ClassMapTraits> old_classes_set(old_classes_set_storage_);
for (intptr_t i = 0; i < saved_num_cids_; i++) {
if (class_table->IsValidIndex(i) && class_table->HasValidClassAt(i)) {
// Copy the class into the saved class table and add it to the set.
- local_saved_class_table[i] = class_table->At(i);
+ local_saved_class_table[i] = class_table->PairAt(i);
if (i != kFreeListElement && i != kForwardingCorpse) {
cls = class_table->At(i);
bool already_present = old_classes_set.Insert(cls);
@@ -934,7 +934,7 @@
}
} else {
// No class at this index, mark it as NULL.
- local_saved_class_table[i] = NULL;
+ local_saved_class_table[i] = ClassAndSize(NULL);
}
}
old_classes_set_storage_ = old_classes_set.Release().raw();
@@ -1197,11 +1197,11 @@
// Overwrite classes in class table with the saved classes.
for (intptr_t i = 0; i < saved_num_cids_; i++) {
if (class_table->IsValidIndex(i)) {
- class_table->SetAt(i, saved_class_table_[i]);
+ class_table->SetAt(i, saved_class_table_[i].get_raw_class());
}
}
- RawClass** local_saved_class_table = saved_class_table_;
+ ClassAndSize* local_saved_class_table = saved_class_table_;
saved_class_table_ = NULL;
// Can't free this table immediately as another thread (e.g., the sweeper) may
// be suspended between loading the table pointer and loading the table
@@ -1644,7 +1644,7 @@
}
// This is important: The saved class table (describing before objects)
- // must be zapped to prevent the forwarding in GetClassForHeapWalkAt.
+ // must be zapped to prevent the forwarding in GetClassSizeForHeapWalkAt.
// Instance will from now be described by the isolate's class table.
free(saved_class_table_);
saved_class_table_ = NULL;
@@ -1709,16 +1709,29 @@
}
RawClass* IsolateReloadContext::GetClassForHeapWalkAt(intptr_t cid) {
- RawClass** class_table = AtomicOperations::LoadRelaxed(&saved_class_table_);
+ ClassAndSize* class_table =
+ AtomicOperations::LoadRelaxed(&saved_class_table_);
if (class_table != NULL) {
ASSERT(cid > 0);
ASSERT(cid < saved_num_cids_);
- return class_table[cid];
+ return class_table[cid].get_raw_class();
} else {
return isolate_->class_table()->At(cid);
}
}
+intptr_t IsolateReloadContext::GetClassSizeForHeapWalkAt(intptr_t cid) {
+ ClassAndSize* class_table =
+ AtomicOperations::LoadRelaxed(&saved_class_table_);
+ if (class_table != NULL) {
+ ASSERT(cid > 0);
+ ASSERT(cid < saved_num_cids_);
+ return class_table[cid].size();
+ } else {
+ return isolate_->class_table()->SizeAt(cid);
+ }
+}
+
RawLibrary* IsolateReloadContext::saved_root_library() const {
return saved_root_library_;
}
diff --git a/runtime/vm/isolate_reload.h b/runtime/vm/isolate_reload.h
index 715802e..f811329 100644
--- a/runtime/vm/isolate_reload.h
+++ b/runtime/vm/isolate_reload.h
@@ -169,6 +169,7 @@
// Prefers old classes when we are in the middle of a reload.
RawClass* GetClassForHeapWalkAt(intptr_t cid);
+ intptr_t GetClassSizeForHeapWalkAt(intptr_t cid);
void RegisterClass(const Class& new_cls);
@@ -280,7 +281,7 @@
JSONStream* js_;
intptr_t saved_num_cids_;
- RawClass** saved_class_table_;
+ ClassAndSize* saved_class_table_;
intptr_t num_saved_libs_;
// Collect the necessary instance transformation for schema changes.
diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc
index 20edba6..d8e1d5d 100644
--- a/runtime/vm/isolate_reload_test.cc
+++ b/runtime/vm/isolate_reload_test.cc
@@ -1210,11 +1210,18 @@
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
- EXPECT_STREQ("instance", SimpleInvokeStr(lib, "main"));
+ const char* expected = "instance";
+ const char* result = SimpleInvokeStr(lib, "main");
+ EXPECT_STREQ(expected, result);
+
+ // Bail out if we've already failed so we don't crash in the tag handler.
+ if ((result == NULL) || (strcmp(expected, result) != 0)) {
+ return;
+ }
lib = Dart_RootLibrary();
EXPECT_NON_NULL(lib);
- EXPECT_STREQ("instance", SimpleInvokeStr(lib, "main"));
+ EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_PendingUnqualifiedCall_InstanceToStatic) {
@@ -1249,11 +1256,24 @@
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
- EXPECT_STREQ("static", SimpleInvokeStr(lib, "main"));
+ const char* expected = "static";
+ const char* result = SimpleInvokeStr(lib, "main");
+ EXPECT_NOTNULL(result);
+
+ // Bail out if we've already failed so we don't crash in StringEquals.
+ if (result == NULL) {
+ return;
+ }
+ EXPECT_STREQ(expected, result);
+
+ // Bail out if we've already failed so we don't crash in the tag handler.
+ if (strcmp(expected, result) != 0) {
+ return;
+ }
lib = Dart_RootLibrary();
EXPECT_NON_NULL(lib);
- EXPECT_STREQ("static", SimpleInvokeStr(lib, "main"));
+ EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_PendingConstructorCall_AbstractToConcrete) {
@@ -1298,11 +1318,18 @@
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
- EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
+ const char* expected = "okay";
+ const char* result = SimpleInvokeStr(lib, "main");
+ EXPECT_STREQ(expected, result);
+
+ // Bail out if we've already failed so we don't crash in the tag handler.
+ if ((result == NULL) || (strcmp(expected, result) != 0)) {
+ return;
+ }
lib = Dart_RootLibrary();
EXPECT_NON_NULL(lib);
- EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
+ EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_PendingConstructorCall_ConcreteToAbstract) {
@@ -1347,18 +1374,25 @@
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
- EXPECT_STREQ("exception", SimpleInvokeStr(lib, "main"));
+ const char* expected = "exception";
+ const char* result = SimpleInvokeStr(lib, "main");
+ EXPECT_STREQ(expected, result);
+
+ // Bail out if we've already failed so we don't crash in the tag handler.
+ if ((result == NULL) || (strcmp(expected, result) != 0)) {
+ return;
+ }
lib = Dart_RootLibrary();
EXPECT_NON_NULL(lib);
- EXPECT_STREQ("exception", SimpleInvokeStr(lib, "main"));
+ EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_PendingStaticCall_DefinedToNSM) {
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
- " static foo() => 'static'\n"
+ " static foo() => 'static';\n"
" test() {\n"
" reloadTest();\n"
" return C.foo();\n"
@@ -1393,11 +1427,25 @@
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
- EXPECT_STREQ("exception", SimpleInvokeStr(lib, "main"));
+ const char* expected = "exception";
+ const char* result = SimpleInvokeStr(lib, "main");
+ EXPECT_NOTNULL(result);
+ // Bail out if we've already failed so we don't crash in StringEquals.
+ if (result == NULL) {
+ return;
+ }
+ EXPECT_STREQ(expected, result);
+
+ // Bail out if we've already failed so we don't crash in the tag handler.
+ if (strcmp(expected, result) != 0) {
+ return;
+ }
+
+ EXPECT_STREQ(expected, result);
lib = Dart_RootLibrary();
EXPECT_NON_NULL(lib);
- EXPECT_STREQ("exception", SimpleInvokeStr(lib, "main"));
+ EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_PendingStaticCall_NSMToDefined) {
@@ -1423,7 +1471,7 @@
const char* kReloadScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
- " static foo() => 'static'\n"
+ " static foo() => 'static';\n"
" test() {\n"
" reloadTest();\n"
" return C.foo();\n"
@@ -1439,11 +1487,18 @@
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
- EXPECT_STREQ("static", SimpleInvokeStr(lib, "main"));
+ const char* expected = "static";
+ const char* result = SimpleInvokeStr(lib, "main");
+ EXPECT_STREQ(expected, result);
+
+ // Bail out if we've already failed so we don't crash in the tag handler.
+ if ((result == NULL) || (strcmp(expected, result) != 0)) {
+ return;
+ }
lib = Dart_RootLibrary();
EXPECT_NON_NULL(lib);
- EXPECT_STREQ("static", SimpleInvokeStr(lib, "main"));
+ EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_PendingSuperCall) {
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index a5521fc..e426f4d 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -149,8 +149,9 @@
kMapConstant = 5,
kListConstant = 6,
kInstanceConstant = 7,
- kTearOffConstant = 8,
- kTypeLiteralConstant = 9,
+ kPartialInstantiationConstant = 8,
+ kTearOffConstant = 9,
+ kTypeLiteralConstant = 10,
};
static const int SpecializedIntLiteralBias = 3;
diff --git a/runtime/vm/kernel_isolate.cc b/runtime/vm/kernel_isolate.cc
index 4445773..a8a9a1f 100644
--- a/runtime/vm/kernel_isolate.cc
+++ b/runtime/vm/kernel_isolate.cc
@@ -48,12 +48,10 @@
// 1 - Update in-memory file system with in-memory sources (used by tests).
// 2 - Accept last compilation result.
// 3 - APP JIT snapshot training run for kernel_service.
-// 4 - Allows for `dart:_internal` to be imported (used by tests).
const int KernelIsolate::kCompileTag = 0;
const int KernelIsolate::kUpdateSourcesTag = 1;
const int KernelIsolate::kAcceptTag = 2;
const int KernelIsolate::kTrainTag = 3;
-const int KernelIsolate::kAllowDartInternalImportTag = 4;
Dart_IsolateCreateCallback KernelIsolate::create_callback_ = NULL;
Monitor* KernelIsolate::monitor_ = new Monitor();
@@ -611,23 +609,6 @@
NULL, 0, source_files_count,
source_files, true);
}
-
-Dart_KernelCompilationResult KernelIsolate::AllowDartInternalImport() {
- // This must be the main script to be loaded. Wait for Kernel isolate
- // to finish initialization.
- Dart_Port kernel_port = WaitForKernelPort();
- if (kernel_port == ILLEGAL_PORT) {
- Dart_KernelCompilationResult result;
- result.status = Dart_KernelCompilationStatus_Unknown;
- result.error = strdup("Error while initializing Kernel isolate");
- return result;
- }
-
- KernelCompilationRequest request;
- return request.SendAndWaitForResponse(
- kAllowDartInternalImportTag, kernel_port, NULL, NULL, 0, 0, NULL, true);
-}
-
#endif // DART_PRECOMPILED_RUNTIME
} // namespace dart
diff --git a/runtime/vm/kernel_isolate.h b/runtime/vm/kernel_isolate.h
index 913b5c6..001aa41 100644
--- a/runtime/vm/kernel_isolate.h
+++ b/runtime/vm/kernel_isolate.h
@@ -22,7 +22,6 @@
static const int kUpdateSourcesTag;
static const int kAcceptTag;
static const int kTrainTag;
- static const int kAllowDartInternalImportTag;
static void Run();
@@ -45,7 +44,6 @@
static Dart_KernelCompilationResult UpdateInMemorySources(
int source_files_count,
Dart_SourceFile source_files[]);
- static Dart_KernelCompilationResult AllowDartInternalImport();
protected:
static Monitor* monitor_;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index c856133..7c31cf4 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -29,6 +29,7 @@
#include "vm/double_conversion.h"
#include "vm/exceptions.h"
#include "vm/growable_array.h"
+#include "vm/hash.h"
#include "vm/hash_table.h"
#include "vm/heap.h"
#include "vm/isolate_reload.h"
@@ -1835,6 +1836,8 @@
return error.raw();
}
+ isolate->class_table()->CopySizesFromClassObjects();
+
ClassFinalizer::VerifyBootstrapClasses();
// Set up the intrinsic state of all functions (core, math and typed data).
@@ -2908,14 +2911,19 @@
}
void Class::Finalize() const {
+ Isolate* isolate = Isolate::Current();
ASSERT(Thread::Current()->IsMutatorThread());
- ASSERT(!Isolate::Current()->all_classes_finalized());
+ ASSERT(!isolate->all_classes_finalized());
ASSERT(!is_finalized());
// Prefinalized classes have a VM internal representation and no Dart fields.
// Their instance size is precomputed and field offsets are known.
if (!is_prefinalized()) {
// Compute offsets of instance fields and instance size.
CalculateFieldOffsets();
+ if (raw() == isolate->class_table()->At(id())) {
+ // Sets the new size in the class table.
+ isolate->class_table()->SetAt(id(), raw());
+ }
}
set_is_finalized();
}
@@ -4828,24 +4836,6 @@
return OS::SCreate(Thread::Current()->zone(), "unresolved class '%s'", cname);
}
-static uint32_t CombineHashes(uint32_t hash, uint32_t other_hash) {
- hash += other_hash;
- hash += hash << 10;
- hash ^= hash >> 6; // Logical shift, unsigned hash.
- return hash;
-}
-
-static uint32_t FinalizeHash(uint32_t hash, intptr_t hashbits) {
- hash += hash << 3;
- hash ^= hash >> 11; // Logical shift, unsigned hash.
- hash += hash << 15;
- // FinalizeHash gets called with values for hashbits that are bigger than 31
- // (like kBitsPerWord - 1). Therefore we are careful to use a type
- // (uintptr_t) big enough to avoid undefined behavior with the left shift.
- hash &= (static_cast<uintptr_t>(1) << hashbits) - 1;
- return (hash == 0) ? 1 : hash;
-}
-
intptr_t TypeArguments::ComputeHash() const {
if (IsNull()) return 0;
const intptr_t num_types = Length();
@@ -22765,6 +22755,16 @@
const Function& function,
const Context& context,
Heap::Space space) {
+ return Closure::New(instantiator_type_arguments, function_type_arguments,
+ Object::empty_type_arguments(), function, context, space);
+}
+
+RawClosure* Closure::New(const TypeArguments& instantiator_type_arguments,
+ const TypeArguments& function_type_arguments,
+ const TypeArguments& delayed_type_arguments,
+ const Function& function,
+ const Context& context,
+ Heap::Space space) {
Closure& result = Closure::Handle();
{
RawObject* raw =
@@ -22776,7 +22776,7 @@
result.StorePointer(&result.raw_ptr()->function_type_arguments_,
function_type_arguments.raw());
result.StorePointer(&result.raw_ptr()->delayed_type_arguments_,
- Object::empty_type_arguments().raw());
+ delayed_type_arguments.raw());
result.StorePointer(&result.raw_ptr()->function_, function.raw());
result.StorePointer(&result.raw_ptr()->context_, context.raw());
}
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index ea2c4d5..60e0288 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -915,6 +915,9 @@
ASSERT(is_finalized() || is_prefinalized());
return (raw_ptr()->instance_size_in_words_ * kWordSize);
}
+ static intptr_t instance_size(RawClass* clazz) {
+ return (clazz->ptr()->instance_size_in_words_ * kWordSize);
+ }
void set_instance_size(intptr_t value_in_bytes) const {
ASSERT(kWordSize != 0);
set_instance_size_in_words(value_in_bytes / kWordSize);
@@ -4422,8 +4425,11 @@
RawPcDescriptors::MergedKindTry::DecodeTryIndex(merged_kind_try);
cur_pc_offset_ += descriptors_.DecodeInteger(&byte_index_);
- cur_deopt_id_ += descriptors_.DecodeInteger(&byte_index_);
- cur_token_pos_ += descriptors_.DecodeInteger(&byte_index_);
+
+ if (!FLAG_precompiled_mode) {
+ cur_deopt_id_ += descriptors_.DecodeInteger(&byte_index_);
+ cur_token_pos_ += descriptors_.DecodeInteger(&byte_index_);
+ }
if ((cur_kind_ & kind_mask_) != 0) {
return true; // Current is valid.
@@ -7907,7 +7913,16 @@
virtual uword ComputeCanonicalTableHash() const;
static const intptr_t kBytesPerElement = kWordSize;
- static const intptr_t kMaxElements = kSmiMax / kBytesPerElement;
+ // The length field is a Smi so that sets one limit on the max Array length.
+ // But we also need to be able to represent the length in bytes in an
+ // intptr_t, which is a different limit. Either may be smaller. We can't
+ // use Utils::Minimum here because it is not a const expression.
+ static const intptr_t kElementLimitDueToIntptrMax = static_cast<intptr_t>(
+ (kIntptrMax - sizeof(RawArray) - kObjectAlignment + kBytesPerElement) /
+ kBytesPerElement);
+ static const intptr_t kMaxElements = kSmiMax < kElementLimitDueToIntptrMax
+ ? kSmiMax
+ : kElementLimitDueToIntptrMax;
static const intptr_t kMaxNewSpaceElements =
(Heap::kNewAllocatableSize - sizeof(RawArray)) / kBytesPerElement;
@@ -8791,6 +8806,13 @@
const Context& context,
Heap::Space space = Heap::kNew);
+ static RawClosure* New(const TypeArguments& instantiator_type_arguments,
+ const TypeArguments& function_type_arguments,
+ const TypeArguments& delayed_type_arguments,
+ const Function& function,
+ const Context& context,
+ Heap::Space space = Heap::kNew);
+
RawFunction* GetInstantiatedSignature(Zone* zone) const;
private:
@@ -8860,7 +8882,7 @@
// Internal stacktrace object used in exceptions for printing stack traces.
class StackTrace : public Instance {
public:
- static const int kPreallocatedStackdepth = 30;
+ static const int kPreallocatedStackdepth = 90;
intptr_t Length() const;
@@ -9146,6 +9168,7 @@
if ((raw_value & kSmiTagMask) == kSmiTag) {
return Smi::Class();
}
+ ASSERT(!Isolate::Current()->compaction_in_progress());
return Isolate::Current()->class_table()->At(raw()->GetClassId());
}
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index f7ffc17..17eadb0 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -308,16 +308,10 @@
EXPECT(Smi::IsValid(-15));
EXPECT(Smi::IsValid(0xFFu));
// Upper two bits must be either 00 or 11.
-#if defined(ARCH_IS_64_BIT)
- EXPECT(!Smi::IsValid(kMaxInt64));
- EXPECT(Smi::IsValid(0x3FFFFFFFFFFFFFFF));
- EXPECT(Smi::IsValid(-1));
-#else
EXPECT(!Smi::IsValid(kMaxInt32));
EXPECT(Smi::IsValid(0x3FFFFFFF));
EXPECT(Smi::IsValid(-1));
EXPECT(!Smi::IsValid(0xFFFFFFFFu));
-#endif
EXPECT_EQ(5, smi.AsInt64Value());
EXPECT_EQ(5.0, smi.AsDoubleValue());
@@ -445,9 +439,6 @@
}
ISOLATE_UNIT_TEST_CASE(Mint) {
-// On 64-bit architectures a Smi is stored in a 64 bit word. A Midint cannot
-// be allocated if it does fit into a Smi.
-#if !defined(ARCH_IS_64_BIT)
{
Mint& med = Mint::Handle();
EXPECT(med.IsNull());
@@ -517,7 +508,6 @@
EXPECT_EQ(mint1.value(), mint_value);
EXPECT_EQ(mint2.value(), mint_value);
EXPECT_EQ(mint1.raw(), mint2.raw());
-#endif
}
ISOLATE_UNIT_TEST_CASE(Double) {
@@ -2747,22 +2737,6 @@
EXPECT(Smi::Cast(result).Value() == kSmiTestValue);
}
-#if defined(ARCH_IS_64_BIT)
-// Test for Embedded Smi object in the instructions.
-ISOLATE_UNIT_TEST_CASE(EmbedSmiIn64BitCode) {
- extern void GenerateEmbedSmiInCode(Assembler * assembler, intptr_t value);
- const intptr_t kSmiTestValue = DART_INT64_C(5) << 32;
- Assembler _assembler_;
- GenerateEmbedSmiInCode(&_assembler_, kSmiTestValue);
- const Function& function =
- Function::Handle(CreateFunction("Test_EmbedSmiIn64BitCode"));
- const Code& code = Code::Handle(Code::FinalizeCode(function, &_assembler_));
- function.AttachCode(code);
- const Object& result =
- Object::Handle(DartEntry::InvokeFunction(function, Array::empty_array()));
- EXPECT(Smi::Cast(result).Value() == kSmiTestValue);
-}
-#endif // ARCH_IS_64_BIT
ISOLATE_UNIT_TEST_CASE(ExceptionHandlers) {
const int kNumEntries = 4;
diff --git a/runtime/vm/pages.h b/runtime/vm/pages.h
index e83f354..06fbf27 100644
--- a/runtime/vm/pages.h
+++ b/runtime/vm/pages.h
@@ -77,6 +77,10 @@
kPageMask);
}
+ static HeapPage* Of(uintptr_t addr) {
+ return reinterpret_cast<HeapPage*>(addr & kPageMask);
+ }
+
private:
void set_object_end(uword value) {
ASSERT((value & kObjectAlignmentMask) == kOldObjectAlignmentOffset);
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index cf7b0b4..5b3ba92 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -1045,6 +1045,10 @@
}
void Profiler::DumpStackTrace(void* context) {
+ if (context == NULL) {
+ DumpStackTrace();
+ return;
+ }
#if defined(HOST_OS_LINUX) || defined(HOST_OS_MACOS) || defined(HOST_OS_ANDROID)
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
mcontext_t mcontext = ucontext->uc_mcontext;
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index e78d53a..2f92257 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -49,6 +49,9 @@
}
}
+// Can't look at the class object because it can be called during
+// compaction when the class objects are moving. Can use the class
+// id in the header and the sizes in the Class Table.
intptr_t RawObject::SizeFromClass() const {
// Only reasonable to be called on heap objects.
ASSERT(IsHeapObject());
@@ -187,9 +190,7 @@
ptr()->tags_);
}
#endif // DEBUG
- RawClass* raw_class = isolate->GetClassForHeapWalkAt(class_id);
- instance_size = raw_class->ptr()->instance_size_in_words_
- << kWordSizeLog2;
+ instance_size = isolate->GetClassSizeForHeapWalkAt(class_id);
}
}
ASSERT(instance_size != 0);
@@ -555,9 +556,8 @@
uint32_t tags = raw_obj->ptr()->tags_;
intptr_t instance_size = SizeTag::decode(tags);
if (instance_size == 0) {
- RawClass* cls =
- visitor->isolate()->GetClassForHeapWalkAt(raw_obj->GetClassId());
- instance_size = cls->ptr()->instance_size_in_words_ << kWordSizeLog2;
+ instance_size =
+ visitor->isolate()->GetClassSizeForHeapWalkAt(raw_obj->GetClassId());
}
// Calculate the first and last raw object pointer fields.
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 5d52cbd..89875ca 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -499,6 +499,9 @@
void Validate(Isolate* isolate) const;
bool FindObject(FindObjectVisitor* visitor);
+ // This function may access the class-ID in the header, but it cannot access
+ // the actual class object, because the sliding compactor uses this function
+ // while the class objects are being moved.
intptr_t VisitPointers(ObjectPointerVisitor* visitor) {
// Fall back to virtual variant for predefined classes
intptr_t class_id = GetClassId();
@@ -731,6 +734,7 @@
friend class VerifyCanonicalVisitor;
friend class ObjectGraph::Stack; // GetClassId
friend class Precompiler; // GetClassId
+ friend class ObjectOffsetTrait; // GetClassId
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(RawObject);
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index bac281c..e8af8b8 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -70,6 +70,8 @@
kAsReference);
cls.StorePointer(&cls.raw_ptr()->dependent_code_, Array::null());
ASSERT(!cls.IsInFullSnapshot());
+ // Also sets instance size in class table.
+ reader->isolate()->class_table()->SetAt(cls.id(), cls.raw());
} else {
cls ^= reader->ReadClassId(object_id);
ASSERT((kind == Snapshot::kMessage) || cls.IsInFullSnapshot());
diff --git a/runtime/vm/regexp.cc b/runtime/vm/regexp.cc
index 4d99e0f..3d23411 100644
--- a/runtime/vm/regexp.cc
+++ b/runtime/vm/regexp.cc
@@ -3023,10 +3023,19 @@
Trace* current_trace,
PreloadState* state) {
if (state->eats_at_least_ == PreloadState::kEatsAtLeastNotYetInitialized) {
- // Save some time by looking at most one machine word ahead.
- state->eats_at_least_ =
- EatsAtLeast(compiler->one_byte() ? 4 : 2, kRecursionBudget,
- current_trace->at_start() == Trace::FALSE_VALUE);
+ // On ARM64, only read 16 bits ahead for now. This ensures that boxing is
+ // trivial even with the new smaller Smis. See
+ // https://github.com/dart-lang/sdk/issues/29951 and
+ // LoadCodeUnitsInstr::EmitNativeCode.
+#if defined(TARGET_ARCH_ARM64)
+ const int kMaxBytesLoaded = 2;
+#else
+ const int kMaxBytesLoaded = 4;
+#endif
+ const int kMaxTwoByteCharactersLoaded = kMaxBytesLoaded / 2;
+ state->eats_at_least_ = EatsAtLeast(
+ compiler->one_byte() ? kMaxBytesLoaded : kMaxTwoByteCharactersLoaded,
+ kRecursionBudget, current_trace->at_start() == Trace::FALSE_VALUE);
}
state->preload_characters_ =
CalculatePreloadCharacters(compiler, state->eats_at_least_);
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index 4838da1..fca1d73 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -171,15 +171,38 @@
}
DEFINE_RUNTIME_ENTRY(NullError, 0) {
- // TODO(dartbug.com/30480): Fill in arguments of NoSuchMethodError.
+ DartFrameIterator iterator(thread,
+ StackFrameIterator::kNoCrossThreadIteration);
+ const StackFrame* caller_frame = iterator.NextFrame();
+ ASSERT(caller_frame->IsDartFrame());
+ const Code& code = Code::Handle(zone, caller_frame->LookupDartCode());
+ const uword pc_offset = caller_frame->pc() - code.PayloadStart();
- const String& member_name = String::Handle(String::New("???"));
+ const CodeSourceMap& map =
+ CodeSourceMap::Handle(zone, code.code_source_map());
+ ASSERT(!map.IsNull());
- const Smi& invocation_type =
- Smi::Handle(Smi::New(InvocationMirror::EncodeType(
- InvocationMirror::kDynamic, InvocationMirror::kMethod)));
+ CodeSourceMapReader reader(map, Array::null_array(),
+ Function::null_function());
+ const intptr_t name_index = reader.GetNullCheckNameIndexAt(pc_offset);
+ RELEASE_ASSERT(name_index >= 0);
- const Array& args = Array::Handle(Array::New(6));
+ const ObjectPool& pool = ObjectPool::Handle(zone, code.object_pool());
+ const String& member_name =
+ String::CheckedHandle(zone, pool.ObjectAt(name_index));
+
+ InvocationMirror::Kind kind = InvocationMirror::kMethod;
+ if (Field::IsGetterName(member_name)) {
+ kind = InvocationMirror::kGetter;
+ } else if (Field::IsSetterName(member_name)) {
+ kind = InvocationMirror::kSetter;
+ }
+
+ const Smi& invocation_type = Smi::Handle(
+ zone,
+ Smi::New(InvocationMirror::EncodeType(InvocationMirror::kDynamic, kind)));
+
+ const Array& args = Array::Handle(zone, Array::New(6));
args.SetAt(0, /* instance */ Object::null_object());
args.SetAt(1, member_name);
args.SetAt(2, invocation_type);
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index 3db2d65..926b75e 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -3199,13 +3199,21 @@
set_vregisterd(vd, 1, 0);
} else if (instr->Bits(16, 5) == 24) {
// Format(instr, "fcvtzds'sf 'rd, 'vn");
+ const intptr_t max = instr->Bit(31) == 1 ? INT64_MAX : INT32_MAX;
+ const intptr_t min = instr->Bit(31) == 1 ? INT64_MIN : INT32_MIN;
const double vn_val = bit_cast<double, int64_t>(get_vregisterd(vn, 0));
- if (vn_val >= static_cast<double>(INT64_MAX)) {
- set_register(instr, rd, INT64_MAX, instr->RdMode());
- } else if (vn_val <= static_cast<double>(INT64_MIN)) {
- set_register(instr, rd, INT64_MIN, instr->RdMode());
+ int64_t result;
+ if (vn_val >= static_cast<double>(max)) {
+ result = max;
+ } else if (vn_val <= static_cast<double>(min)) {
+ result = min;
} else {
- set_register(instr, rd, static_cast<int64_t>(vn_val), instr->RdMode());
+ result = static_cast<int64_t>(vn_val);
+ }
+ if (instr->Bit(31) == 1) {
+ set_register(instr, rd, result, instr->RdMode());
+ } else {
+ set_register(instr, rd, result & 0xffffffffll, instr->RdMode());
}
} else {
UnimplementedInstruction(instr);
diff --git a/runtime/vm/simulator_dbc.cc b/runtime/vm/simulator_dbc.cc
index bd7be22..59edcb4 100644
--- a/runtime/vm/simulator_dbc.cc
+++ b/runtime/vm/simulator_dbc.cc
@@ -636,11 +636,11 @@
// __builtin_s{add,sub,mul}_overflow() intrinsics here and below.
// Note that they may clobber the output location even when there is overflow:
// https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html
-DART_FORCE_INLINE static bool SignedAddWithOverflow(intptr_t lhs,
- intptr_t rhs,
+DART_FORCE_INLINE static bool SignedAddWithOverflow(int32_t lhs,
+ int32_t rhs,
intptr_t* out) {
intptr_t res = 1;
-#if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64)
+#if defined(HOST_ARCH_IA32)
asm volatile(
"add %2, %1\n"
"jo 1f;\n"
@@ -650,7 +650,19 @@
: "+r"(res), "+r"(lhs)
: "r"(rhs), "r"(out)
: "cc");
-#elif defined(HOST_ARCH_ARM) || defined(HOST_ARCH_ARM64)
+#elif defined(HOST_ARCH_X64)
+ int64_t tmp;
+ asm volatile(
+ "addl %[rhs], %[lhs]\n"
+ "jo 1f;\n"
+ "xor %[res], %[res]\n"
+ "movslq %[lhs], %[tmp]\n"
+ "mov %[tmp], 0(%[out])\n"
+ "1: "
+ : [res] "+r"(res), [lhs] "+r"(lhs), [tmp] "=&r"(tmp)
+ : [rhs] "r"(rhs), [out] "r"(out)
+ : "cc");
+#elif defined(HOST_ARCH_ARM)
asm volatile(
"adds %1, %1, %2;\n"
"bvs 1f;\n"
@@ -660,32 +672,13 @@
: "+r"(res), "+r"(lhs)
: "r"(rhs), "r"(out)
: "cc");
-#else
-#error "Unsupported platform"
-#endif
- return (res != 0);
-}
-
-DART_FORCE_INLINE static bool SignedSubWithOverflow(intptr_t lhs,
- intptr_t rhs,
- intptr_t* out) {
- intptr_t res = 1;
-#if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64)
+#elif defined(HOST_ARCH_ARM64)
asm volatile(
- "sub %2, %1\n"
- "jo 1f;\n"
- "xor %0, %0\n"
- "mov %1, 0(%3)\n"
- "1: "
- : "+r"(res), "+r"(lhs)
- : "r"(rhs), "r"(out)
- : "cc");
-#elif defined(HOST_ARCH_ARM) || defined(HOST_ARCH_ARM64)
- asm volatile(
- "subs %1, %1, %2;\n"
+ "adds %w1, %w1, %w2;\n"
"bvs 1f;\n"
+ "sxtw %x1, %w1;\n"
"mov %0, #0;\n"
- "str %1, [%3, #0]\n"
+ "str %x1, [%3, #0]\n"
"1:"
: "+r"(res), "+r"(lhs)
: "r"(rhs), "r"(out)
@@ -696,11 +689,64 @@
return (res != 0);
}
-DART_FORCE_INLINE static bool SignedMulWithOverflow(intptr_t lhs,
- intptr_t rhs,
+DART_FORCE_INLINE static bool SignedSubWithOverflow(int32_t lhs,
+ int32_t rhs,
intptr_t* out) {
intptr_t res = 1;
-#if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64)
+#if defined(HOST_ARCH_IA32)
+ asm volatile(
+ "sub %2, %1\n"
+ "jo 1f;\n"
+ "xor %0, %0\n"
+ "mov %1, 0(%3)\n"
+ "1: "
+ : "+r"(res), "+r"(lhs)
+ : "r"(rhs), "r"(out)
+ : "cc");
+#elif defined(HOST_ARCH_X64)
+ int64_t tmp;
+ asm volatile(
+ "subl %[rhs], %[lhs]\n"
+ "jo 1f;\n"
+ "xor %[res], %[res]\n"
+ "movslq %[lhs], %[tmp]\n"
+ "mov %[tmp], 0(%[out])\n"
+ "1: "
+ : [res] "+r"(res), [lhs] "+r"(lhs), [tmp] "=&r"(tmp)
+ : [rhs] "r"(rhs), [out] "r"(out)
+ : "cc");
+#elif defined(HOST_ARCH_ARM)
+ asm volatile(
+ "subs %1, %1, %2;\n"
+ "bvs 1f;\n"
+ "mov %0, #0;\n"
+ "str %1, [%3, #0]\n"
+ "1:"
+ : "+r"(res), "+r"(lhs)
+ : "r"(rhs), "r"(out)
+ : "cc");
+#elif defined(HOST_ARCH_ARM64)
+ asm volatile(
+ "subs %w1, %w1, %w2;\n"
+ "bvs 1f;\n"
+ "sxtw %x1, %w1;\n"
+ "mov %0, #0;\n"
+ "str %x1, [%3, #0]\n"
+ "1:"
+ : "+r"(res), "+r"(lhs)
+ : "r"(rhs), "r"(out)
+ : "cc");
+#else
+#error "Unsupported platform"
+#endif
+ return (res != 0);
+}
+
+DART_FORCE_INLINE static bool SignedMulWithOverflow(int32_t lhs,
+ int32_t rhs,
+ intptr_t* out) {
+ intptr_t res = 1;
+#if defined(HOST_ARCH_IA32)
asm volatile(
"imul %2, %1\n"
"jo 1f;\n"
@@ -710,6 +756,18 @@
: "+r"(res), "+r"(lhs)
: "r"(rhs), "r"(out)
: "cc");
+#elif defined(HOST_ARCH_X64)
+ int64_t tmp;
+ asm volatile(
+ "imull %[rhs], %[lhs]\n"
+ "jo 1f;\n"
+ "xor %[res], %[res]\n"
+ "movslq %[lhs], %[tmp]\n"
+ "mov %[tmp], 0(%[out])\n"
+ "1: "
+ : [res] "+r"(res), [lhs] "+r"(lhs), [tmp] "=&r"(tmp)
+ : [rhs] "r"(rhs), [out] "r"(out)
+ : "cc");
#elif defined(HOST_ARCH_ARM)
asm volatile(
"smull %1, ip, %1, %2;\n"
@@ -724,12 +782,12 @@
#elif defined(HOST_ARCH_ARM64)
int64_t prod_lo = 0;
asm volatile(
- "mul %1, %2, %3\n"
- "smulh %2, %2, %3\n"
- "cmp %2, %1, ASR #63;\n"
+ "smull %x1, %w2, %w3\n"
+ "asr %x2, %x1, #63\n"
+ "cmp %x2, %x1, ASR #31;\n"
"bne 1f;\n"
"mov %0, #0;\n"
- "str %1, [%4, #0]\n"
+ "str %x1, [%4, #0]\n"
"1:"
: "=r"(res), "+r"(prod_lo), "+r"(lhs)
: "r"(rhs), "r"(out)
@@ -1971,11 +2029,7 @@
if (rhs != 0) {
const intptr_t lhs = reinterpret_cast<intptr_t>(FP[rB]);
const intptr_t res = (lhs >> kSmiTagSize) / (rhs >> kSmiTagSize);
-#if defined(ARCH_IS_64_BIT)
- const intptr_t untaggable = 0x4000000000000000LL;
-#else
const intptr_t untaggable = 0x40000000L;
-#endif // defined(ARCH_IS_64_BIT)
if (res != untaggable) {
*reinterpret_cast<intptr_t*>(&FP[rA]) = res << kSmiTagSize;
pc++;
@@ -2001,11 +2055,12 @@
{
BYTECODE(Shl, A_B_C);
const intptr_t rhs = reinterpret_cast<intptr_t>(FP[rC]) >> kSmiTagSize;
- if (static_cast<uintptr_t>(rhs) < kBitsPerWord) {
- const intptr_t lhs = reinterpret_cast<intptr_t>(FP[rB]);
- const intptr_t res = lhs << rhs;
+ const int kBitsPerInt32 = 32;
+ if (static_cast<uintptr_t>(rhs) < kBitsPerInt32) {
+ const int32_t lhs = reinterpret_cast<intptr_t>(FP[rB]);
+ const int32_t res = lhs << rhs;
if (lhs == (res >> rhs)) {
- *reinterpret_cast<intptr_t*>(&FP[rA]) = res;
+ *reinterpret_cast<intptr_t*>(&FP[rA]) = static_cast<intptr_t>(res);
pc++;
}
}
@@ -2016,8 +2071,7 @@
BYTECODE(Shr, A_B_C);
const intptr_t rhs = reinterpret_cast<intptr_t>(FP[rC]) >> kSmiTagSize;
if (rhs >= 0) {
- const intptr_t shift_amount =
- (rhs >= kBitsPerWord) ? (kBitsPerWord - 1) : rhs;
+ const intptr_t shift_amount = (rhs >= 32) ? (32 - 1) : rhs;
const intptr_t lhs = reinterpret_cast<intptr_t>(FP[rB]) >> kSmiTagSize;
*reinterpret_cast<intptr_t*>(&FP[rA]) = (lhs >> shift_amount)
<< kSmiTagSize;
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 6dd74d4..60a944f 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -202,6 +202,14 @@
const uint8_t* Addr() const { return reinterpret_cast<const uint8_t*>(this); }
+ const uint8_t* DataImage() const {
+ if (!IncludesCode(kind())) {
+ return NULL;
+ }
+ uword offset = Utils::RoundUp(length(), OS::kMaxPreferredCodeAlignment);
+ return Addr() + offset;
+ }
+
private:
// Prevent Snapshot from ever being allocated directly.
Snapshot();
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index cff0584..22067a5 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -253,10 +253,6 @@
// here covers most of the 64-bit range. On 32-bit platforms the smi
// range covers most of the 32-bit range and values outside that
// range are also represented as mints.
-#if defined(ARCH_IS_64_BIT)
- EXPECT_EQ(Dart_CObject_kInt64, mint_cobject->type);
- EXPECT_EQ(value, mint_cobject->value.as_int64);
-#else
if (kMinInt32 < value && value < kMaxInt32) {
EXPECT_EQ(Dart_CObject_kInt32, mint_cobject->type);
EXPECT_EQ(value, mint_cobject->value.as_int32);
@@ -264,7 +260,6 @@
EXPECT_EQ(Dart_CObject_kInt64, mint_cobject->type);
EXPECT_EQ(value, mint_cobject->value.as_int64);
}
-#endif
}
TEST_CASE(SerializeMints) {
@@ -1775,8 +1770,9 @@
{
// Use a script snapshot where a full snapshot is expected.
char* error = NULL;
- Dart_Isolate isolate = Dart_CreateIsolate(
- "script-uri", "main", script_snapshot, NULL, NULL, NULL, &error);
+ Dart_Isolate isolate =
+ Dart_CreateIsolate("script-uri", "main", script_snapshot, NULL, NULL,
+ NULL, NULL, NULL, &error);
EXPECT(isolate == NULL);
EXPECT(error != NULL);
EXPECT_SUBSTRING(
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index f0354a8..401a611 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -1334,14 +1334,18 @@
__ ldr(R1, Address(SP, +1 * kWordSize)); // Left.
__ orr(TMP, R0, Operand(R1));
__ BranchIfNotSmi(TMP, not_smi_or_overflow);
+ __ AssertSmiInRange(R0);
+ __ AssertSmiInRange(R1);
switch (kind) {
case Token::kADD: {
- __ adds(R0, R1, Operand(R0)); // Adds.
+ __ addsw(R0, R1, Operand(R0)); // Adds.
+ __ sxtw(R0, R0);
__ b(not_smi_or_overflow, VS); // Branch if overflow.
break;
}
case Token::kSUB: {
- __ subs(R0, R1, Operand(R0)); // Subtract.
+ __ subsw(R0, R1, Operand(R0)); // Subtract.
+ __ sxtw(R0, R0);
__ b(not_smi_or_overflow, VS); // Branch if overflow.
break;
}
@@ -1383,6 +1387,8 @@
__ StoreToOffset(R1, R6, count_offset);
}
+ __ AssertSmiInRange(R0, Assembler::kValueCanBeHeapPointer);
+
__ ret();
}
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index fc8e781..b21d9db 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -1274,13 +1274,15 @@
__ j(NOT_ZERO, not_smi_or_overflow);
switch (kind) {
case Token::kADD: {
- __ addq(RAX, RCX);
+ __ addl(RAX, RCX);
__ j(OVERFLOW, not_smi_or_overflow);
+ __ movsxd(RAX, RAX);
break;
}
case Token::kSUB: {
- __ subq(RAX, RCX);
+ __ subl(RAX, RCX);
__ j(OVERFLOW, not_smi_or_overflow);
+ __ movsxd(RAX, RAX);
break;
}
case Token::kEQ: {
diff --git a/runtime/vm/token_position.h b/runtime/vm/token_position.h
index c28f9a4..eadb562 100644
--- a/runtime/vm/token_position.h
+++ b/runtime/vm/token_position.h
@@ -18,7 +18,7 @@
// ClassifyingTokenPositions N -> -1 - N
//
// Synthetically created AstNodes are given real source positions but encoded
-// as negative numbers from [kSmiMin32, -1 - N]. For example:
+// as negative numbers from [kSmiMin, -1 - N]. For example:
//
// A source position of 0 in a synthetic AstNode would be encoded as -2 - N.
// A source position of 1 in a synthetic AstNode would be encoded as -3 - N.
@@ -86,7 +86,7 @@
#undef DECLARE_VALUES
static const intptr_t kMinSourcePos = 0;
static const TokenPosition kMinSource;
- static const intptr_t kMaxSourcePos = kSmiMax32 - kMaxSentinelDescriptors - 2;
+ static const intptr_t kMaxSourcePos = kSmiMax - kMaxSentinelDescriptors - 2;
static const TokenPosition kMaxSource;
// Decode from a snapshot.
diff --git a/runtime/vm/type_testing_stubs.cc b/runtime/vm/type_testing_stubs.cc
index 82f55a7..70c1e2c 100644
--- a/runtime/vm/type_testing_stubs.cc
+++ b/runtime/vm/type_testing_stubs.cc
@@ -184,7 +184,7 @@
// TODO(kustermann): Use sorting/hashtables to speed this up.
RawInstructions* TypeTestingStubFinder::LookupByAddresss(
uword entry_point) const {
- // First test the 2 common ones:
+ // First test the 4 common ones:
code_ = StubCode::DefaultTypeTest_entry()->code();
if (entry_point == code_.UncheckedEntryPoint()) {
return code_.instructions();
@@ -208,11 +208,19 @@
const char* TypeTestingStubFinder::StubNameFromAddresss(
uword entry_point) const {
- // First test the 2 common ones:
+ // First test the 4 common ones:
code_ = StubCode::DefaultTypeTest_entry()->code();
if (entry_point == code_.UncheckedEntryPoint()) {
return "TypeTestingStub_Default";
}
+ code_ = StubCode::TopTypeTypeTest_entry()->code();
+ if (entry_point == code_.UncheckedEntryPoint()) {
+ return "TypeTestingStub_Top";
+ }
+ code_ = StubCode::TypeRefTypeTest_entry()->code();
+ if (entry_point == code_.UncheckedEntryPoint()) {
+ return "TypeTestingStub_Ref";
+ }
code_ = StubCode::UnreachableTypeTest_entry()->code();
if (entry_point == code_.UncheckedEntryPoint()) {
return "TypeTestingStub_Unreachable";
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index b107412..92e1838 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -94,8 +94,8 @@
api_flags.use_dart_frontend = FLAG_use_dart_frontend;
Dart_Isolate isolate = NULL;
if (len == 0) {
- isolate = Dart_CreateIsolate(name, NULL, data_buffer, instr_buffer,
- &api_flags, data, &err);
+ isolate = Dart_CreateIsolate(name, NULL, data_buffer, instr_buffer, NULL,
+ NULL, &api_flags, data, &err);
} else {
kernel::Program* program = reinterpret_cast<kernel::Program*>(
Dart_ReadKernelBinary(data_buffer, len, NoopRelease));
@@ -594,11 +594,6 @@
Dart_Handle TestCase::LoadCoreTestScript(const char* script,
Dart_NativeEntryResolver resolver) {
- if (FLAG_use_dart_frontend) {
- // Sets a flag in the CFE to not throw an error if `dart:_internal` is
- // imported from a non-internal library.
- KernelIsolate::AllowDartInternalImport();
- }
return LoadTestScript(script, resolver, CORELIB_TEST_URI);
}
diff --git a/runtime/vm/virtual_memory_win.cc b/runtime/vm/virtual_memory_win.cc
index 15329e6..b31a2fe 100644
--- a/runtime/vm/virtual_memory_win.cc
+++ b/runtime/vm/virtual_memory_win.cc
@@ -62,20 +62,24 @@
}
VirtualMemory::~VirtualMemory() {
- if (!vm_owns_region() || (reserved_.size() == 0)) {
+ // Note that the size of the reserved region might be set to 0 by
+ // Truncate(0, true) but that does not actually release the mapping
+ // itself. The only way to release the mapping is to invoke VirtualFree
+ // with original base pointer and MEM_RELEASE.
+ if (!vm_owns_region()) {
return;
}
if (VirtualFree(reserved_.pointer(), 0, MEM_RELEASE) == 0) {
- FATAL("VirtualFree failed");
+ FATAL1("VirtualFree failed: Error code %d\n", GetLastError());
}
}
bool VirtualMemory::FreeSubSegment(void* address,
intptr_t size) {
- // On Windows only the entire segment returned by VirtualAlloc
- // can be freed. Therefore we will have to waste these unused
- // virtual memory sub-segments.
- return false;
+ if (VirtualFree(address, size, MEM_DECOMMIT) == 0) {
+ FATAL1("VirtualFree failed: Error code %d\n", GetLastError());
+ }
+ return true;
}
void VirtualMemory::Protect(void* address, intptr_t size, Protection mode) {
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index 4d58c04..766a114 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -270,21 +270,6 @@
ignore_patterns = "{}"
} ]
-# This rule copies pub assets to lib/_internal/pub/asset
-copy_tree_specs += [ {
- target = "copy_pub_assets"
- visibility = [
- ":create_common_sdk",
- ":copy_7zip",
- ]
- deps = [
- ":copy_libraries",
- ]
- source = "../third_party/pkg/pub/lib/src/asset"
- dest = "$root_out_dir/dart-sdk/lib/_internal/pub/asset"
- ignore_patterns = "{}"
- } ]
-
# This loop generates rules to copy libraries to lib/
foreach(library, _full_sdk_libraries) {
copy_tree_specs += [ {
@@ -305,7 +290,6 @@
visibility = [ ":create_common_sdk" ]
deps = [
":copy_libraries",
- ":copy_pub_assets",
]
source = "../third_party/7zip"
dest = "$root_out_dir/dart-sdk/lib/_internal/pub/asset/7zip"
@@ -959,7 +943,6 @@
":copy_license",
":copy_libraries_specification",
":copy_platform_files",
- ":copy_pub_assets",
":copy_readme",
":copy_vm_dill_files",
":write_revision_file",
diff --git a/sdk/lib/_internal/js_runtime/lib/js_array.dart b/sdk/lib/_internal/js_runtime/lib/js_array.dart
index 79d4c94..04e8f49 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_array.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_array.dart
@@ -523,7 +523,13 @@
void sort([int compare(E a, E b)]) {
checkMutable('sort');
- Sort.sort(this, compare == null ? Comparable.compare : compare);
+ Sort.sort(this, compare ?? _compareAny);
+ }
+
+ static int _compareAny(a, b) {
+ // In strong mode Comparable.compare requires an implicit cast to ensure
+ // `a` and `b` are Comparable.
+ return Comparable.compare(a, b);
}
void shuffle([Random random]) {
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index b2b328e..e0024cf 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -17,6 +17,7 @@
Language/Expressions/Function_Invocation/async_cleanup_t08: Skip # https://github.com/dart-lang/sdk/issues/28873
Language/Expressions/Function_Invocation/async_generator_invokation_t08: Skip # Issue 25967
Language/Expressions/Function_Invocation/async_generator_invokation_t10: Skip # Issue 25967
+Language/Expressions/Function_Invocation/async_invokation_t02: RuntimeError # sync-async is on by default.
Language/Expressions/Function_Invocation/async_invokation_t04: RuntimeError, Pass # co19 issue 57
Language/Expressions/Instance_Creation/New/evaluation_t19: RuntimeError # Please triage this failure
Language/Expressions/Instance_Creation/New/evaluation_t20: RuntimeError # Please triage this failure
@@ -1366,12 +1367,15 @@
WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/ownerdocument-001_t01: RuntimeError # Please triage this failure
[ $compiler == dart2js && $runtime == chrome && $csp && $minified ]
+LayoutTests/fast/css/fontface-properties_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/inherited-properties-rare-text_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/HTMLScriptElement/isURLAttribute_t01: SkipByDesign # Uses script injection
LayoutTests/fast/dom/HTMLScriptElement/remove-source_t01: Pass # Please triage this failure
LayoutTests/fast/dom/HTMLScriptElement/script-for-attribute-unexpected-execution_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/HTMLScriptElement/script-reexecution_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/HTMLTemplateElement/inertContents_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/Range/create-contextual-fragment-script-unmark-already-started_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/shadow/elementfrompoint_t01: RuntimeError # Please triage this failure
LayoutTests/fast/files/workers/inline-worker-via-blob-url_t01: SkipByDesign # inlined script
LayoutTests/fast/loader/scroll-position-restored-on-back_t01: Skip # Timeout. Please triage this failure
WebPlatformTest/webstorage/event_local_key_t01: Skip # Timeout. Please triage this failure.
@@ -1493,7 +1497,7 @@
LibTest/async/DeferredLibrary/DeferredLibrary_A01_t01: RuntimeError
[ $compiler == dart2js && $runtime == d8 && $fast_startup ]
-LibTest/isolate/Isolate/spawn_A04_t04: Fail # Issue 27558
+LibTest/isolate/Isolate/spawn_A04_t04: Pass # Technically fails, but since sync-async was turned on, this test completes before it fails. Underlying issue: #27558
[ $compiler == dart2js && $runtime == d8 && $fasta ]
LayoutTests/*: SkipByDesign
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 2dd3260..76eadd0 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -188,9 +188,6 @@
LibTest/collection/ListMixin/ListMixin_class_A01_t02: Skip # co19 issue 673, These tests take too much memory (300 MB) for our 1 GB test machine co19 issue 673. http://code.google.com/p/co19/issues/detail?id=673
LibTest/core/List/List_class_A01_t02: Skip # co19 issue 673, These tests take too much memory (300 MB) for our 1 GB test machine co19 issue 673. http://code.google.com/p/co19/issues/detail?id=673
-[ $arch != arm64 && $arch != simarm64 && $arch != simdbc && $arch != simdbc64 && $arch != x64 && ($runtime == dart_precompiled || $runtime == vm) ]
-LibTest/core/int/operator_left_shift_A01_t02: Fail # co19 issue 129
-
[ $arch == ia32 && $mode == release && $runtime == vm && $system == linux ]
service/dev_fs_spawn_test: Pass, Fail # Issue 28411
@@ -382,6 +379,9 @@
LibTest/typed_data/Uint64List/Uint64List.view_A01_t02: CompileTimeError # Large integer literal
WebPlatformTest/*: SkipByDesign # dart:html not supported on VM.
+[ $runtime == dart_precompiled || $runtime == vm ]
+LibTest/core/int/operator_left_shift_A01_t02: Fail # Can't represent 1 << 2147483647 without running out of memory.
+
[ $runtime == flutter || $hot_reload || $hot_reload_rollback ]
Language/Expressions/Assignment/prefix_object_t02: Skip # Requires deferred libraries
Language/Expressions/Constants/constant_constructor_t03: Skip # Requires deferred libraries
diff --git a/tests/compiler/dart2js/end_to_end/data/dart2js_batch2_run.dart b/tests/compiler/dart2js/end_to_end/data/dart2js_batch2_run.dart
index b6de254..e63be3b 100644
--- a/tests/compiler/dart2js/end_to_end/data/dart2js_batch2_run.dart
+++ b/tests/compiler/dart2js/end_to_end/data/dart2js_batch2_run.dart
@@ -2,7 +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.
-// ignore: INVALID_ANNOTATION
+// ignore: UNDEFINED_ANNOTATION
@notExisting
var x;
diff --git a/tests/compiler/dart2js/equivalence/equivalence_helper.dart b/tests/compiler/dart2js/equivalence/equivalence_helper.dart
index 75d497d..45437a9 100644
--- a/tests/compiler/dart2js/equivalence/equivalence_helper.dart
+++ b/tests/compiler/dart2js/equivalence/equivalence_helper.dart
@@ -951,6 +951,15 @@
strategy.testConstants(
exp1, exp2, 'message', exp1.message, exp2.message);
}
+
+ @override
+ bool visitInstantiation(InstantiationConstantExpression exp1,
+ covariant InstantiationConstantExpression exp2) {
+ return strategy.testTypeLists(exp1, exp2, 'typeArguments',
+ exp1.typeArguments, exp2.typeArguments) &&
+ strategy.testConstants(
+ exp1, exp2, 'expression', exp1.expression, exp2.expression);
+ }
}
/// Visitor that checks for structural equivalence of [ConstantValue]s.
@@ -1086,6 +1095,15 @@
covariant InterceptorConstantValue value2) {
return strategy.testElements(value1, value2, 'cls', value1.cls, value2.cls);
}
+
+ @override
+ bool visitInstantiation(InstantiationConstantValue value1,
+ covariant InstantiationConstantValue value2) {
+ return strategy.testTypeLists(value1, value2, 'typeArguments',
+ value1.typeArguments, value2.typeArguments) &&
+ strategy.testConstantValues(
+ value1, value2, 'function', value1.function, value2.function);
+ }
}
/// Tests the equivalence of [impact1] and [impact2] using [strategy].
diff --git a/tests/compiler/dart2js/model/constant_expression_evaluate_test.dart b/tests/compiler/dart2js/model/constant_expression_evaluate_test.dart
index 532dd9e..8fa15e2 100644
--- a/tests/compiler/dart2js/model/constant_expression_evaluate_test.dart
+++ b/tests/compiler/dart2js/model/constant_expression_evaluate_test.dart
@@ -34,7 +34,10 @@
/// Tested constants.
final List<ConstantData> constants;
- const TestData(this.name, this.declarations, this.constants);
+ final bool strongModeOnly;
+
+ const TestData(this.name, this.declarations, this.constants,
+ {this.strongModeOnly: false});
}
class ConstantData {
@@ -46,12 +49,17 @@
/// a [ConstantResult].
final expectedResults;
+ /// Expected results for Dart 2 if different from [expectedResults].
+ final strongModeResults;
+
/// A [MessageKind] or a list of [MessageKind]s containing the error messages
/// expected as the result of evaluating the constant under the empty
/// environment.
final expectedErrors;
- const ConstantData(this.code, this.expectedResults, [this.expectedErrors]);
+ const ConstantData(this.code, this.expectedResults,
+ {this.expectedErrors, strongModeResults})
+ : this.strongModeResults = strongModeResults ?? expectedResults;
}
class EvaluationError {
@@ -77,6 +85,10 @@
}
@override
+ DartType getTypeInContext(DartType type) =>
+ _environment.getTypeInContext(type);
+
+ @override
ConstantConstructor getConstructorConstant(ConstructorEntity constructor) {
return _environment.getConstructorConstant(constructor);
}
@@ -152,21 +164,25 @@
const ConstantData('Object', 'TypeConstant(Object)'),
const ConstantData('null ?? 0', 'IntConstant(0)'),
const ConstantData(
- 'const [0, 1]', 'ListConstant([IntConstant(0), IntConstant(1)])'),
+ 'const [0, 1]', 'ListConstant([IntConstant(0), IntConstant(1)])',
+ strongModeResults:
+ 'ListConstant(<int>[IntConstant(0), IntConstant(1)])'),
const ConstantData('const <int>[0, 1]',
'ListConstant(<int>[IntConstant(0), IntConstant(1)])'),
const ConstantData(
'const {0: 1, 2: 3}',
'MapConstant({IntConstant(0): IntConstant(1), '
- 'IntConstant(2): IntConstant(3)})'),
+ 'IntConstant(2): IntConstant(3)})',
+ strongModeResults:
+ 'MapConstant(<int, int>{IntConstant(0): IntConstant(1), '
+ 'IntConstant(2): IntConstant(3)})'),
const ConstantData(
'const <int, int>{0: 1, 2: 3}',
'MapConstant(<int, int>{IntConstant(0): IntConstant(1), '
'IntConstant(2): IntConstant(3)})'),
- const ConstantData(
- 'const <int, int>{0: 1, 0: 2}',
+ const ConstantData('const <int, int>{0: 1, 0: 2}',
'MapConstant(<int, int>{IntConstant(0): IntConstant(2)})',
- MessageKind.EQUAL_MAP_ENTRY_KEY),
+ expectedErrors: MessageKind.EQUAL_MAP_ENTRY_KEY),
const ConstantData(
'const bool.fromEnvironment("foo", defaultValue: false)', const {
const {}: 'BoolConstant(false)',
@@ -355,133 +371,137 @@
const ConstantData(
r'"$integer $string $boolean"', 'StringConstant("5 baz false")'),
const ConstantData('0 ? true : false', 'NonConstant',
- MessageKind.INVALID_CONSTANT_CONDITIONAL_TYPE),
+ expectedErrors: MessageKind.INVALID_CONSTANT_CONDITIONAL_TYPE),
const ConstantData('integer ? true : false', 'NonConstant',
- MessageKind.INVALID_CONSTANT_CONDITIONAL_TYPE),
+ expectedErrors: MessageKind.INVALID_CONSTANT_CONDITIONAL_TYPE),
const ConstantData(r'"${const []}"', 'NonConstant',
- MessageKind.INVALID_CONSTANT_INTERPOLATION_TYPE),
+ expectedErrors: MessageKind.INVALID_CONSTANT_INTERPOLATION_TYPE),
const ConstantData(r'"${proxy}"', 'NonConstant',
- MessageKind.INVALID_CONSTANT_INTERPOLATION_TYPE),
- const ConstantData(r'"${proxy}${const []}"', 'NonConstant', const [
- MessageKind.INVALID_CONSTANT_INTERPOLATION_TYPE,
- MessageKind.INVALID_CONSTANT_INTERPOLATION_TYPE
- ]),
- const ConstantData(r'"${"${proxy}"}${const []}"', 'NonConstant', const [
- MessageKind.INVALID_CONSTANT_INTERPOLATION_TYPE,
- MessageKind.INVALID_CONSTANT_INTERPOLATION_TYPE
- ]),
- const ConstantData(
- '0 + ""', 'NonConstant', MessageKind.INVALID_CONSTANT_NUM_ADD_TYPE),
- const ConstantData(
- '0 + string', 'NonConstant', MessageKind.INVALID_CONSTANT_NUM_ADD_TYPE),
- const ConstantData(
- '"" + 0', 'NonConstant', MessageKind.INVALID_CONSTANT_STRING_ADD_TYPE),
+ expectedErrors: MessageKind.INVALID_CONSTANT_INTERPOLATION_TYPE),
+ const ConstantData(r'"${proxy}${const []}"', 'NonConstant',
+ expectedErrors: const [
+ MessageKind.INVALID_CONSTANT_INTERPOLATION_TYPE,
+ MessageKind.INVALID_CONSTANT_INTERPOLATION_TYPE
+ ]),
+ const ConstantData(r'"${"${proxy}"}${const []}"', 'NonConstant',
+ expectedErrors: const [
+ MessageKind.INVALID_CONSTANT_INTERPOLATION_TYPE,
+ MessageKind.INVALID_CONSTANT_INTERPOLATION_TYPE
+ ]),
+ const ConstantData('0 + ""', 'NonConstant',
+ expectedErrors: MessageKind.INVALID_CONSTANT_NUM_ADD_TYPE),
+ const ConstantData('0 + string', 'NonConstant',
+ expectedErrors: MessageKind.INVALID_CONSTANT_NUM_ADD_TYPE),
+ const ConstantData('"" + 0', 'NonConstant',
+ expectedErrors: MessageKind.INVALID_CONSTANT_STRING_ADD_TYPE),
const ConstantData('string + 0', 'NonConstant',
- MessageKind.INVALID_CONSTANT_STRING_ADD_TYPE),
+ expectedErrors: MessageKind.INVALID_CONSTANT_STRING_ADD_TYPE),
const ConstantData('true + ""', 'NonConstant',
- MessageKind.INVALID_CONSTANT_STRING_ADD_TYPE),
+ expectedErrors: MessageKind.INVALID_CONSTANT_STRING_ADD_TYPE),
const ConstantData('boolean + string', 'NonConstant',
- MessageKind.INVALID_CONSTANT_STRING_ADD_TYPE),
- const ConstantData(
- 'true + false', 'NonConstant', MessageKind.INVALID_CONSTANT_ADD_TYPES),
+ expectedErrors: MessageKind.INVALID_CONSTANT_STRING_ADD_TYPE),
+ const ConstantData('true + false', 'NonConstant',
+ expectedErrors: MessageKind.INVALID_CONSTANT_ADD_TYPES),
const ConstantData('boolean + false', 'NonConstant',
- MessageKind.INVALID_CONSTANT_ADD_TYPES),
+ expectedErrors: MessageKind.INVALID_CONSTANT_ADD_TYPES),
const ConstantData('const [] == null', 'NonConstant',
- MessageKind.INVALID_CONSTANT_BINARY_PRIMITIVE_TYPE),
+ expectedErrors: MessageKind.INVALID_CONSTANT_BINARY_PRIMITIVE_TYPE),
const ConstantData('proxy == null', 'NonConstant',
- MessageKind.INVALID_CONSTANT_BINARY_PRIMITIVE_TYPE),
- const ConstantData(
- '0 * ""', 'NonConstant', MessageKind.INVALID_CONSTANT_BINARY_NUM_TYPE),
+ expectedErrors: MessageKind.INVALID_CONSTANT_BINARY_PRIMITIVE_TYPE),
+ const ConstantData('0 * ""', 'NonConstant',
+ expectedErrors: MessageKind.INVALID_CONSTANT_BINARY_NUM_TYPE),
const ConstantData('0 * string', 'NonConstant',
- MessageKind.INVALID_CONSTANT_BINARY_NUM_TYPE),
- const ConstantData(
- '0 % ""', 'NonConstant', MessageKind.INVALID_CONSTANT_BINARY_NUM_TYPE),
+ expectedErrors: MessageKind.INVALID_CONSTANT_BINARY_NUM_TYPE),
+ const ConstantData('0 % ""', 'NonConstant',
+ expectedErrors: MessageKind.INVALID_CONSTANT_BINARY_NUM_TYPE),
const ConstantData('0 % string', 'NonConstant',
- MessageKind.INVALID_CONSTANT_BINARY_NUM_TYPE),
- const ConstantData(
- '0 << ""', 'NonConstant', MessageKind.INVALID_CONSTANT_BINARY_INT_TYPE),
+ expectedErrors: MessageKind.INVALID_CONSTANT_BINARY_NUM_TYPE),
+ const ConstantData('0 << ""', 'NonConstant',
+ expectedErrors: MessageKind.INVALID_CONSTANT_BINARY_INT_TYPE),
const ConstantData('0 << string', 'NonConstant',
- MessageKind.INVALID_CONSTANT_BINARY_INT_TYPE),
- const ConstantData(
- 'null[0]', 'NonConstant', MessageKind.INVALID_CONSTANT_INDEX),
+ expectedErrors: MessageKind.INVALID_CONSTANT_BINARY_INT_TYPE),
+ const ConstantData('null[0]', 'NonConstant',
+ expectedErrors: MessageKind.INVALID_CONSTANT_INDEX),
const ConstantData('const bool.fromEnvironment(0)', 'NonConstant',
- MessageKind.INVALID_FROM_ENVIRONMENT_NAME_TYPE),
+ expectedErrors: MessageKind.INVALID_FROM_ENVIRONMENT_NAME_TYPE),
const ConstantData('const bool.fromEnvironment(integer)', 'NonConstant',
- MessageKind.INVALID_FROM_ENVIRONMENT_NAME_TYPE),
+ expectedErrors: MessageKind.INVALID_FROM_ENVIRONMENT_NAME_TYPE),
const ConstantData(
- 'const bool.fromEnvironment("baz", defaultValue: 0)',
- 'NonConstant',
- MessageKind.INVALID_BOOL_FROM_ENVIRONMENT_DEFAULT_VALUE_TYPE),
+ 'const bool.fromEnvironment("baz", defaultValue: 0)', 'NonConstant',
+ expectedErrors:
+ MessageKind.INVALID_BOOL_FROM_ENVIRONMENT_DEFAULT_VALUE_TYPE),
const ConstantData(
'const bool.fromEnvironment("baz", defaultValue: integer)',
'NonConstant',
- MessageKind.INVALID_BOOL_FROM_ENVIRONMENT_DEFAULT_VALUE_TYPE),
+ expectedErrors:
+ MessageKind.INVALID_BOOL_FROM_ENVIRONMENT_DEFAULT_VALUE_TYPE),
const ConstantData('const int.fromEnvironment(0)', 'NonConstant',
- MessageKind.INVALID_FROM_ENVIRONMENT_NAME_TYPE),
+ expectedErrors: MessageKind.INVALID_FROM_ENVIRONMENT_NAME_TYPE),
const ConstantData('const int.fromEnvironment(integer)', 'NonConstant',
- MessageKind.INVALID_FROM_ENVIRONMENT_NAME_TYPE),
+ expectedErrors: MessageKind.INVALID_FROM_ENVIRONMENT_NAME_TYPE),
const ConstantData(
- 'const int.fromEnvironment("baz", defaultValue: "")',
- 'NonConstant',
- MessageKind.INVALID_INT_FROM_ENVIRONMENT_DEFAULT_VALUE_TYPE),
+ 'const int.fromEnvironment("baz", defaultValue: "")', 'NonConstant',
+ expectedErrors:
+ MessageKind.INVALID_INT_FROM_ENVIRONMENT_DEFAULT_VALUE_TYPE),
const ConstantData(
- 'const int.fromEnvironment("baz", defaultValue: string)',
- 'NonConstant',
- MessageKind.INVALID_INT_FROM_ENVIRONMENT_DEFAULT_VALUE_TYPE),
+ 'const int.fromEnvironment("baz", defaultValue: string)', 'NonConstant',
+ expectedErrors:
+ MessageKind.INVALID_INT_FROM_ENVIRONMENT_DEFAULT_VALUE_TYPE),
const ConstantData('const String.fromEnvironment(0)', 'NonConstant',
- MessageKind.INVALID_FROM_ENVIRONMENT_NAME_TYPE),
+ expectedErrors: MessageKind.INVALID_FROM_ENVIRONMENT_NAME_TYPE),
const ConstantData('const String.fromEnvironment(integer)', 'NonConstant',
- MessageKind.INVALID_FROM_ENVIRONMENT_NAME_TYPE),
+ expectedErrors: MessageKind.INVALID_FROM_ENVIRONMENT_NAME_TYPE),
const ConstantData(
- 'const String.fromEnvironment("baz", defaultValue: 0)',
- 'NonConstant',
- MessageKind.INVALID_STRING_FROM_ENVIRONMENT_DEFAULT_VALUE_TYPE),
+ 'const String.fromEnvironment("baz", defaultValue: 0)', 'NonConstant',
+ expectedErrors:
+ MessageKind.INVALID_STRING_FROM_ENVIRONMENT_DEFAULT_VALUE_TYPE),
const ConstantData(
'const String.fromEnvironment("baz", defaultValue: integer)',
'NonConstant',
- MessageKind.INVALID_STRING_FROM_ENVIRONMENT_DEFAULT_VALUE_TYPE),
+ expectedErrors:
+ MessageKind.INVALID_STRING_FROM_ENVIRONMENT_DEFAULT_VALUE_TYPE),
const ConstantData('true || 0', 'NonConstant',
- MessageKind.INVALID_LOGICAL_OR_OPERAND_TYPE),
+ expectedErrors: MessageKind.INVALID_LOGICAL_OR_OPERAND_TYPE),
const ConstantData('0 || true', 'NonConstant',
- MessageKind.INVALID_LOGICAL_OR_OPERAND_TYPE),
+ expectedErrors: MessageKind.INVALID_LOGICAL_OR_OPERAND_TYPE),
const ConstantData('true || integer', 'NonConstant',
- MessageKind.INVALID_LOGICAL_OR_OPERAND_TYPE),
+ expectedErrors: MessageKind.INVALID_LOGICAL_OR_OPERAND_TYPE),
const ConstantData('integer || true', 'NonConstant',
- MessageKind.INVALID_LOGICAL_OR_OPERAND_TYPE),
+ expectedErrors: MessageKind.INVALID_LOGICAL_OR_OPERAND_TYPE),
const ConstantData('true && 0', 'NonConstant',
- MessageKind.INVALID_LOGICAL_AND_OPERAND_TYPE),
+ expectedErrors: MessageKind.INVALID_LOGICAL_AND_OPERAND_TYPE),
const ConstantData('0 && true', 'NonConstant',
- MessageKind.INVALID_LOGICAL_AND_OPERAND_TYPE),
+ expectedErrors: MessageKind.INVALID_LOGICAL_AND_OPERAND_TYPE),
const ConstantData('integer && true', 'NonConstant',
- MessageKind.INVALID_LOGICAL_AND_OPERAND_TYPE),
- const ConstantData(
- '!0', 'NonConstant', MessageKind.INVALID_CONSTANT_NOT_TYPE),
- const ConstantData(
- '!string', 'NonConstant', MessageKind.INVALID_CONSTANT_NOT_TYPE),
- const ConstantData(
- '-("")', 'NonConstant', MessageKind.INVALID_CONSTANT_NEGATE_TYPE),
- const ConstantData(
- '-(string)', 'NonConstant', MessageKind.INVALID_CONSTANT_NEGATE_TYPE),
+ expectedErrors: MessageKind.INVALID_LOGICAL_AND_OPERAND_TYPE),
+ const ConstantData('!0', 'NonConstant',
+ expectedErrors: MessageKind.INVALID_CONSTANT_NOT_TYPE),
+ const ConstantData('!string', 'NonConstant',
+ expectedErrors: MessageKind.INVALID_CONSTANT_NOT_TYPE),
+ const ConstantData('-("")', 'NonConstant',
+ expectedErrors: MessageKind.INVALID_CONSTANT_NEGATE_TYPE),
+ const ConstantData('-(string)', 'NonConstant',
+ expectedErrors: MessageKind.INVALID_CONSTANT_NEGATE_TYPE),
const ConstantData('not_string.length', 'NonConstant',
- MessageKind.INVALID_CONSTANT_STRING_LENGTH_TYPE),
+ expectedErrors: MessageKind.INVALID_CONSTANT_STRING_LENGTH_TYPE),
const ConstantData('const Class1()', 'NonConstant',
- MessageKind.INVALID_CONSTANT_STRING_LENGTH_TYPE),
+ expectedErrors: MessageKind.INVALID_CONSTANT_STRING_LENGTH_TYPE),
const ConstantData('getter', 'NonConstant'),
- const ConstantData(
- 'const Class2()', 'NonConstant', MessageKind.INVALID_ASSERT_VALUE),
+ const ConstantData('const Class2()', 'NonConstant',
+ expectedErrors: MessageKind.INVALID_ASSERT_VALUE),
const ConstantData('const Class2.redirect()', 'NonConstant',
- MessageKind.INVALID_ASSERT_VALUE),
+ expectedErrors: MessageKind.INVALID_ASSERT_VALUE),
const ConstantData('const Class3()', 'NonConstant',
- MessageKind.INVALID_ASSERT_VALUE_MESSAGE),
- const ConstantData(
- 'const Class3.fact()', 'NonConstant', MessageKind.INVALID_ASSERT_VALUE),
- const ConstantData(
- 'const Class4()', 'NonConstant', MessageKind.INVALID_ASSERT_VALUE),
+ expectedErrors: MessageKind.INVALID_ASSERT_VALUE_MESSAGE),
+ const ConstantData('const Class3.fact()', 'NonConstant',
+ expectedErrors: MessageKind.INVALID_ASSERT_VALUE),
+ const ConstantData('const Class4()', 'NonConstant',
+ expectedErrors: MessageKind.INVALID_ASSERT_VALUE),
const ConstantData('const Class5(0)', 'NonConstant',
- MessageKind.INVALID_ASSERT_VALUE_MESSAGE),
+ expectedErrors: MessageKind.INVALID_ASSERT_VALUE_MESSAGE),
const ConstantData('const Class5(1)', 'ConstructedConstant(Class5())'),
const ConstantData('const Class6(1)', 'NonConstant',
- MessageKind.INVALID_ASSERT_VALUE_MESSAGE),
+ expectedErrors: MessageKind.INVALID_ASSERT_VALUE_MESSAGE),
const ConstantData('const Class6(2)', 'ConstructedConstant(Class6())'),
]),
const TestData('assert', '''
@@ -505,6 +525,31 @@
const ConstantData(r'const D(0)',
'ConstructedConstant(D(a=IntConstant(1),b=IntConstant(2)))'),
]),
+ const TestData(
+ 'instantiations',
+ '''
+T identity<T>(T t) => t;
+class C<T> {
+ final T defaultValue;
+ final T Function(T t) identityFunction;
+
+ const C(this.defaultValue, this.identityFunction);
+}
+ ''',
+ const <ConstantData>[
+ const ConstantData('identity', 'FunctionConstant(identity)'),
+ const ConstantData(
+ 'const C<int>(0, identity)',
+ 'ConstructedConstant(C<int>(defaultValue=IntConstant(0),'
+ 'identityFunction=InstantiationConstant([int],'
+ 'FunctionConstant(identity))))'),
+ const ConstantData(
+ 'const C<double>(0.5, identity)',
+ 'ConstructedConstant(C<double>(defaultValue=DoubleConstant(0.5),'
+ 'identityFunction=InstantiationConstant([double],'
+ 'FunctionConstant(identity))))'),
+ ],
+ strongModeOnly: true)
];
main(List<String> args) {
@@ -518,14 +563,20 @@
Future testData(TestData data) async {
StringBuffer sb = new StringBuffer();
- sb.write('${data.declarations}\n');
+ sb.writeln('${data.declarations}');
Map<String, ConstantData> constants = {};
+ List<String> names = <String>[];
data.constants.forEach((ConstantData constantData) {
String name = 'c${constants.length}';
- sb.write('const $name = ${constantData.code};\n');
+ names.add(name);
+ sb.writeln('const $name = ${constantData.code};');
constants[name] = constantData;
});
- sb.write('main() {}\n');
+ sb.writeln('main() {');
+ for (String name in names) {
+ sb.writeln(' print($name);');
+ }
+ sb.writeln('}');
String source = sb.toString();
print("--source '${data.name}'---------------------------------------------");
print(source);
@@ -533,7 +584,8 @@
Future runTest(
List<String> options,
EvaluationEnvironment getEnvironment(
- Compiler compiler, FieldEntity field)) async {
+ Compiler compiler, FieldEntity field),
+ {bool strongMode: false}) async {
CompilationResult result = await runCompiler(
memorySourceFiles: {'main.dart': source}, options: options);
Compiler compiler = result.compiler;
@@ -546,7 +598,8 @@
ConstantExpression constant =
elementEnvironment.getFieldConstant(field);
- var expectedResults = data.expectedResults;
+ var expectedResults =
+ strongMode ? data.strongModeResults : data.expectedResults;
if (expectedResults is String) {
expectedResults = {const <String, String>{}: expectedResults};
}
@@ -606,23 +659,42 @@
'redirect',
];
- if (!skipAstList.contains(data.name)) {
+ const skipStrongList = const [
+ // TODO(johnniwinther): Investigate why some types of the constructed
+ // objects don't match.
+ 'redirect',
+ // TODO(johnniwinther): Investigate why different errors are reported in
+ // strong mode.
+ 'errors',
+ ];
+
+ if (!skipAstList.contains(data.name) && !data.strongModeOnly) {
print(
'--test ast----------------------------------------------------------');
await runTest(
- [Flags.useOldFrontend, Flags.analyzeAll],
+ [Flags.useOldFrontend],
(Compiler compiler, FieldEntity field) => new AstEvaluationEnvironment(
compiler,
constantRequired: field.isConst));
}
- if (!skipKernelList.contains(data.name)) {
+ if (!skipKernelList.contains(data.name) && !data.strongModeOnly) {
print(
'--test kernel-------------------------------------------------------');
- await runTest([Flags.analyzeOnly], (Compiler compiler, FieldEntity field) {
+ await runTest([], (Compiler compiler, FieldEntity field) {
KernelFrontEndStrategy frontendStrategy = compiler.frontendStrategy;
KernelToElementMap elementMap = frontendStrategy.elementMap;
return new KernelEvaluationEnvironment(elementMap, null, field,
constantRequired: field.isConst);
});
}
+ if (!skipStrongList.contains(data.name)) {
+ print(
+ '--test kernel (strong mode)-----------------------------------------');
+ await runTest([Flags.strongMode], (Compiler compiler, FieldEntity field) {
+ KernelFrontEndStrategy frontendStrategy = compiler.frontendStrategy;
+ KernelToElementMap elementMap = frontendStrategy.elementMap;
+ return new KernelEvaluationEnvironment(elementMap, null, field,
+ constantRequired: field.isConst);
+ }, strongMode: true);
+ }
}
diff --git a/tests/compiler/dart2js/model/constant_expression_test.dart b/tests/compiler/dart2js/model/constant_expression_test.dart
index 6babb67..efe465e 100644
--- a/tests/compiler/dart2js/model/constant_expression_test.dart
+++ b/tests/compiler/dart2js/model/constant_expression_test.dart
@@ -7,8 +7,9 @@
import 'dart:async';
import 'package:async_helper/async_helper.dart';
import 'package:expect/expect.dart';
-import 'package:compiler/src/constants/expressions.dart';
+import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/compiler.dart';
+import 'package:compiler/src/constants/expressions.dart';
import 'package:compiler/src/kernel/element_map_impl.dart';
import 'package:compiler/src/elements/entities.dart';
import '../memory_compiler.dart';
@@ -21,7 +22,10 @@
/// Tested constants.
final List<ConstantData> constants;
- const TestData(this.declarations, this.constants);
+ final bool strongModeOnly;
+
+ const TestData(this.declarations, this.constants,
+ {this.strongModeOnly: false});
}
class ConstantData {
@@ -34,6 +38,9 @@
/// ConstantExpression.getText() result if different from [code].
final String text;
+ /// ConstantExpression.getText() result if different from [code].
+ final String strongText;
+
/// The expected instance type for ConstructedConstantExpression.
final String type;
@@ -41,9 +48,10 @@
final Map<String, String> fields;
const ConstantData(String code, this.kind,
- {String text, this.type, this.fields})
+ {String text, String strongText, this.type, this.fields})
: this.code = code,
- this.text = text != null ? text : code;
+ this.text = text ?? code,
+ this.strongText = strongText ?? text ?? code;
}
const List<TestData> DATA = const [
@@ -56,7 +64,6 @@
const ConstantData('"foo"', ConstantExpressionKind.STRING),
const ConstantData('1 + 2', ConstantExpressionKind.BINARY),
const ConstantData('1 == 2', ConstantExpressionKind.BINARY),
- // TODO(sigmund): reenable (Issue 32511)
const ConstantData('1 != 2', ConstantExpressionKind.UNARY,
// a != b is encoded as !(a == b) by CFE.
text: '!(1 == 2)'),
@@ -71,9 +78,11 @@
const ConstantData('proxy', ConstantExpressionKind.FIELD),
const ConstantData('Object', ConstantExpressionKind.TYPE),
const ConstantData('#name', ConstantExpressionKind.SYMBOL),
- const ConstantData('const [0, 1]', ConstantExpressionKind.LIST),
+ const ConstantData('const [0, 1]', ConstantExpressionKind.LIST,
+ strongText: 'const <int>[0, 1]'),
const ConstantData('const <int>[0, 1]', ConstantExpressionKind.LIST),
- const ConstantData('const {0: 1, 2: 3}', ConstantExpressionKind.MAP),
+ const ConstantData('const {0: 1, 2: 3}', ConstantExpressionKind.MAP,
+ strongText: 'const <int, int>{0: 1, 2: 3}'),
const ConstantData(
'const <int, int>{0: 1, 2: 3}', ConstantExpressionKind.MAP),
const ConstantData('const bool.fromEnvironment("foo", defaultValue: false)',
@@ -157,7 +166,6 @@
const ConstantData(
'const A<int>(field1: 87)', ConstantExpressionKind.CONSTRUCTED,
type: 'A<int>', fields: const {'field(A#field1)': '87'}),
- // TODO(sigmund): reenable (Issue 32511)
const ConstantData('const B()', ConstantExpressionKind.CONSTRUCTED,
type: 'A<B<dynamic>>',
fields: const {
@@ -197,25 +205,63 @@
// Redirecting factories are replaced by their effective targets by CFE.
text: 'const A<int>()'),
]),
+ const TestData('''
+T identity<T>(T t) => t;
+class C<T> {
+ final T defaultValue;
+ final T Function(T t) identityFunction;
+
+ const C(this.defaultValue, this.identityFunction);
+}
+ ''', const <ConstantData>[
+ const ConstantData('identity', ConstantExpressionKind.FUNCTION),
+ const ConstantData(
+ 'const C<int>(0, identity)', ConstantExpressionKind.CONSTRUCTED,
+ type: 'C<int>', strongText: 'const C<int>(0, <int>(identity))'),
+ const ConstantData(
+ 'const C<double>(0.5, identity)', ConstantExpressionKind.CONSTRUCTED,
+ type: 'C<double>',
+ strongText: 'const C<double>(0.5, <double>(identity))'),
+ ], strongModeOnly: true)
];
main() {
- asyncTest(() => Future.forEach(DATA, testData));
+ asyncTest(() async {
+ print('--test from kernel------------------------------------------------');
+ await runTest(strongMode: false);
+ print('--test from kernel (strong)---------------------------------------');
+ await runTest(strongMode: true);
+ });
}
-Future testData(TestData data) async {
+Future runTest({bool strongMode}) async {
+ for (TestData data in DATA) {
+ await testData(data, strongMode: strongMode);
+ }
+}
+
+Future testData(TestData data, {bool strongMode}) async {
+ if (data.strongModeOnly && !strongMode) return;
+
StringBuffer sb = new StringBuffer();
- sb.write('${data.declarations}\n');
+ sb.writeln('${data.declarations}');
Map<String, ConstantData> constants = {};
+ List<String> names = <String>[];
data.constants.forEach((ConstantData constantData) {
String name = 'c${constants.length}';
- sb.write('const $name = ${constantData.code};\n');
+ names.add(name);
+ sb.writeln('const $name = ${constantData.code};');
constants[name] = constantData;
});
- sb.write('main() {}\n');
+ sb.writeln('main() {');
+ for (String name in names) {
+ sb.writeln(' print($name);');
+ }
+ sb.writeln('}');
String source = sb.toString();
CompilationResult result = await runCompiler(
- memorySourceFiles: {'main.dart': source}, options: ['--analyze-all']);
+ memorySourceFiles: {'main.dart': source},
+ options: strongMode ? [Flags.strongMode] : []);
Compiler compiler = result.compiler;
var elementEnvironment = compiler.frontendStrategy.elementEnvironment;
@@ -233,11 +279,12 @@
constant.kind,
"Unexpected kind '${constant.kind}' for constant "
"`${constant.toDartText()}`, expected '${data.kind}'.");
+ String text = strongMode ? data.strongText : data.text;
Expect.equals(
- data.text,
+ text,
constant.toDartText(),
"Unexpected text '${constant.toDartText()}' for constant, "
- "expected '${data.text}'.");
+ "expected '${text}'.");
if (data.type != null) {
String instanceType =
constant.computeInstanceType(environment).toString();
diff --git a/tests/compiler/dart2js/old_frontend/mock_libraries.dart b/tests/compiler/dart2js/old_frontend/mock_libraries.dart
index a4e4158..f5f6e63 100644
--- a/tests/compiler/dart2js/old_frontend/mock_libraries.dart
+++ b/tests/compiler/dart2js/old_frontend/mock_libraries.dart
@@ -233,7 +233,10 @@
'IrRepresentation': 'class IrRepresentation {}',
'isJsIndexable': 'isJsIndexable(a, b) {}',
'JavaScriptIndexingBehavior': 'abstract class JavaScriptIndexingBehavior {}',
- 'JSInvocationMirror': 'class JSInvocationMirror {}',
+ 'JSInvocationMirror': r'''
+ class JSInvocationMirror {
+ get typeArguments => null;
+ }''',
'listSuperNativeTypeCast': 'listSuperNativeTypeCast(value) {}',
'listSuperNativeTypeCheck': 'listSuperNativeTypeCheck(value) {}',
'listSuperTypeCast': 'listSuperTypeCast(value) {}',
diff --git a/tests/compiler/dart2js/rti/data/no_such_method1_strong.dart b/tests/compiler/dart2js/rti/data/no_such_method1_strong.dart
new file mode 100644
index 0000000..21ed9d8
--- /dev/null
+++ b/tests/compiler/dart2js/rti/data/no_such_method1_strong.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+class C {
+ /*element: C.noSuchMethod:selectors=[Selector(call, foo, arity=0, types=2)]*/
+ noSuchMethod(i) => i.typeArguments;
+}
+
+@NoInline()
+test(dynamic x) {
+ print(x.foo<int, String>());
+}
+
+main() {
+ test(new C());
+}
diff --git a/tests/compiler/dart2js/rti/data/no_such_method2_strong.dart b/tests/compiler/dart2js/rti/data/no_such_method2_strong.dart
new file mode 100644
index 0000000..6b39377
--- /dev/null
+++ b/tests/compiler/dart2js/rti/data/no_such_method2_strong.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+class C {
+ /*element: C.noSuchMethod:selectors=[Selector(call, foo, arity=0, types=2)]*/
+ noSuchMethod(i) => i.typeArguments;
+}
+
+class D {
+ /*element: D.foo:exp,needsArgs,selectors=[Selector(call, foo, arity=0, types=2)]*/
+ foo<U, V>() => [U, V];
+}
+
+@NoInline()
+test(dynamic x) {
+ print(x.foo<int, String>());
+}
+
+main() {
+ test(new C());
+ test(new D());
+}
diff --git a/tests/compiler/dart2js/rti/data/no_such_method3_strong.dart b/tests/compiler/dart2js/rti/data/no_such_method3_strong.dart
new file mode 100644
index 0000000..98883aa
--- /dev/null
+++ b/tests/compiler/dart2js/rti/data/no_such_method3_strong.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+class C {
+ /*element: C.noSuchMethod:*/
+ noSuchMethod(i) => null;
+}
+
+@NoInline()
+test(dynamic x) {
+ print(x.foo<int, String>());
+}
+
+main() {
+ test(new C());
+}
diff --git a/tests/compiler/dart2js/sourcemaps/data/invokes.dart b/tests/compiler/dart2js/sourcemaps/data/invokes.dart
index fa7bed0..53e84d3 100644
--- a/tests/compiler/dart2js/sourcemaps/data/invokes.dart
+++ b/tests/compiler/dart2js/sourcemaps/data/invokes.dart
@@ -122,7 +122,7 @@
}
invalidInvokes() {
- // ignore: invocation_of_non_function
+ // ignore: not_enough_required_arguments
C();
// ignore: undefined_method
dynamic();
diff --git a/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_async.dart b/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_async.dart
index b1cc65d..7ca81d3 100644
--- a/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_async.dart
+++ b/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_async.dart
@@ -11,5 +11,6 @@
@NoInline()
test() async {
+ await null;
/*1:test*/ throw '>ExceptionMarker<';
}
diff --git a/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_awaited_async.dart b/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_awaited_async.dart
index 47d2c2d..522bcf7 100644
--- a/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_awaited_async.dart
+++ b/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_awaited_async.dart
@@ -16,5 +16,6 @@
@NoInline()
test2() async {
+ await null;
/*1:test2*/ throw '>ExceptionMarker<';
}
diff --git a/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_constructor_from_async.dart b/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_constructor_from_async.dart
index 05db172..0120aa3 100644
--- a/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_constructor_from_async.dart
+++ b/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_constructor_from_async.dart
@@ -10,6 +10,7 @@
}
test() async {
+ await null;
// ignore: UNUSED_LOCAL_VARIABLE
var c = new /*1:test*/ Class();
}
diff --git a/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_top_level_method_from_async.dart b/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_top_level_method_from_async.dart
index af5ea17..c172214 100644
--- a/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_top_level_method_from_async.dart
+++ b/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_top_level_method_from_async.dart
@@ -10,6 +10,7 @@
@NoInline()
test1() async {
+ await null;
/*1:test1*/ test2();
}
diff --git a/tests/compiler/dart2js_extra/27323_test.dart b/tests/compiler/dart2js_extra/27323_test.dart
new file mode 100644
index 0000000..8e2a919
--- /dev/null
+++ b/tests/compiler/dart2js_extra/27323_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2018, 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.
+
+// dart2jsOptions=--strong
+
+import 'package:expect/expect.dart';
+
+class C {
+ noSuchMethod(i) => i.typeArguments;
+}
+
+class D {
+ foo<U, V>() => [U, V];
+}
+
+@NoInline()
+test(dynamic x) {
+ dynamic typeArguments = x.foo<int, String>();
+ Expect.equals(int, typeArguments[0]);
+ Expect.equals(String, typeArguments[1]);
+}
+
+main() {
+ test(new C());
+ test(new D()); //# 01: ok
+}
diff --git a/tests/compiler/dart2js_extra/js_array_sort_default_test.dart b/tests/compiler/dart2js_extra/js_array_sort_default_test.dart
new file mode 100644
index 0000000..8f4e161
--- /dev/null
+++ b/tests/compiler/dart2js_extra/js_array_sort_default_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2018, 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.
+
+/// Tests that the default comparable function in JSArray.sort has a valid
+/// strong-mode type.
+void main() {
+ new List<dynamic>.from(['1', '2']).sort();
+}
diff --git a/tests/corelib_2/corelib_2.status b/tests/corelib_2/corelib_2.status
index ce101ae..6641868 100644
--- a/tests/corelib_2/corelib_2.status
+++ b/tests/corelib_2/corelib_2.status
@@ -613,5 +613,4 @@
[ $hot_reload || $hot_reload_rollback ]
bigint_parse_radix_test: Pass, Timeout # Issue 31659
-bigint_test: Pass, Crash # Issue 31660
integer_parsed_mul_div_vm_test: Pass, Slow # Slow
diff --git a/tests/language/language.status b/tests/language/language.status
index 0916858..33b2122 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -12,11 +12,11 @@
vm/regress_27201_test: SkipByDesign # Loads bad library, so will always crash.
[ $compiler == precompiler ]
-deferred_global_test: Fail # Deferred loading happens eagerly. Issue #27587
+deferred_global_test: Skip # Deferred loading happens eagerly.
deopt_inlined_function_lazy_test: Skip # Incompatible flag: --deoptimize-alot
implicit_closure_test: Skip # Incompatible flag: --use_slow_path
regress_23408_test: RuntimeError
-vm/regress_27201_test: Fail # Deferred loading happens eagerly. Issue #27587
+vm/regress_27201_test: Skip # Deferred loading happens eagerly.
[ $mode == product ]
assertion_test: SkipByDesign # Requires checked mode.
@@ -448,10 +448,10 @@
redirecting_constructor_initializer_test: RuntimeError # Issue 23488
[ $compiler == app_jit || $compiler == precompiler || $mode == product ]
-deferred_load_constants_test/02: Fail # Deferred loading happens eagerly. Issue #27587
-deferred_load_constants_test/03: Fail # Deferred loading happens eagerly. Issue #27587
-deferred_load_constants_test/05: Fail # Deferred loading happens eagerly. Issue #27587
-deferred_not_loaded_check_test: Fail # Deferred loading happens eagerly. Issue #27587
+deferred_load_constants_test/02: Skip # Deferred loading happens eagerly.
+deferred_load_constants_test/03: Skip # Deferred loading happens eagerly.
+deferred_load_constants_test/05: Skip # Deferred loading happens eagerly.
+deferred_not_loaded_check_test: Skip # Deferred loading happens eagerly.
vm/regress_27201_test: Fail
[ $compiler == app_jit || $runtime == dart_precompiled ]
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 0453fe4..9a7255e 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -5,8 +5,11 @@
[ $compiler != dart2analyzer ]
switch_case_warn_test: Skip # Analyzer only, see language_analyzer2.status
-# VM specific tests that should not be run by dart2js.
[ $compiler == dart2js ]
+async_await_test: RuntimeError # sync-async is on by default
+asyncstar_throw_in_catch_test: RuntimeError # sync-async is on by default
+await_nonfuture_test: RuntimeError # sync-async is on by default
+await_not_started_immediately_test: RuntimeError # sync-async is on by default
full_stacktrace1_test: Pass, RuntimeError # Issue 12698
full_stacktrace2_test: Pass, RuntimeError # Issue 12698
full_stacktrace3_test: Pass, RuntimeError # Issue 12698
@@ -585,7 +588,6 @@
[ $compiler == dart2js && $fasta && $host_checked ]
async_test/setter1: Crash # 'file:*/pkg/compiler/lib/src/kernel/element_map_impl.dart': Failed assertion: line 939 pos 18: 'asyncMarker == AsyncMarker.SYNC': is not true.
-branches_test: Crash # 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart': Failed assertion: line 441 pos 16: 'identical(combiner.arguments.positional[0], rhs)': is not true.
closure_self_reference_test: Crash # 'file:*/pkg/compiler/lib/src/ssa/nodes.dart': Failed assertion: line 641 pos 12: 'isClosed()': is not true.
generic_methods_generic_function_parameter_test: Crash # 'file:*/pkg/compiler/lib/src/ssa/builder_kernel.dart': Failed assertion: line 1728 pos 16: 'type is MethodTypeVariableType': is not true.
generic_methods_type_expression_test/01: Crash # 'file:*/pkg/compiler/lib/src/ssa/builder_kernel.dart': Failed assertion: line 1728 pos 16: 'type is MethodTypeVariableType': is not true.
@@ -593,8 +595,6 @@
generic_methods_type_expression_test/none: Crash # 'file:*/pkg/compiler/lib/src/ssa/builder_kernel.dart': Failed assertion: line 1728 pos 16: 'type is MethodTypeVariableType': is not true.
invocation_mirror_test: Crash # 'file:*/pkg/compiler/lib/src/ssa/builder_kernel.dart': Failed assertion: line 3014 pos 14: 'arguments.named.isEmpty': is not true.
operator2_negative_test: Crash # 'file:*/pkg/compiler/lib/src/kernel/env.dart': Failed assertion: line 322 pos 16: '!name.contains('#')': is not true.
-operator_test: Crash # 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart': Failed assertion: line 441 pos 16: 'identical(combiner.arguments.positional[0], rhs)': is not true.
-prefix5_negative_test: Crash # 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart': Failed assertion: line 441 pos 16: 'identical(combiner.arguments.positional[0], rhs)': is not true.
sync_generator2_test/41: Crash # 'file:*/pkg/compiler/lib/src/kernel/element_map_impl.dart': Failed assertion: line 939 pos 18: 'asyncMarker == AsyncMarker.SYNC': is not true.
sync_generator2_test/52: Crash # 'file:*/pkg/compiler/lib/src/kernel/element_map_impl.dart': Failed assertion: line 939 pos 18: 'asyncMarker == AsyncMarker.SYNC': is not true.
syntax_test/04: Crash # 'file:*/pkg/compiler/lib/src/kernel/env.dart': Failed assertion: line 322 pos 16: '!name.contains('#')': is not true.
diff --git a/tests/language/language_spec_parser.status b/tests/language/language_spec_parser.status
index 16dec52..5e35c74 100644
--- a/tests/language/language_spec_parser.status
+++ b/tests/language/language_spec_parser.status
@@ -19,7 +19,6 @@
is_not_class4_negative_test: Fail # Negative, uses `a is A is A`.
issue1578_negative_test: Fail # Negative, is line noise.
issue_1751477_test: Skip # Times out: 9 levels, exponential blowup => 430 secs.
-label8_negative_test: Fail # Negative, uses misplaced label.
list_literal_negative_test: Fail # Negative, uses `new List<int>[1, 2]`.
map_literal_negative_test: Fail # Negative, uses `new Map<int>{..}`.
new_expression1_negative_test: Fail # Negative, uses `new id`.
diff --git a/tests/language_2/break_outside_loop_test.dart b/tests/language_2/break_outside_loop_test.dart
new file mode 100644
index 0000000..5fab9e1
--- /dev/null
+++ b/tests/language_2/break_outside_loop_test.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test program to test check that we catch label errors.
+
+main() {
+ if (true) {
+ break; //# 01: compile-time error
+ }
+}
diff --git a/tests/language_2/label2_negative_test.dart b/tests/language_2/label2_negative_test.dart
deleted file mode 100644
index ab9d256..0000000
--- a/tests/language_2/label2_negative_test.dart
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-// Dart test program to test check that we catch label errors.
-
-
-class Label2NegativeTest {
- static testMain() {
- if (true) {
- break; // Illegal: not embedded in a loop.
- }
- }
-}
-
-
-main() {
- Label2NegativeTest.testMain();
-}
diff --git a/tests/language_2/label3_negative_test.dart b/tests/language_2/label3_negative_test.dart
deleted file mode 100644
index 56482ee..0000000
--- a/tests/language_2/label3_negative_test.dart
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-// Dart test program to test check that we catch label errors.
-
-
-class Label3NegativeTest {
- static testMain() {
- L: while (false) {
- if (true) break L; // Ok
- }
- continue L; // Illegal: L is out of scope.
- }
-}
-
-
-main() {
- Label3NegativeTest.testMain();
-}
diff --git a/tests/language_2/label3_test.dart b/tests/language_2/label3_test.dart
new file mode 100644
index 0000000..5685aab
--- /dev/null
+++ b/tests/language_2/label3_test.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2011, 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.
+
+main() {
+ L: while (false) {
+ if (true) break L; //# 01: ok
+ }
+ // Illegal: L is out of scope.
+ continue L; //# 02: compile-time error
+}
diff --git a/tests/language_2/label5_negative_test.dart b/tests/language_2/label5_negative_test.dart
deleted file mode 100644
index 520fbb44..0000000
--- a/tests/language_2/label5_negative_test.dart
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-// Dart test program to test check that we catch label errors.
-
-class Label5NegativeTest {
- static testMain() {
- var L = 33;
- while (false) {
- if (true) break L; // Illegal: L is not a label.
- }
- }
-}
-
-main() {
- Label5NegativeTest.testMain();
-}
diff --git a/tests/language_2/label5_test.dart b/tests/language_2/label5_test.dart
new file mode 100644
index 0000000..2007cf4
--- /dev/null
+++ b/tests/language_2/label5_test.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2011, 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.
+
+main() {
+ var L = 33;
+ while (false) {
+ // Illegal: L is not a label.
+ if (true) break L; //# 01: compile-time error
+ }
+}
diff --git a/tests/language_2/label6_negative_test.dart b/tests/language_2/label6_negative_test.dart
deleted file mode 100644
index eee60ab2..0000000
--- a/tests/language_2/label6_negative_test.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-// Dart test program to test check that we catch label errors.
-
-class Label6NegativeTest {
- static testMain() {
- L:
- while (false) {
- break; // ok;
- break L; // ok
- void innerfunc() {
- if (true) break L; // Illegal: jump target is outside of function
- }
-
- innerfunc();
- }
- }
-}
-
-main() {
- Label6NegativeTest.testMain();
-}
diff --git a/tests/language_2/label6_test.dart b/tests/language_2/label6_test.dart
new file mode 100644
index 0000000..d46ca9b
--- /dev/null
+++ b/tests/language_2/label6_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2011, 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.
+
+main() {
+ L:
+ while (false) {
+ break; //# 01: ok
+ break L; //# 02: ok
+ void innerfunc() {
+ // Illegal: jump target is outside of function
+ if (true) break L; //# 03: compile-time error
+ }
+
+ innerfunc();
+ }
+}
diff --git a/tests/language_2/label8_negative_test.dart b/tests/language_2/label8_negative_test.dart
deleted file mode 100644
index ff35321..0000000
--- a/tests/language_2/label8_negative_test.dart
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2011, 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.
-// Labels aren't allowed in front of { for switch stmt
-
-
-class Label8NegativeTest {
- static errorMethod() {
- int i;
- // grammar doesn't currently allow label on block for switch stmt.
- switch(i) L: {
- case 111:
- while (doAgain()) {
- break L;
- }
- i++;
- }
- }
- static testMain() {
- Label8NegativeTest.errorMethod();
- }
-}
-
-
-main() {
- Label8NegativeTest.testMain();
-}
diff --git a/tests/language_2/label8_test.dart b/tests/language_2/label8_test.dart
new file mode 100644
index 0000000..751d35b
--- /dev/null
+++ b/tests/language_2/label8_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2011, 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.
+
+main() {
+ int i;
+ // Grammar doesn't allow label on block for switch statement.
+ switch(i)
+ L: //# 01: compile-time error
+ {
+ case 111:
+ while (false) {
+ break L; //# 01: continued
+ }
+ i++;
+ }
+}
diff --git a/tests/language_2/language_2_analyzer.status b/tests/language_2/language_2_analyzer.status
index 55a2708..7bf5e3c 100644
--- a/tests/language_2/language_2_analyzer.status
+++ b/tests/language_2/language_2_analyzer.status
@@ -62,12 +62,6 @@
is_not_class1_negative_test: CompileTimeError
is_not_class4_negative_test: CompileTimeError
issue1578_negative_test: CompileTimeError
-label2_negative_test: CompileTimeError
-label3_negative_test: CompileTimeError
-label5_negative_test: CompileTimeError
-label6_negative_test: CompileTimeError
-label8_negative_test: CompileTimeError
-library_negative_test: CompileTimeError
list_literal2_negative_test: CompileTimeError
list_literal_negative_test: CompileTimeError
map_literal_negative_test: CompileTimeError
diff --git a/tests/language_2/language_2_dart2js.status b/tests/language_2/language_2_dart2js.status
index 7d81932..edb651c 100644
--- a/tests/language_2/language_2_dart2js.status
+++ b/tests/language_2/language_2_dart2js.status
@@ -282,7 +282,7 @@
covariance_type_parameter_test/02: Crash # NoSuchMethodError: The method 'hasSubclass' was called on null.
covariance_type_parameter_test/03: Crash # NoSuchMethodError: The method 'hasSubclass' was called on null.
covariant_override/runtime_check_test: RuntimeError
-covariant_subtyping_test: CompileTimeError
+covariant_subtyping_test: RuntimeError
cyclic_constructor_test/01: Crash # Stack Overflow
deferred_constraints_constants_test/default_argument2: Crash # Unsupported operation: KernelDeferredLoadTask.addMirrorElementsForLibrary
deferred_constraints_constants_test/none: Crash # Unsupported operation: KernelDeferredLoadTask.addMirrorElementsForLibrary
@@ -1038,7 +1038,6 @@
bad_override_test/05: MissingCompileTimeError
bit_operations_test: RuntimeError
branch_canonicalization_test: RuntimeError
-branches_test: Crash # 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart': Failed assertion: line 441 pos 16: 'identical(combiner.arguments.positional[0], rhs)': is not true.
call_method_implicit_tear_off_implements_function_test/02: RuntimeError
call_method_implicit_tear_off_implements_function_test/04: RuntimeError
call_method_implicit_tear_off_test/02: RuntimeError
@@ -1093,7 +1092,7 @@
covariance_type_parameter_test/02: RuntimeError
covariance_type_parameter_test/03: RuntimeError
covariant_override/tear_off_type_test: RuntimeError
-covariant_subtyping_test: CompileTimeError
+covariant_subtyping_test: RuntimeError
cyclic_constructor_test/01: Crash # Issue 30856
cyclic_type_test/00: RuntimeError
cyclic_type_test/02: RuntimeError
@@ -1413,7 +1412,6 @@
number_identity2_test: RuntimeError
numbers_test: RuntimeError, OK # non JS number semantics
operator2_negative_test: Crash # 'file:*/pkg/compiler/lib/src/kernel/env.dart': Failed assertion: line 322 pos 16: '!name.contains('#')': is not true.
-operator_test: Crash # 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart': Failed assertion: line 441 pos 16: 'identical(combiner.arguments.positional[0], rhs)': is not true.
overridden_no_such_method_test: RuntimeError
override_field_method1_negative_test: Fail
override_field_method2_negative_test: Fail
@@ -1446,7 +1444,6 @@
partial_tearoff_instantiation_test/06: Crash # Assertion failure: kind=special,memberName=instantiate,callStructure:CallStructure(arity=0, types=1)
partial_tearoff_instantiation_test/07: Crash # Assertion failure: kind=special,memberName=instantiate,callStructure:CallStructure(arity=0, types=1)
partial_tearoff_instantiation_test/08: Crash # Assertion failure: kind=special,memberName=instantiate,callStructure:CallStructure(arity=0, types=1)
-prefix5_negative_test: Crash # 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart': Failed assertion: line 441 pos 16: 'identical(combiner.arguments.positional[0], rhs)': is not true.
redirecting_factory_default_values_test/01: MissingCompileTimeError
redirecting_factory_default_values_test/02: MissingCompileTimeError
redirecting_factory_infinite_steps_test/01: MissingCompileTimeError
@@ -1716,7 +1713,7 @@
covariance_type_parameter_test/02: RuntimeError
covariance_type_parameter_test/03: RuntimeError
covariant_override/tear_off_type_test: RuntimeError
-covariant_subtyping_test: CompileTimeError
+covariant_subtyping_test: RuntimeError
cyclic_constructor_test/01: Crash # Issue 30856
cyclic_type_variable_test/01: MissingCompileTimeError
cyclic_type_variable_test/02: MissingCompileTimeError
@@ -2192,6 +2189,7 @@
[ $compiler == dart2js && $fasta && $strong ]
const_constructor3_test/04: MissingCompileTimeError # OK - Subtype check uses JS number semantics.
+covariant_subtyping_test: Crash
ct_const_test: RuntimeError
[ $compiler == dart2js && $fasta && !$strong ]
diff --git a/tests/language_2/language_2_dartdevc.status b/tests/language_2/language_2_dartdevc.status
index b611f55..47cd057 100644
--- a/tests/language_2/language_2_dartdevc.status
+++ b/tests/language_2/language_2_dartdevc.status
@@ -97,8 +97,6 @@
issue31596_test: CompileTimeError
issue32353_test: RuntimeError
label_test: RuntimeError
-lazy_static3_test: RuntimeError # Issue 30852
-lazy_static8_test: RuntimeError # Issue 30852
left_shift_test: RuntimeError # Ints and doubles are unified.
library_env_test/has_io_support: RuntimeError # Intended to fail, bool.fromEnvironment("dart.library.async") is false
library_env_test/has_mirror_support: RuntimeError # Intended to fail, bool.fromEnvironment("dart.library.async") is false
@@ -350,7 +348,7 @@
constructor_redirect1_negative_test/01: MissingCompileTimeError
constructor_redirect2_negative_test: MissingCompileTimeError
constructor_redirect_test/01: MissingCompileTimeError
-covariant_subtyping_test: CompileTimeError
+covariant_subtyping_test: RuntimeError
cyclic_constructor_test/01: MissingCompileTimeError
cyclic_type_variable_test/01: MissingCompileTimeError
cyclic_type_variable_test/02: MissingCompileTimeError
@@ -427,7 +425,6 @@
issue31596_super_test/03: CompileTimeError
issue31596_super_test/04: MissingCompileTimeError
issue31596_super_test/05: RuntimeError
-issue32353_test: RuntimeError # Issue 32428
library_env_test/has_io_support: RuntimeError # Unsupported operation: bool.fromEnvironment can only be used as a const constructor
library_env_test/has_mirror_support: RuntimeError # Unsupported operation: bool.fromEnvironment can only be used as a const constructor
library_env_test/has_no_html_support: RuntimeError # Unsupported operation: bool.fromEnvironment can only be used as a const constructor
@@ -518,7 +515,6 @@
mixin_invalid_bound_test/08: MissingCompileTimeError
mixin_invalid_bound_test/09: MissingCompileTimeError
mixin_invalid_bound_test/10: MissingCompileTimeError
-mixin_regress_13688_test: RuntimeError # Issue 32427
mixin_super_2_test/01: MissingCompileTimeError
mixin_super_2_test/03: MissingCompileTimeError
mixin_super_bound_test/01: MissingCompileTimeError
@@ -569,13 +565,11 @@
override_inheritance_mixed_test/08: MissingCompileTimeError
override_inheritance_mixed_test/09: MissingCompileTimeError
override_method_with_field_test/01: MissingCompileTimeError
-recursive_mixin_test: RuntimeError # Issue 32428
redirecting_factory_default_values_test/01: MissingCompileTimeError
redirecting_factory_default_values_test/02: MissingCompileTimeError
redirecting_factory_infinite_steps_test/01: MissingCompileTimeError
redirecting_factory_malbounded_test/01: MissingCompileTimeError
redirecting_factory_reflection_test: RuntimeError # UnimplementedError: node <InvalidExpression> `invalid-expression`
-regress_22666_test: RuntimeError # Issue 32427
regress_23089_test: Crash # Crashes in KernelClassBuilder.buildTypeArguments
regress_23408_test: CompileTimeError # Issue 31533
regress_24283_test: RuntimeError # Expect.equals(expected: <-1>, actual: <4294967295>) fails.
@@ -583,7 +577,6 @@
regress_29405_test: CompileTimeError # Issue 31402 Error: A value of type '#lib2::Foo' can't be assigned to a variable of type '(#lib2::Foo) → void'.
regress_29784_test/01: MissingCompileTimeError
regress_29784_test/02: MissingCompileTimeError
-regress_29949_test: RuntimeError # Issue 32429
regress_30339_test: CompileTimeError
regress_30339_test: RuntimeError # Uncaught Expect.isTrue(false) fails.
setter4_test: MissingCompileTimeError
@@ -683,7 +676,6 @@
ct_const_test: RuntimeError # Issue 2992; RangeError: Maximum call stack size exceeded
custom_await_stack_trace_test: RuntimeError # Issue 29920; Uncaught Expect.equals(at index 0: Expected <Blah \x0ABloop\x0ABleep\x0A...>
cyclic_type2_test: RuntimeError # Issue 29920; Uncaught ReferenceError: V is not defined
-cyclic_type_test/00: RuntimeError # Issue 32564: <dynamic> not printed.
cyclic_type_test/02: RuntimeError # Issue 29920; Uncaught RangeError: Maximum call stack size exceeded
cyclic_type_test/03: RuntimeError # Issue 29920; Uncaught ReferenceError: U is not defined
cyclic_type_test/04: RuntimeError # Issue 29920; Uncaught ReferenceError: U is not defined
@@ -698,7 +690,6 @@
exception_test: RuntimeError # DDC doesn't implement NullThrownError?; Expect.isTrue(false) fails.
expect_test: RuntimeError # Issue 29920; Expect.identical did not fail
f_bounded_quantification3_test: RuntimeError # Issue 29920; Uncaught Error: type arguments should not be null: (F1, F2) => {
-f_bounded_quantification4_test: RuntimeError # Issue 32564: <dynamic> not printed.
field3_test/01: MissingCompileTimeError
field_increment_bailout_test: RuntimeError # Issue 29920; UnimplementedError: JsInstanceMirror.delegate unimplemented
field_initialization_order_test/none: RuntimeError # Expect.equals(expected: <b.a.ai.bi.>, actual: <b.bi.a.ai.>) fails.
@@ -727,8 +718,6 @@
invocation_mirror_test: RuntimeError # Type 'NativeJavaScriptObject' is not a subtype of type 'int' in strong mode
issue21159_test: RuntimeError # Issue 30701; TypeError: method.bind is not a function
issue23244_test: RuntimeError # Issue 29920; Uncaught Unsupported operation: only top-level functions can be spawned.
-lazy_static3_test: RuntimeError # Issue 30852; Expect.equals(expected: <null>, actual: <499>) fails.
-lazy_static8_test: RuntimeError # Issue 30852; Expect.equals(expected: <42>, actual: <2>) fails.
least_upper_bound_expansive_test/none: RuntimeError # 30908; Uncaught RangeError: Maximum call stack size exceeded
left_shift_test: RuntimeError # Ints and doubles are unified.; Expect.equals(expected: <1>, actual: <-4294967295>) fails.
library_env_test/has_html_support: RuntimeError # Issue 30907; Unsupported operation: bool.fromEnvironment can only be used as a const constructor
@@ -741,7 +730,6 @@
many_overridden_no_such_method_test: RuntimeError # UnimplementedError: JsInstanceMirror.delegate unimplemented; UnimplementedError: JsInstanceMirror.delegate unimplemented
method_override7_test/03: MissingCompileTimeError # Issue 30514
mint_arithmetic_test: RuntimeError # Issue 29920; Expect.equals(expected: <4294967297>, actual: <1>) fails.
-mixin_mixin6_test: RuntimeError # Issue 32564: <dynamic> not printed.
modulo_test: RuntimeError # Ints and doubles are unified.; Expect.throws fails: Did not throw
multiline_newline_test/04: MissingCompileTimeError
multiline_newline_test/04r: MissingCompileTimeError
diff --git a/tests/language_2/language_2_kernel.status b/tests/language_2/language_2_kernel.status
index 52eae2d..3e8a0a8 100644
--- a/tests/language_2/language_2_kernel.status
+++ b/tests/language_2/language_2_kernel.status
@@ -13,6 +13,7 @@
[ $compiler == dartkp ]
class_cycle_test/02: MissingCompileTimeError
class_cycle_test/03: MissingCompileTimeError
+covariant_subtyping_test: RuntimeError
duplicate_implements_test/01: MissingCompileTimeError
duplicate_implements_test/02: MissingCompileTimeError
generic_methods_generic_function_result_test/01: MissingCompileTimeError
@@ -82,7 +83,6 @@
constructor_redirect1_negative_test/01: MissingCompileTimeError
constructor_redirect2_negative_test: MissingCompileTimeError
constructor_redirect_test/01: MissingCompileTimeError # Fasta bug: Initializer refers to this.
-covariant_subtyping_test: CompileTimeError
cyclic_constructor_test/01: MissingCompileTimeError # Fasta bug: Cyclic constructor redirection.
cyclic_type_variable_test/01: MissingCompileTimeError
cyclic_type_variable_test/02: MissingCompileTimeError
@@ -572,6 +572,7 @@
const_string_test: RuntimeError
constructor12_test: RuntimeError
constructor3_test: Fail, OK, Pass
+covariant_subtyping_test: RuntimeError
ct_const2_test: Pass, Crash # Flaky
ct_const_test: RuntimeError
cyclic_type2_test: RuntimeError, CompileTimeError
@@ -717,6 +718,7 @@
assertion_initializer_const_error2_test/cc09: MissingCompileTimeError # Not reporting failed assert() at compile time.
assertion_initializer_const_error2_test/cc10: MissingCompileTimeError # Not reporting failed assert() at compile time.
assertion_initializer_const_error2_test/cc11: MissingCompileTimeError # Not reporting failed assert() at compile time.
+covariant_subtyping_test: RuntimeError
redirecting_factory_reflection_test: RuntimeError
# Enabling of dartk for sim{arm,arm64,dbc64} revelaed these test failures, which
@@ -931,7 +933,6 @@
for_in_side_effects_test/01: MissingCompileTimeError
function_propagation_test: RuntimeError
function_subtype_inline2_test: RuntimeError
-function_type_alias6_test/none: RuntimeError
generic_instanceof2_test: RuntimeError
generic_is_check_test: RuntimeError
generic_methods_recursive_bound_test/03: Crash, Pass
diff --git a/tests/language_2/language_2_precompiled.status b/tests/language_2/language_2_precompiled.status
index 8ff6cb8..a771e2d 100644
--- a/tests/language_2/language_2_precompiled.status
+++ b/tests/language_2/language_2_precompiled.status
@@ -247,7 +247,7 @@
covariant_subtyping_tearoff1_test: RuntimeError
covariant_subtyping_tearoff2_test: RuntimeError
covariant_subtyping_tearoff3_test: RuntimeError
-covariant_subtyping_test: CompileTimeError
+covariant_subtyping_test: RuntimeError
covariant_subtyping_unsafe_call1_test: RuntimeError
covariant_subtyping_unsafe_call2_test: RuntimeError
covariant_subtyping_unsafe_call3_test: RuntimeError
diff --git a/tests/language_2/language_2_spec_parser.status b/tests/language_2/language_2_spec_parser.status
index e223c59..7788992 100644
--- a/tests/language_2/language_2_spec_parser.status
+++ b/tests/language_2/language_2_spec_parser.status
@@ -35,12 +35,6 @@
is_not_class4_negative_test: Fail # Negative, uses `a is A is A`.
issue1578_negative_test: Fail # Negative, is line noise.
issue_1751477_test: Skip # Times out: 9 levels, exponential blowup => 430 secs.
-label2_negative_test: Skip # Negative, not syntax.
-label3_negative_test: Skip # Negative, not syntax.
-label5_negative_test: Skip # Negative, not syntax.
-label6_negative_test: Skip # Negative, not syntax.
-label8_negative_test: Fail # Negative, uses misplaced label.
-library_negative_test: Skip # Negative, not syntax.
list_literal2_negative_test: Skip # Negative, not syntax.
list_literal_negative_test: Fail # Negative, uses `new List<int>[1, 2]`.
map_literal2_negative_test: Skip # Negative, not syntax.
diff --git a/tests/language_2/language_2_vm.status b/tests/language_2/language_2_vm.status
index 8e3a8e3..8b95fdf9 100644
--- a/tests/language_2/language_2_vm.status
+++ b/tests/language_2/language_2_vm.status
@@ -1335,6 +1335,7 @@
generic_methods_generic_function_parameter_test: Pass # Issue 25869
generic_methods_new_test: Pass # Issue 25869
generic_methods_test: Pass # Issue 25869
+library_test/01: MissingCompileTimeError
nosuchmethod_forwarding/nosuchmethod_forwarding_arguments_test: RuntimeError
nosuchmethod_forwarding/nosuchmethod_forwarding_test/05: RuntimeError
nosuchmethod_forwarding/nosuchmethod_forwarding_test/06: RuntimeError
diff --git a/tests/language_2/library_negative_test.dart b/tests/language_2/library_negative_test.dart
deleted file mode 100644
index e15b159..0000000
--- a/tests/language_2/library_negative_test.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2011, 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.
-// This test should fail to load because the app file references a
-// library spec file that does not exist.
-
-library LibraryNegativeTest.dart;
-
-import "nonexisting_library.lib";
-
-main(args) {
- LibraryNegativeTest.testMain(args);
-}
-
-class LibraryNegativeTest {
- static testMain() {
- print("Er, hello world? This should not be printed!");
- }
-}
-
-main() {
- LibraryNegativeTest.testMain();
-}
diff --git a/tests/language_2/library_test.dart b/tests/language_2/library_test.dart
new file mode 100644
index 0000000..6dd7428
--- /dev/null
+++ b/tests/language_2/library_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2011, 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 "nonexistent_library.dart"; //# 01: compile-time error
+
+main() {
+ print("Er, hello world? This should not be printed!");
+}
diff --git a/tests/language_2/mixin_and_extension_member_test.dart b/tests/language_2/mixin_and_extension_member_test.dart
index 8565366..3f96a4a 100644
--- a/tests/language_2/mixin_and_extension_member_test.dart
+++ b/tests/language_2/mixin_and_extension_member_test.dart
@@ -27,6 +27,6 @@
main() {
List x = new ListMock();
x.add(42);
- Expect.equals(x[0], 42);
- Expect.equals(x.first, 9999);
+ Expect.equals(42, x[0]);
+ Expect.equals(9999, x.first);
}
diff --git a/tests/language_2/redirecting_factory_reflection_test.dart b/tests/language_2/redirecting_factory_reflection_test.dart
index b1ae524..cf5d60b 100644
--- a/tests/language_2/redirecting_factory_reflection_test.dart
+++ b/tests/language_2/redirecting_factory_reflection_test.dart
@@ -18,5 +18,7 @@
main() {
ClassMirror m = reflectClass(A);
var i = m.newInstance(Symbol.empty, []).reflectee;
- Expect.equals(i.t.toString(), 'A');
+ var s = i.t.toString();
+ Expect.isTrue(s == 'A' || s == 'A<dynamic>',
+ 'mirrors should create the correct reified generic type');
}
diff --git a/tests/language_2/type_literal_test.dart b/tests/language_2/type_literal_test.dart
index 94e3750..37e59d1 100644
--- a/tests/language_2/type_literal_test.dart
+++ b/tests/language_2/type_literal_test.dart
@@ -19,6 +19,8 @@
Type get typeArg => T;
}
+class G<A, B> {}
+
typedef int Func(bool b);
typedef int GenericFunc<T>(T t);
@@ -36,14 +38,16 @@
testType(Foo, "Foo");
// Generic classes.
- testType(Box, "Box");
+ testType(Box, "Box", "<dynamic>");
testType(new Box<Foo>().typeArg, "Foo");
testType(new Box<dynamic>().typeArg, "dynamic");
testType(new Box<Box<Foo>>().typeArg, "Box<Foo>");
+ testType(G, "G", "<dynamic, dynamic>");
+ testType(new Box<G<int, String>>().typeArg, "G<int, String>");
// Typedef.
testType(Func, "Func");
- testType(GenericFunc, "GenericFunc");
+ testType(GenericFunc, "GenericFunc", "<dynamic>");
testType(new Box<GenericFunc<int>>().typeArg, "GenericFunc<int>");
// Literals are canonicalized.
@@ -66,7 +70,15 @@
Expect.equals("result", prefix.Foo.method());
}
-void testType(Type type, String string) {
- Expect.equals(string, type.toString());
+void testType(Type type, String string, [String genericArgs]) {
+ if (genericArgs != null) {
+ var s = type.toString();
+ Expect.isTrue(
+ s == string || s == '$string$genericArgs',
+ 'type `$type`.toString() should be `$string`, '
+ 'optionally with $genericArgs suffix.');
+ } else {
+ Expect.equals(string, type.toString());
+ }
Expect.isTrue(type is Type);
}
diff --git a/tests/language_2/vm/regress_32971_test.dart b/tests/language_2/vm/regress_32971_test.dart
new file mode 100644
index 0000000..6f5863b
--- /dev/null
+++ b/tests/language_2/vm/regress_32971_test.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2018, 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.
+
+// Test verifying that default switch cast is cloned correctly by the
+// mixin transformation.
+
+import "package:expect/expect.dart";
+
+void main() {
+ final o = new A();
+ Expect.isTrue(o.f());
+ Expect.isTrue(o.g());
+}
+
+class A extends B with M {}
+
+class B {
+ bool f() {
+ switch (true) {
+ default:
+ return true;
+ }
+ return false;
+ }
+}
+
+class M {
+ bool g() {
+ switch (true) {
+ default:
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 45b680a..7a7c744 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -15,6 +15,7 @@
*: Skip
[ $compiler == dart2js ]
+async/async_await_sync_completer_test: RuntimeError # sync-async is on by default.
async/schedule_microtask6_test: RuntimeError # global error handling is not supported. Issue 5958
convert/base64_test/01: Fail, OK # Uses bit-wise operations to detect invalid values. Some large invalid values accepted by dart2js.
convert/chunked_conversion_utf88_test: Slow, Pass
diff --git a/tests/lib_2/lib_2_analyzer.status b/tests/lib_2/lib_2_analyzer.status
index f79c3c3..8a7efd5 100644
--- a/tests/lib_2/lib_2_analyzer.status
+++ b/tests/lib_2/lib_2_analyzer.status
@@ -20,6 +20,9 @@
[ $compiler == dart2analyzer && !$preview_dart_2 ]
mirrors/metadata_nested_constructor_call_test/none: CompileTimeError
+[ $compiler == dart2analyzer && !$preview_dart_2 && !$strong ]
+mirrors/metadata_allowed_values_test/16: MissingCompileTimeError
+
[ $compiler == dart2analyzer && $strong ]
mirrors/deferred_mirrors_metadata_test: StaticWarning # Issue 28969
mirrors/deferred_type_test: CompileTimeError, OK # Deliberately refers to a deferred type in a declaration.
@@ -37,6 +40,7 @@
mirrors/generic_bounded_test/02: MissingCompileTimeError
mirrors/generic_interface_test/01: MissingCompileTimeError
mirrors/generics_test/01: MissingCompileTimeError
+mirrors/metadata_allowed_values_test/16: MissingCompileTimeError
mirrors/redirecting_factory_different_type_test/01: MissingCompileTimeError
mirrors/reflect_class_test/01: MissingCompileTimeError
mirrors/reflect_class_test/02: MissingCompileTimeError
diff --git a/tests/lib_2/lib_2_dartdevc.status b/tests/lib_2/lib_2_dartdevc.status
index 1d2d4a3..4e43310 100644
--- a/tests/lib_2/lib_2_dartdevc.status
+++ b/tests/lib_2/lib_2_dartdevc.status
@@ -15,7 +15,6 @@
convert/codec1_test: RuntimeError
convert/utf82_test: RuntimeError
html/debugger_test: CompileTimeError
-js/prototype_access_test: RuntimeError
[ $runtime == chrome && ($compiler == dartdevc || $compiler == dartdevk) ]
html/element_animate_test/timing_dict: RuntimeError # Issue 29922
diff --git a/tests/standalone/app_snapshot_share_test.dart b/tests/standalone/app_snapshot_share_test.dart
new file mode 100644
index 0000000..3e80c75
--- /dev/null
+++ b/tests/standalone/app_snapshot_share_test.dart
@@ -0,0 +1,94 @@
+// Copyright (c) 2018, 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:io";
+
+void main(List<String> args) {
+ if (args.contains("--child")) {
+ print("Hello, sharing world!");
+ return;
+ }
+
+ if (!Platform.executable.endsWith("dart_precompiled_runtime")) {
+ return; // Running in JIT or Windows: AOT binaries not available.
+ }
+
+ if (Platform.isAndroid) {
+ return; // SDK tree and dart_bootstrap not available on the test device.
+ }
+
+ var buildDir =
+ Platform.executable.substring(0, Platform.executable.lastIndexOf('/'));
+ var tempDir = Directory.systemTemp.createTempSync("app-shared");
+ var snapshot1Path = tempDir.uri.resolve("hello1.snapshot").toFilePath();
+ var snapshot2Path = tempDir.uri.resolve("hello2.snapshot").toFilePath();
+ var scriptPath = new Directory(buildDir)
+ .uri
+ .resolve("../../tests/standalone/app_snapshot_share_test.dart")
+ .toFilePath();
+
+ var exec = "$buildDir/dart_bootstrap";
+ args = new List<String>();
+ args.add("--deterministic");
+ args.add("--use-blobs");
+ args.add("--snapshot-kind=app-aot");
+ args.add("--snapshot=$snapshot1Path");
+ args.add(scriptPath);
+ print("+ $exec $args");
+ var result = Process.runSync(exec, args);
+ print("Exit code: ${result.exitCode}");
+ print("stdout:");
+ print(result.stdout);
+ print("stderr:");
+ print(result.stderr);
+ if (result.exitCode != 0) {
+ throw "Bad exit code";
+ }
+
+ exec = "$buildDir/dart_bootstrap";
+ args = new List<String>();
+ args.add("--deterministic");
+ args.add("--use-blobs");
+ args.add("--snapshot-kind=app-aot");
+ args.add("--snapshot=$snapshot2Path");
+ args.add("--shared-blobs=$snapshot1Path");
+ args.add(scriptPath);
+ print("+ $exec $args");
+ result = Process.runSync(exec, args);
+ print("Exit code: ${result.exitCode}");
+ print("stdout:");
+ print(result.stdout);
+ print("stderr:");
+ print(result.stderr);
+ if (result.exitCode != 0) {
+ throw "Bad exit code";
+ }
+
+ var sizeWithoutSharing = new File(snapshot1Path).statSync().size;
+ var deltaWhenSharing = new File(snapshot2Path).statSync().size;
+ print("sizeWithoutSharing: $sizeWithoutSharing");
+ print("deltaWhenSharing: $deltaWhenSharing");
+ if (deltaWhenSharing >= sizeWithoutSharing) {
+ throw "Sharing did not shrink size";
+ }
+
+ exec = "$buildDir/dart_precompiled_runtime";
+ args = new List<String>();
+ args.add("--shared-blobs=$snapshot1Path");
+ args.add(snapshot2Path);
+ args.add("--child");
+ print("+ $exec $args");
+ result = Process.runSync(exec, args);
+ print("Exit code: ${result.exitCode}");
+ print("stdout:");
+ print(result.stdout);
+ print("stderr:");
+ print(result.stderr);
+ if (result.exitCode != 0) {
+ throw "Bad exit code";
+ }
+ if (!result.stdout.contains("Hello, sharing world!")) {
+ throw "Missing output";
+ }
+}
diff --git a/tests/standalone_2/app_snapshot_share_test.dart b/tests/standalone_2/app_snapshot_share_test.dart
new file mode 100644
index 0000000..f623875
--- /dev/null
+++ b/tests/standalone_2/app_snapshot_share_test.dart
@@ -0,0 +1,94 @@
+// Copyright (c) 2018, 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:io";
+
+void main(List<String> args) {
+ if (args.contains("--child")) {
+ print("Hello, sharing world!");
+ return;
+ }
+
+ if (!Platform.executable.endsWith("dart_precompiled_runtime")) {
+ return; // Running in JIT or Windows: AOT binaries not available.
+ }
+
+ if (Platform.isAndroid) {
+ return; // SDK tree and dart_bootstrap not available on the test device.
+ }
+
+ var buildDir =
+ Platform.executable.substring(0, Platform.executable.lastIndexOf('/'));
+ var tempDir = Directory.systemTemp.createTempSync("app-shared");
+ var snapshot1Path = tempDir.uri.resolve("hello1.snapshot").toFilePath();
+ var snapshot2Path = tempDir.uri.resolve("hello2.snapshot").toFilePath();
+ var scriptPath = new Directory(buildDir)
+ .uri
+ .resolve("../../tests/standalone_2/app_snapshot_share_test.dart")
+ .toFilePath();
+
+ var exec = "$buildDir/dart_bootstrap";
+ args = new List<String>();
+ args.add("--deterministic");
+ args.add("--use-blobs");
+ args.add("--snapshot-kind=app-aot");
+ args.add("--snapshot=$snapshot1Path");
+ args.add(scriptPath);
+ print("+ $exec $args");
+ var result = Process.runSync(exec, args);
+ print("Exit code: ${result.exitCode}");
+ print("stdout:");
+ print(result.stdout);
+ print("stderr:");
+ print(result.stderr);
+ if (result.exitCode != 0) {
+ throw "Bad exit code";
+ }
+
+ exec = "$buildDir/dart_bootstrap";
+ args = new List<String>();
+ args.add("--deterministic");
+ args.add("--use-blobs");
+ args.add("--snapshot-kind=app-aot");
+ args.add("--snapshot=$snapshot2Path");
+ args.add("--shared-blobs=$snapshot1Path");
+ args.add(scriptPath);
+ print("+ $exec $args");
+ result = Process.runSync(exec, args);
+ print("Exit code: ${result.exitCode}");
+ print("stdout:");
+ print(result.stdout);
+ print("stderr:");
+ print(result.stderr);
+ if (result.exitCode != 0) {
+ throw "Bad exit code";
+ }
+
+ var sizeWithoutSharing = new File(snapshot1Path).statSync().size;
+ var deltaWhenSharing = new File(snapshot2Path).statSync().size;
+ print("sizeWithoutSharing: $sizeWithoutSharing");
+ print("deltaWhenSharing: $deltaWhenSharing");
+ if (deltaWhenSharing >= sizeWithoutSharing) {
+ throw "Sharing did not shrink size";
+ }
+
+ exec = "$buildDir/dart_precompiled_runtime";
+ args = new List<String>();
+ args.add("--shared-blobs=$snapshot1Path");
+ args.add(snapshot2Path);
+ args.add("--child");
+ print("+ $exec $args");
+ result = Process.runSync(exec, args);
+ print("Exit code: ${result.exitCode}");
+ print("stdout:");
+ print(result.stdout);
+ print("stderr:");
+ print(result.stderr);
+ if (result.exitCode != 0) {
+ throw "Bad exit code";
+ }
+ if (!result.stdout.contains("Hello, sharing world!")) {
+ throw "Missing output";
+ }
+}
diff --git a/tools/VERSION b/tools/VERSION
index 5c6fbcc..0a3d56d 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 0
PATCH 0
-PRERELEASE 50
+PRERELEASE 51
PRERELEASE_PATCH 0
diff --git a/tools/observatory_tool.py b/tools/observatory_tool.py
index 654f1f6..28be29b 100755
--- a/tools/observatory_tool.py
+++ b/tools/observatory_tool.py
@@ -8,18 +8,17 @@
import os
import platform
import shutil
-import socket
import subprocess
import sys
import utils
SCRIPT_DIR = os.path.dirname(sys.argv[0])
DART_ROOT = os.path.realpath(os.path.join(SCRIPT_DIR, '..'))
-PUB_PATH = os.path.join(DART_ROOT, 'third_party', 'pkg',
- 'pub', 'bin', 'pub.dart')
+DART2JS_PATH = os.path.join(DART_ROOT, 'pkg', 'compiler', 'bin', 'dart2js.dart')
IGNORE_PATTERNS = shutil.ignore_patterns(
'$sdk',
'*.concat.js',
+ '*.dart',
'*.log',
'*.map',
'*.precompiled.js',
@@ -49,7 +48,7 @@
https://github.com/dart-lang/sdk/wiki/The-checked-in-SDK-in-tools
-To use the dart_bootstrap binary please update the PubCommand function
+To use the dart_bootstrap binary please update the Build function
in the tools/observatory_tool.py script.
"""
@@ -70,17 +69,8 @@
# True, and return the return code.
def RunCommand(command, always_silent=False):
try:
- # Dart IO respects the following environment variables to configure the
- # HttpClient proxy: https://api.dartlang.org/stable/1.22.1/dart-io/HttpClient/findProxyFromEnvironment.html
- # We strip these to avoid problems with pub build and transformers.
- no_http_proxy_env = os.environ.copy()
- no_http_proxy_env.pop('http_proxy', None)
- no_http_proxy_env.pop('HTTP_PROXY', None)
- no_http_proxy_env.pop('https_proxy', None)
- no_http_proxy_env.pop('HTTPS_PROXY', None)
subprocess.check_output(command,
- stderr=subprocess.STDOUT,
- env=no_http_proxy_env)
+ stderr=subprocess.STDOUT)
return 0
except subprocess.CalledProcessError as e:
if not always_silent:
@@ -89,23 +79,15 @@
DisplayFailureMessage()
return e.returncode
-def CreateTimestampFile(options):
- if options.stamp != '':
- dir_name = os.path.dirname(options.stamp)
- if dir_name != '':
- if not os.path.exists(dir_name):
- os.mkdir(dir_name)
- open(options.stamp, 'w').close()
-
def BuildArguments():
result = argparse.ArgumentParser(usage=usage)
result.add_argument("--dart-executable", help="dart executable", default=None)
- result.add_argument("--pub-executable", help="pub executable", default=None)
+ result.add_argument("--dart2js-executable", help="dart2js executable",
+ default=None)
result.add_argument("--directory", help="observatory root", default=None)
- result.add_argument("--command", help="[get, build, deploy]", default=None)
+ result.add_argument("--command", help="[build, deploy]", default=None)
result.add_argument("--silent", help="silence all output", default=None)
result.add_argument("--sdk", help="Use prebuilt sdk", default=None)
- result.add_argument("--stamp", help="Write a stamp file", default='')
return result
def ProcessOptions(options, args):
@@ -130,113 +112,97 @@
if options.command is None or options.directory is None:
return False
- # Set a default value for pub_snapshot.
- options.pub_snapshot = None
-
- # If we have a working pub executable, try and use that.
- # TODO(whesse): Drop the pub-executable option if it isn't used.
- if options.pub_executable is not None:
+ # If a dart2js execuble was provided, try and use that.
+ # TODO(whesse): Drop the dart2js-executable option if it isn't used.
+ if options.dart2js_executable is not None:
try:
- if 0 == RunCommand([options.pub_executable, '--version'],
+ if 0 == RunCommand([options.dart2js_executable, '--version'],
always_silent=True):
return True
except OSError as e:
pass
- options.pub_executable = None
+ options.dart2js_executable = None
+ # Use the checked in dart2js executable.
if options.sdk and utils.CheckedInSdkCheckExecutable():
- # Use the checked in pub executable.
- options.pub_snapshot = os.path.join(utils.CheckedInSdkPath(),
- 'bin',
- 'snapshots',
- 'pub.dart.snapshot');
+ dart2js_binary = 'dart2js.bat' if utils.IsWindows() else 'dart2js'
+ options.dart2js_executable = os.path.join(utils.CheckedInSdkPath(),
+ 'bin',
+ dart2js_binary)
try:
- if 0 == RunCommand([utils.CheckedInSdkExecutable(),
- options.pub_snapshot,
- '--version'], always_silent=True):
+ if 0 == RunCommand([options.dart2js_executable, '--version'],
+ always_silent=True):
return True
except OSError as e:
pass
- options.pub_snapshot = None
+ options.dart2js_executable = None
- # We need a dart executable.
+ # We need a dart executable and will run from source
return (options.dart_executable is not None)
def ChangeDirectory(directory):
os.chdir(directory);
-def PubCommand(dart_executable,
- pub_executable,
- pub_snapshot,
- command,
- silent):
- if pub_executable is not None:
- executable = [pub_executable]
- elif pub_snapshot is not None:
- executable = [utils.CheckedInSdkExecutable(), pub_snapshot]
+# - Copy over the filtered web directory
+# - Merge in the .js file
+# - Copy over the filtered dependency lib directories
+# - Copy over the filtered observatory package
+def Deploy(output_dir, web_dir, observatory_lib, js_file, pub_packages_dir):
+ shutil.rmtree(output_dir)
+ os.makedirs(output_dir)
+
+ output_web_dir = os.path.join(output_dir, 'web')
+ shutil.copytree(web_dir, output_web_dir, ignore=IGNORE_PATTERNS)
+ os.utime(os.path.join(output_web_dir, 'index.html'), None)
+
+ shutil.copy(js_file, output_web_dir)
+
+ packages_dir = os.path.join(output_web_dir, 'packages')
+ os.makedirs(packages_dir)
+ for subdir in os.listdir(pub_packages_dir):
+ libdir = os.path.join(pub_packages_dir, subdir, 'lib')
+ if os.path.isdir(libdir):
+ shutil.copytree(libdir, os.path.join(packages_dir, subdir),
+ ignore=IGNORE_PATTERNS)
+ shutil.copytree(observatory_lib, os.path.join(packages_dir, 'observatory'),
+ ignore=IGNORE_PATTERNS)
+
+def Build(dart_executable,
+ dart2js_executable,
+ script_path,
+ output_path,
+ packages_path,
+ silent):
+ if dart2js_executable is not None:
+ command = [dart2js_executable]
else:
if not silent:
DisplayBootstrapWarning()
- executable = [dart_executable, PUB_PATH]
- # Prevent the bootstrap Dart executable from running in regular
- # development flow.
- # REMOVE THE FOLLOWING LINE TO USE the dart_bootstrap binary.
- # return False
+ command = [dart_executable, DART2JS_PATH]
+ command += ['-DOBS_VER=' + utils.GetVersion(no_git_hash=True)]
+ command += [script_path, '-o', output_path, '--packages=%s' % packages_path]
+ # Add the defaults pub used
+ command += ['--minify']
if not silent:
- print >> sys.stderr, ('Running command "%s"') % (executable + command)
- return RunCommand(executable + command)
-
-def Deploy(input_dir, output_dir):
- shutil.rmtree(output_dir)
- shutil.copytree(input_dir, output_dir, ignore=IGNORE_PATTERNS)
- index_file = os.path.join(output_dir, 'web', 'index.html')
- os.utime(index_file, None)
- return 0
-
-def RewritePubSpec(input_path, output_path, search, replace):
- with open(input_path, 'rb') as input_file:
- input_data = input_file.read()
- input_data = input_data.replace(search, replace)
- with open(output_path, 'wb+') as output_file:
- output_file.write(input_data)
+ print >> sys.stderr, 'Running command "%s"' % command
+ return RunCommand(command)
def ExecuteCommand(options, args):
cmd = options.command
- if (cmd == 'get'):
- # Always remove pubspec.lock before running 'pub get'.
- try:
- os.remove('pubspec.lock');
- except OSError as e:
- pass
- return PubCommand(options.dart_executable,
- options.pub_executable,
- options.pub_snapshot,
- ['get', '--offline'],
- options.silent)
- elif (cmd == 'build'):
- return PubCommand(options.dart_executable,
- options.pub_executable,
- options.pub_snapshot,
- ['build',
- '-DOBS_VER=' + utils.GetVersion(no_git_hash=True),
- '--output', args[0]],
- options.silent)
+ if (cmd == 'build'):
+ return Build(options.dart_executable,
+ options.dart2js_executable,
+ args[0],
+ args[1],
+ args[2],
+ options.silent)
elif (cmd == 'deploy'):
- Deploy('build', 'deployed')
- elif (cmd == 'rewrite'):
- RewritePubSpec(args[0], args[1], args[2], args[3])
+ Deploy(args[0], args[1], args[2], args[3], args[4])
else:
print >> sys.stderr, ('ERROR: command "%s" not supported') % (cmd)
return -1;
def main():
- # Sanity check that localhost can be resolved.
- try:
- socket.gethostbyname('localhost')
- except:
- print("The hostname 'localhost' could not be resolved. Please fix your"
- "/etc/hosts file and try again")
- return -1
# Parse the options.
parser = BuildArguments()
(options, args) = parser.parse_known_args()
@@ -246,24 +212,16 @@
# Calculate absolute paths before changing directory.
if (options.dart_executable != None):
options.dart_executable = os.path.abspath(options.dart_executable)
- if (options.pub_executable != None):
- options.pub_executable = os.path.abspath(options.pub_executable)
- if (options.pub_snapshot != None):
- options.pub_snapshot = os.path.abspath(options.pub_snapshot)
- if (options.stamp != ''):
- options.stamp = os.path.abspath(options.stamp)
+ if (options.dart2js_executable != None):
+ options.dart2js_executable = os.path.abspath(options.dart2js_executable)
if len(args) == 1:
args[0] = os.path.abspath(args[0])
try:
# Pub must be run from the project's root directory.
ChangeDirectory(options.directory)
- result = ExecuteCommand(options, args)
- if result == 0:
- CreateTimestampFile(options)
- return result
+ return ExecuteCommand(options, args)
except:
DisplayFailureMessage()
-
if __name__ == '__main__':
sys.exit(main());
diff --git a/tools/testing/dart/compiler_configuration.dart b/tools/testing/dart/compiler_configuration.dart
index 0b7c602..0b5b805 100644
--- a/tools/testing/dart/compiler_configuration.dart
+++ b/tools/testing/dart/compiler_configuration.dart
@@ -1004,6 +1004,8 @@
}
if (_isStrong) {
arguments.add('--strong');
+ } else {
+ arguments.add('--no-strong');
}
// Since this is not a real compilation, no artifacts are produced.
diff --git a/tools/testing/dart/multitest.dart b/tools/testing/dart/multitest.dart
index ed10d09..f918d98 100644
--- a/tools/testing/dart/multitest.dart
+++ b/tools/testing/dart/multitest.dart
@@ -281,11 +281,10 @@
}
}
-// Find all relative imports and copy them into the dir that contains
-// the generated tests.
+/// Finds all relative imports and copies them into the directory with the
+/// generated tests.
Set<String> _findAllRelativeImports(Path topLibrary) {
- var toSearch = [topLibrary].toSet();
- var foundImports = new Set<String>();
+ var found = new Set<String>();
var libraryDir = topLibrary.directoryPath;
var relativeImportRegExp = new RegExp(
'^(?:@.*\\s+)?' // Allow for a meta-data annotation.
@@ -294,36 +293,36 @@
'(?!(dart:|dart-ext:|data:|package:|/))' // Look-ahead: not in package.
'([^"\']*)' // The path to the imported file.
'["\']');
- while (!toSearch.isEmpty) {
- var thisPass = toSearch;
- toSearch = new Set<Path>();
- for (var filename in thisPass) {
- var f = new File(filename.toNativePath());
- for (var line in f.readAsLinesSync()) {
- var match = relativeImportRegExp.firstMatch(line);
- if (match != null) {
- var relativePath = new Path(match.group(3));
- if (foundImports.contains(relativePath.toString())) {
- continue;
- }
+ processFile(Path filePath) {
+ var file = new File(filePath.toNativePath());
+ for (var line in file.readAsLinesSync()) {
+ var match = relativeImportRegExp.firstMatch(line);
+ if (match == null) continue;
+ var relativePath = match.group(3);
- if (relativePath.toString().contains('..')) {
- // This is just for safety reasons, we don't want
- // to unintentionally clobber files relative to the destination
- // dir when copying them over.
- print("relative paths containing '..' are not allowed.");
- exit(1);
- }
+ // If a multitest deliberately imports a non-existent file, don't try to
+ // include it.
+ if (relativePath.contains("nonexistent")) continue;
- foundImports.add(relativePath.toString());
- toSearch.add(libraryDir.join(relativePath));
- }
+ // Handle import cycles.
+ if (!found.add(relativePath)) continue;
+
+ if (relativePath.contains("..")) {
+ // This is just for safety reasons, we don't want to unintentionally
+ // clobber files relative to the destination dir when copying them
+ // over.
+ print("Relative import in multitest containing '..' is not allowed.");
+ exit(1);
}
+
+ processFile(libraryDir.append(relativePath));
}
}
- return foundImports;
+ processFile(topLibrary);
+
+ return found;
}
String _suiteNameFromPath(Path suiteDir) {
diff --git a/tools/testing/dart/options.dart b/tools/testing/dart/options.dart
index 93f6d44..f20dbfd 100644
--- a/tools/testing/dart/options.dart
+++ b/tools/testing/dart/options.dart
@@ -166,11 +166,8 @@
'Only run tests that are not marked `Slow` or `Timeout`.'),
new _Option.bool('enable_asserts',
'Pass the --enable-asserts flag to dart2js or to the vm.'),
- new _Option.bool(
- 'no-preview_dart_2', 'Pass the --no-preview-dart-2 flag to analyzer.',
- hide: true),
- new _Option.bool(
- 'preview_dart_2', 'Pass the --preview-dart-2 flag to analyzer.',
+ new _Option.bool('preview_dart_2',
+ 'Pass the --preview-dart-2 flag to analyzer, or pass --no-preview-dart-2 if false.',
hide: true),
// TODO(sigmund): replace dart2js_with_kernel with preview-dart-2.
new _Option.bool(
@@ -644,7 +641,7 @@
isVerbose: data["verbose"] as bool,
listTests: data["list"] as bool,
listStatusFiles: data["list_status_files"] as bool,
- noPreviewDart2: data["no-preview_dart_2"] as bool,
+ noPreviewDart2: !(data["preview_dart_2"] as bool),
previewDart2: data["preview_dart_2"] as bool,
printTiming: data["time"] as bool,
printReport: data["report"] as bool,