Version 1.13.0-dev.6.0
Merge commit '3abd6ad7583fa0e87158fddbdc7668c851874e5f' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e6e2695..2f9aadf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,26 +1,40 @@
## 1.13.0
+### Core library changes
+* `dart:async`
+ * `StreamTransformer` instances created with `fromHandlers` with no
+ `handleError` callback now forward stack traces along with errors to the
+ resulting streams.
+
* `dart:core`
* `Uri` added `removeFragment` method.
* `String.allMatches` (implementing `Pattern.allMatches`) is now lazy,
as all `allMatches` implementations are intended to be.
+ * `Resource` is deprecated in favor of the resource package.
+ See https://pub.dartlang.org/packages/resource to learn more. This is
+ the last release to contain the Resource class.
* `dart:io`
* `HttpClient` no longer sends URI fragments in the request. This is not
allowed by the HTTP protocol.
The `HttpServer` still gracefully receives fragments, but discards them
before delivering the request.
-
-* `dart:async`
- * `StreamTransformer`s created with `fromHandlers` with no `handleError`
- callback now forward stack traces along with errors to the resulting
- streams.
+ * Removed server socket references. The use of server socket references
+ was deprecated back in 1.9. Use the `shared` flag when creating listening
+ sockets and `HttpServer` to distribute accepted sockets between isolates.
### Tool changes
* `docgen` and 'dartdocgen' no longer ship in the sdk. The `docgen` sources have
been removed from the repository.
+* This is the last release to ship the VM's "legacy debug protocol".
+ We intend to remove the legacy debug protocol in Dart VM 1.14.
+
+* The VM's Service Protocol has been updated to version 3.0 to take care
+ of a number of issues uncovered by the first few non-observatory
+ clients. This is a potentially breaking change for clients.
+
## 1.12.0
### Language changes
diff --git a/DEPS b/DEPS
index 9cb65e6..ac30916 100644
--- a/DEPS
+++ b/DEPS
@@ -38,7 +38,7 @@
# Revisions of /third_party/* dependencies.
"7zip_rev" : "@19997",
- "analyzer_cli_rev" : "@0b89a16c0566f36676fa8f2016eb2c332178f616",
+ "analyzer_cli_rev" : "@c8a60be821be07df64cde2efb8f87b462a91a521",
"args_tag": "@0.13.0",
"async_tag": "@1.2.0",
"barback_tag" : "@0.15.2+7",
@@ -50,8 +50,8 @@
"collection_rev": "@1da9a07f32efa2ba0c391b289e2037391e31da0e",
"crypto_rev" : "@2df57a1e26dd88e8d0614207d4b062c73209917d",
"csslib_tag" : "@0.12.0",
- "dart2js_info_rev" : "@bad01369f1f605ab688d505c135db54de927318f",
- "dartdoc_rev" : "@786426c4bbea96729d5eab2add744def41a5a690",
+ "dart2js_info_rev" : "@ffd03ee45f7459efd3039ff565b4d0aa2e7cd9e7",
+ "dartdoc_rev" : "@d51211b7c0a30862a691aa6dc0631009bd926004",
"dart_services_rev" : "@7aea2574e6f3924bf409a80afb8ad52aa2be4f97",
"dart_style_tag": "@0.2.0",
"dev_compiler_rev": "@0.1.8",
diff --git a/codereview.settings b/codereview.settings
index 3e78887..ada9e3c 100644
--- a/codereview.settings
+++ b/codereview.settings
@@ -1,4 +1,4 @@
# This file is used by gcl to get repository specific information.
-CODE_REVIEW_SERVER: http://codereview.chromium.org/
+CODE_REVIEW_SERVER: http://codereview.chromium.org
VIEW_VC: https://github.com/dart-lang/sdk/commit/
CC_LIST: reviews@dartlang.org
diff --git a/pkg/analysis_server/benchmark/perf/analysis_timing_tests.dart b/pkg/analysis_server/benchmark/perf/analysis_timing_tests.dart
index fd50e13..6f7a3c6 100644
--- a/pkg/analysis_server/benchmark/perf/analysis_timing_tests.dart
+++ b/pkg/analysis_server/benchmark/perf/analysis_timing_tests.dart
@@ -7,43 +7,82 @@
import 'dart:async';
import 'dart:io';
+import 'package:analysis_server/src/protocol.dart';
import 'package:args/args.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:unittest/unittest.dart';
import '../../test/utils.dart';
import 'performance_tests.dart';
-const String SOURCE_OPTION = 'source';
-
/**
- * Pass in the directory of the source to be analyzed as option --source
+ * Pass in the directory of the source to be analyzed as option `--source`,
+ * optionally specify a priority file with `--priority` and the specific
+ * test to run with `--test`. If no test is specified, the default is
+ * `analysis`.
*/
-main(List<String> arguements) {
+main(List<String> arguments) {
initializeTestEnvironment();
ArgParser parser = _createArgParser();
- var args = parser.parse(arguements);
+ var args = parser.parse(arguments);
if (args[SOURCE_OPTION] == null) {
print('path to source directory must be specified');
exit(1);
}
source = args[SOURCE_OPTION];
- defineReflectiveTests(AnalysisTimingIntegrationTest);
+ priorityFile = args[PRIORITY_FILE_OPTION];
+ testName = args[TEST_NAME_OPTION] ?? DEFAULT_TEST;
+
+ switch (testName) {
+ case 'analysis':
+ defineReflectiveTests(AnalysisTimingIntegrationTest);
+ break;
+ case 'highlighting':
+ defineReflectiveTests(HighlightingTimingIntegrationTest);
+ break;
+ case 'navigation':
+ defineReflectiveTests(NavigationTimingIntegrationTest);
+ break;
+ case 'outline':
+ defineReflectiveTests(OutlineTimingIntegrationTest);
+ break;
+ default:
+ print('unrecognized test name $testName');
+ exit(1);
+ }
}
+const DEFAULT_TEST = 'analysis';
+const PRIORITY_FILE_OPTION = 'priority';
+const SOURCE_OPTION = 'source';
+const TEST_NAME_OPTION = 'test';
+
+String priorityFile;
String source;
+String testName;
+
+ArgParser _createArgParser() => new ArgParser()
+ ..addOption(TEST_NAME_OPTION, help: 'test name (defaults to `analysis`)')
+ ..addOption(SOURCE_OPTION, help: 'full path to source directory for analysis')
+ ..addOption(PRIORITY_FILE_OPTION,
+ help: '(optional) full path to a priority file');
+
+class AbstractTimingTest extends AbstractAnalysisServerPerformanceTest {
+ @override
+ Future setUp() => super.setUp().then((_) {
+ sourceDirectory = new Directory(source);
+ subscribeToStatusNotifications();
+ });
+}
@reflectiveTest
-class AnalysisTimingIntegrationTest
- extends AbstractAnalysisServerPerformanceTest {
+class AnalysisTimingIntegrationTest extends AbstractTimingTest {
test_detect_analysis_done() {
- sourceDirectory = new Directory(source);
- subscribeToStatusNotifications();
- return _runAndTimeAnalysis();
- }
-
- Future _runAndTimeAnalysis() {
stopwatch.start();
setAnalysisRoot();
+ if (priorityFile != null) {
+ sendAnalysisSetPriorityFiles([priorityFile]);
+ }
return analysisFinished.then((_) {
print('analysis completed in ${stopwatch.elapsed}');
stopwatch.reset();
@@ -51,9 +90,67 @@
}
}
-ArgParser _createArgParser() {
- ArgParser parser = new ArgParser();
- parser.addOption('source',
- help: 'full path to source directory for analysis');
- return parser;
+@reflectiveTest
+class HighlightingTimingIntegrationTest extends PriorityFileTimer {
+ @override
+ String get description => 'highlighting';
+
+ @override
+ Stream get eventStream => onAnalysisHighlights;
+
+ @override
+ AnalysisService get service => AnalysisService.HIGHLIGHTS;
+}
+
+@reflectiveTest
+class NavigationTimingIntegrationTest extends PriorityFileTimer {
+ @override
+ String get description => 'navigation';
+
+ @override
+ Stream get eventStream => onAnalysisNavigation;
+
+ @override
+ AnalysisService get service => AnalysisService.NAVIGATION;
+}
+
+@reflectiveTest
+class OutlineTimingIntegrationTest extends PriorityFileTimer {
+ @override
+ String get description => 'outline';
+
+ @override
+ Stream get eventStream => onAnalysisOutline;
+
+ @override
+ AnalysisService get service => AnalysisService.OUTLINE;
+}
+
+abstract class PriorityFileTimer extends AbstractTimingTest {
+ String get description;
+ Stream get eventStream;
+ AnalysisService get service;
+
+ Future test_timing() {
+ expect(priorityFile, isNotNull,
+ reason: 'A priority file must be specified for $description testing.');
+ stopwatch.start();
+
+ Duration elapsed;
+ eventStream.listen((_) {
+ elapsed = stopwatch.elapsed;
+ });
+
+ setAnalysisRoot();
+ sendAnalysisSetSubscriptions({
+ service: [priorityFile]
+ });
+
+ sendAnalysisSetPriorityFiles([priorityFile]);
+
+ return analysisFinished.then((_) {
+ print('$description completed in ${elapsed}');
+ stopwatch.reset();
+ });
+ }
}
diff --git a/pkg/analysis_server/benchmark/perf/performance_tests.dart b/pkg/analysis_server/benchmark/perf/performance_tests.dart
index a926e33..3dd1842 100644
--- a/pkg/analysis_server/benchmark/perf/performance_tests.dart
+++ b/pkg/analysis_server/benchmark/perf/performance_tests.dart
@@ -25,9 +25,8 @@
* Send the server an 'analysis.setAnalysisRoots' command directing it to
* analyze [sourceDirectory].
*/
- Future setAnalysisRoot() {
- return sendAnalysisSetAnalysisRoots([sourceDirectory.path], []);
- }
+ Future setAnalysisRoot() =>
+ sendAnalysisSetAnalysisRoots([sourceDirectory.path], []);
/**
* Enable [SERVER_STATUS] notifications so that [analysisFinished]
@@ -69,7 +68,5 @@
* After every test, the server is stopped.
*/
@override
- Future tearDown() {
- return shutdownIfNeeded();
- }
+ Future tearDown() => shutdownIfNeeded();
}
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 52b4419..69a9f87 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -61,7 +61,7 @@
</style></head>
<body>
<h1>Analysis Server API Specification</h1>
- <h1 style="color:#999999">Version 1.9.0</h1>
+ <h1 style="color:#999999">Version 1.12.0</h1>
<p>
This document contains a specification of the API provided by the
analysis server. The API in this document is currently under
@@ -1200,6 +1200,8 @@
"event": "analysis.outline"
"params": {
"<b>file</b>": <a href="#type_FilePath">FilePath</a>
+ "<b>kind</b>": <a href="#type_FileKind">FileKind</a>
+ "<b>libraryName</b>": <span style="color:#999999">optional</span> String
"<b>outline</b>": <a href="#type_Outline">Outline</a>
}
}</pre></div>
@@ -1218,6 +1220,21 @@
<p>
The file with which the outline is associated.
</p>
+ </dd><dt class="field"><b><i>kind ( <a href="#type_FileKind">FileKind</a> )</i></b></dt><dd>
+
+ <p>
+ The kind of the file.
+ </p>
+ </dd><dt class="field"><b><i>libraryName ( <span style="color:#999999">optional</span> String )</i></b></dt><dd>
+
+ <p>
+ The name of the library defined by the file using a "library"
+ directive, or referenced by a "part of" directive. If both
+ "library" and "part of" directives are present, then the
+ "library" directive takes precedence.
+ This field will be omitted if the file has neither "library"
+ nor "part of" directives.
+ </p>
</dd><dt class="field"><b><i>outline ( <a href="#type_Outline">Outline</a> )</i></b></dt><dd>
<p>
@@ -2309,6 +2326,7 @@
+
<dl><dt class="typeDefinition"><a name="type_AddContentOverlay">AddContentOverlay: object</a></dt><dd>
<p>
A directive to begin overlaying the contents of a file. The
@@ -2362,6 +2380,20 @@
the error. The field is omitted if there is no correction
message associated with the error code.
</p>
+ </dd><dt class="field"><b><i>hasFix ( <span style="color:#999999">optional</span> bool )</i></b></dt><dd>
+
+ <p>
+ A hint to indicate to interested clients that this error has
+ an associated fix (or fixes). The absence of this field implies
+ there are not known to be fixes. Note that since the operation
+ to calculate whether fixes apply needs to be performant it is
+ possible that complicated tests will be skipped and a false
+ negative returned. For this reason, this attribute should be
+ treated as a "hint". Despite the possibility of false negatives,
+ no false positives should be returned. If a client sees this
+ flag set they can proceed with the confidence that there are in
+ fact associated fixes.
+ </p>
</dd></dl></dd><dt class="typeDefinition"><a name="type_AnalysisErrorFixes">AnalysisErrorFixes: object</a></dt><dd>
<p>
A list of fixes associated with a specific error
@@ -2775,7 +2807,12 @@
domain.
</p>
- <dl><dt class="value">LAUNCH_DATA</dt></dl></dd><dt class="typeDefinition"><a name="type_FilePath">FilePath: String</a></dt><dd>
+ <dl><dt class="value">LAUNCH_DATA</dt></dl></dd><dt class="typeDefinition"><a name="type_FileKind">FileKind: String</a></dt><dd>
+ <p>
+ An enumeration of the kinds of files.
+ </p>
+
+ <dl><dt class="value">LIBRARY</dt><dt class="value">PART</dt></dl></dd><dt class="typeDefinition"><a name="type_FilePath">FilePath: String</a></dt><dd>
<p>
The absolute path of a file.
@@ -3918,16 +3955,28 @@
</p>
<h4>Feedback</h4><p>none</p><h4>Options</h4><p>none</p></dd><dt class="refactoring">EXTRACT_LOCAL_VARIABLE</dt><dd>
<p>
- Create a local variable initialized by a specified
- expression.
+ Create a local variable initialized by the expression that covers
+ the specified selection.
</p>
<p>
- It is an error if the range contains anything other than a
- complete expression (no partial expressions are allowed).
+ It is an error if the selection range is not covered by a
+ complete expression.
</p>
- <h4>Feedback</h4><dl><dt class="field"><b><i>names ( List<String> )</i></b></dt><dd>
+ <h4>Feedback</h4><dl><dt class="field"><b><i>coveringExpressionOffsets ( List<int> )</i></b></dt><dd>
+
+ <p>
+ The offsets of the expressions that cover the specified
+ selection, from the down most to the up most.
+ </p>
+ </dd><dt class="field"><b><i>coveringExpressionLengths ( List<int> )</i></b></dt><dd>
+
+ <p>
+ The lengths of the expressions that cover the specified
+ selection, from the down most to the up most.
+ </p>
+ </dd><dt class="field"><b><i>names ( List<String> )</i></b></dt><dd>
<p>
The proposed names for the local variable.
@@ -4202,7 +4251,7 @@
TBD
</p>
<h2 class="domain"><a name="index">Index</a></h2>
- <h3>Domains</h3><h4>server (<a href="#domain_server">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_server.getVersion">getVersion</a></li><li><a href="#request_server.shutdown">shutdown</a></li><li><a href="#request_server.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_server.connected">connected</a></li><li><a href="#notification_server.error">error</a></li><li><a href="#notification_server.status">status</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getErrors">getErrors</a></li><li><a href="#request_analysis.getHover">getHover</a></li><li><a href="#request_analysis.getLibraryDependencies">getLibraryDependencies</a></li><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setAnalysisRoots">setAnalysisRoots</a></li><li><a href="#request_analysis.setGeneralSubscriptions">setGeneralSubscriptions</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li><li><a href="#request_analysis.updateOptions">updateOptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.analyzedFiles">analyzedFiles</a></li><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.flushResults">flushResults</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.implemented">implemented</a></li><li><a href="#notification_analysis.invalidate">invalidate</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li><li><a href="#notification_analysis.overrides">overrides</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_completion.results">results</a></li></ul></div></div><h4>search (<a href="#domain_search">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_search.findElementReferences">findElementReferences</a></li><li><a href="#request_search.findMemberDeclarations">findMemberDeclarations</a></li><li><a href="#request_search.findMemberReferences">findMemberReferences</a></li><li><a href="#request_search.findTopLevelDeclarations">findTopLevelDeclarations</a></li><li><a href="#request_search.getTypeHierarchy">getTypeHierarchy</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_search.results">results</a></li></ul></div></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.format">format</a></li><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getAvailableRefactorings">getAvailableRefactorings</a></li><li><a href="#request_edit.getFixes">getFixes</a></li><li><a href="#request_edit.getRefactoring">getRefactoring</a></li><li><a href="#request_edit.sortMembers">sortMembers</a></li><li><a href="#request_edit.organizeDirectives">organizeDirectives</a></li></ul></div><h4>execution (<a href="#domain_execution">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_execution.createContext">createContext</a></li><li><a href="#request_execution.deleteContext">deleteContext</a></li><li><a href="#request_execution.mapUri">mapUri</a></li><li><a href="#request_execution.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_execution.launchData">launchData</a></li></ul></div></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisOptions">AnalysisOptions</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_AnalysisStatus">AnalysisStatus</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_CompletionId">CompletionId</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_ExecutableFile">ExecutableFile</a></li><li><a href="#type_ExecutableKind">ExecutableKind</a></li><li><a href="#type_ExecutionContextId">ExecutionContextId</a></li><li><a href="#type_ExecutionService">ExecutionService</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_GeneralAnalysisService">GeneralAnalysisService</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_HoverInformation">HoverInformation</a></li><li><a href="#type_ImplementedClass">ImplementedClass</a></li><li><a href="#type_ImplementedMember">ImplementedMember</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_Override">Override</a></li><li><a href="#type_OverriddenMember">OverriddenMember</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PubStatus">PubStatus</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringFeedback">RefactoringFeedback</a></li><li><a href="#type_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_SearchId">SearchId</a></li><li><a href="#type_SearchResult">SearchResult</a></li><li><a href="#type_SearchResultKind">SearchResultKind</a></li><li><a href="#type_ServerService">ServerService</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_TypeHierarchyItem">TypeHierarchyItem</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
+ <h3>Domains</h3><h4>server (<a href="#domain_server">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_server.getVersion">getVersion</a></li><li><a href="#request_server.shutdown">shutdown</a></li><li><a href="#request_server.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_server.connected">connected</a></li><li><a href="#notification_server.error">error</a></li><li><a href="#notification_server.status">status</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getErrors">getErrors</a></li><li><a href="#request_analysis.getHover">getHover</a></li><li><a href="#request_analysis.getLibraryDependencies">getLibraryDependencies</a></li><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setAnalysisRoots">setAnalysisRoots</a></li><li><a href="#request_analysis.setGeneralSubscriptions">setGeneralSubscriptions</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li><li><a href="#request_analysis.updateOptions">updateOptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.analyzedFiles">analyzedFiles</a></li><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.flushResults">flushResults</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.implemented">implemented</a></li><li><a href="#notification_analysis.invalidate">invalidate</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li><li><a href="#notification_analysis.overrides">overrides</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_completion.results">results</a></li></ul></div></div><h4>search (<a href="#domain_search">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_search.findElementReferences">findElementReferences</a></li><li><a href="#request_search.findMemberDeclarations">findMemberDeclarations</a></li><li><a href="#request_search.findMemberReferences">findMemberReferences</a></li><li><a href="#request_search.findTopLevelDeclarations">findTopLevelDeclarations</a></li><li><a href="#request_search.getTypeHierarchy">getTypeHierarchy</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_search.results">results</a></li></ul></div></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.format">format</a></li><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getAvailableRefactorings">getAvailableRefactorings</a></li><li><a href="#request_edit.getFixes">getFixes</a></li><li><a href="#request_edit.getRefactoring">getRefactoring</a></li><li><a href="#request_edit.sortMembers">sortMembers</a></li><li><a href="#request_edit.organizeDirectives">organizeDirectives</a></li></ul></div><h4>execution (<a href="#domain_execution">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_execution.createContext">createContext</a></li><li><a href="#request_execution.deleteContext">deleteContext</a></li><li><a href="#request_execution.mapUri">mapUri</a></li><li><a href="#request_execution.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_execution.launchData">launchData</a></li></ul></div></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisOptions">AnalysisOptions</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_AnalysisStatus">AnalysisStatus</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_CompletionId">CompletionId</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_ExecutableFile">ExecutableFile</a></li><li><a href="#type_ExecutableKind">ExecutableKind</a></li><li><a href="#type_ExecutionContextId">ExecutionContextId</a></li><li><a href="#type_ExecutionService">ExecutionService</a></li><li><a href="#type_FileKind">FileKind</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_GeneralAnalysisService">GeneralAnalysisService</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_HoverInformation">HoverInformation</a></li><li><a href="#type_ImplementedClass">ImplementedClass</a></li><li><a href="#type_ImplementedMember">ImplementedMember</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_Override">Override</a></li><li><a href="#type_OverriddenMember">OverriddenMember</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PubStatus">PubStatus</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringFeedback">RefactoringFeedback</a></li><li><a href="#type_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_SearchId">SearchId</a></li><li><a href="#type_SearchResult">SearchResult</a></li><li><a href="#type_SearchResultKind">SearchResultKind</a></li><li><a href="#type_ServerService">ServerService</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_TypeHierarchyItem">TypeHierarchyItem</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
</body></html>
\ No newline at end of file
diff --git a/pkg/analysis_server/lib/analysis/index_core.dart b/pkg/analysis_server/lib/analysis/index_core.dart
index aac9d8a..58e996e 100644
--- a/pkg/analysis_server/lib/analysis/index_core.dart
+++ b/pkg/analysis_server/lib/analysis/index_core.dart
@@ -12,6 +12,16 @@
import 'package:analyzer/src/generated/source.dart';
/**
+ * Return the integer value that corresponds to the given [string]. The value of
+ * [string] may be `null`.
+ *
+ * Clients are not expected to implement this signature. A function of this type
+ * is provided by the framework to clients in order to implement the method
+ * [IndexableObjectKind.encodeHash].
+ */
+typedef int StringToInt(String string);
+
+/**
* An object that can have a [Relationship] with various [Location]s in a code
* base. The object is abstractly represented by a [kind] and an [offset] within
* a [source].
@@ -29,17 +39,6 @@
IndexableObjectKind get kind;
/**
- * Return the length of the indexable object within its source.
- */
- int get length;
-
- /**
- * Return the name of this element.
- */
- // TODO(brianwilkerson) Remove the need for this getter.
- String get name;
-
- /**
* Return the offset of the indexable object within its source.
*/
int get offset;
@@ -88,6 +87,27 @@
IndexableObject decode(AnalysisContext context, String filePath, int offset);
/**
+ * Returns the hash value that corresponds to the given [indexable].
+ *
+ * This hash is used to remember buckets with relations of the given
+ * [indexable]. Usually the name of the indexable object is encoded
+ * using [stringToInt] and mixed with other information to produce the final
+ * result.
+ *
+ * Clients must ensure that the same value is returned for the same object.
+ *
+ * Returned values must have good selectivity, e.g. if it is possible that
+ * there are many different objects with the same name, then additional
+ * information should be mixed in, for example the hash of the source that
+ * declares the given [indexable].
+ *
+ * Clients don't have to use name to compute this result, so if an indexable
+ * object does not have a name, some other value may be returned, but it still
+ * must be always the same for the same object and have good selectivity.
+ */
+ int encodeHash(StringToInt stringToInt, IndexableObject indexable);
+
+ /**
* Return the object kind with the given [index].
*/
static IndexableObjectKind getKind(int index) {
@@ -121,20 +141,6 @@
void contributeTo(IndexStore store, AnalysisContext context, Object object);
}
-// A sketch of what the driver routine might look like:
-//
-//void buildIndexForSource(AnalysisContext context, Source source) {
-// IndexStoreImpl store;
-// store.aboutToIndex(context, source);
-// try {
-// for (IndexContributor contributor in contributors) {
-// contributor.contributeTo(store, context, source);
-// }
-// } finally {
-// store.doneIndexing();
-// }
-//}
-
/**
* An object that stores information about the relationships between locations
* in a code base.
diff --git a/pkg/analysis_server/lib/analysis/navigation_core.dart b/pkg/analysis_server/lib/analysis/navigation_core.dart
index e2f56f8..2e2623d 100644
--- a/pkg/analysis_server/lib/analysis/navigation_core.dart
+++ b/pkg/analysis_server/lib/analysis/navigation_core.dart
@@ -25,8 +25,7 @@
}
/**
- * An object that [NavigationContributor]s use to record navigation regions
- * into.
+ * An object that [NavigationContributor]s use to record navigation regions.
*
* Clients are not expected to subtype this class.
*/
diff --git a/pkg/analysis_server/lib/plugin/occurrences.dart b/pkg/analysis_server/lib/plugin/occurrences.dart
index 5339ccc..eaabc26 100644
--- a/pkg/analysis_server/lib/plugin/occurrences.dart
+++ b/pkg/analysis_server/lib/plugin/occurrences.dart
@@ -5,6 +5,23 @@
/**
* Support for client code that extends the analysis server by adding new
* occurrences contributors.
+ *
+ * Plugins can register occurrences contributors. The registered contributors
+ * will be used to get occurrence information any time the server is about to
+ * send an 'analysis.occurrences' notification.
+ *
+ * If a plugin wants to add occurrence information, it should implement the
+ * class [OccurrencesContributor] and then register the contributor by including
+ * code like the following in the plugin's registerExtensions method:
+ *
+ * @override
+ * void registerExtensions(RegisterExtension registerExtension) {
+ * ...
+ * registerExtension(
+ * OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT_ID,
+ * new MyOccurrencesContributor());
+ * ...
+ * }
*/
library analysis_server.plugin.occurrences;
@@ -14,8 +31,8 @@
/**
* The identifier of the extension point that allows plugins to register
- * element occurrences. The object used as an extension must be
- * a [OccurrencesContributor].
+ * occurrence information. The object used as an extension must be an
+ * [OccurrencesContributor].
*/
final String OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT_ID = Plugin.join(
ServerPlugin.UNIQUE_IDENTIFIER,
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index cee3508..8cb08b0 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -70,7 +70,7 @@
* The version of the analysis server. The value should be replaced
* automatically during the build.
*/
- static final String VERSION = '1.9.0';
+ static final String VERSION = '1.12.0';
/**
* The number of milliseconds to perform operations before inserting
@@ -1002,7 +1002,9 @@
case AnalysisService.OUTLINE:
AnalysisContext context = dartUnit.element.context;
LineInfo lineInfo = context.getLineInfo(source);
- sendAnalysisNotificationOutline(this, file, lineInfo, dartUnit);
+ SourceKind kind = context.getKindOf(source);
+ sendAnalysisNotificationOutline(
+ this, file, lineInfo, kind, dartUnit);
break;
case AnalysisService.OVERRIDES:
sendAnalysisNotificationOverrides(this, file, dartUnit);
@@ -1221,8 +1223,15 @@
if (dartUnits != null) {
AnalysisErrorInfo errorInfo = context.getErrors(source);
for (var dartUnit in dartUnits) {
- scheduleNotificationOperations(this, file, errorInfo.lineInfo,
- context, null, dartUnit, errorInfo.errors);
+ scheduleNotificationOperations(
+ this,
+ source,
+ file,
+ errorInfo.lineInfo,
+ context,
+ null,
+ dartUnit,
+ errorInfo.errors);
scheduleIndexOperation(this, file, context, dartUnit);
}
} else {
diff --git a/pkg/analysis_server/lib/src/computer/computer_hover.dart b/pkg/analysis_server/lib/src/computer/computer_hover.dart
index c09668b..8d870c0 100644
--- a/pkg/analysis_server/lib/src/computer/computer_hover.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_hover.dart
@@ -111,9 +111,7 @@
}
}
// documentation
- String dartDoc = element.computeDocumentationComment();
- dartDoc = _removeDartDocDelimiters(dartDoc);
- hover.dartdoc = dartDoc;
+ hover.dartdoc = _computeDocumentation(element);
}
// parameter
hover.parameter = _safeToString(expression.bestParameterElement);
@@ -127,5 +125,13 @@
return null;
}
+ String _computeDocumentation(Element element) {
+ if (element is ParameterElement) {
+ element = element.enclosingElement;
+ }
+ String dartDoc = element.computeDocumentationComment();
+ return _removeDartDocDelimiters(dartDoc);
+ }
+
static _safeToString(obj) => obj != null ? obj.toString() : null;
}
diff --git a/pkg/analysis_server/lib/src/constants.dart b/pkg/analysis_server/lib/src/constants.dart
index 391e41c..a32ad98 100644
--- a/pkg/analysis_server/lib/src/constants.dart
+++ b/pkg/analysis_server/lib/src/constants.dart
@@ -137,6 +137,7 @@
const String FILES = 'files';
const String FIXES = 'fixes';
const String FLAGS = 'flags';
+const String HAS_FIX = 'hasFix';
const String HIERARCHY_ITEMS = 'hierarchyItems';
const String HOVERS = 'hovers';
const String ID = 'id';
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index 81d7bf2..970e189 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -6,12 +6,12 @@
import 'dart:async';
-import 'package:analysis_server/completion/completion_core.dart'
- show CompletionRequest, CompletionResult;
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/context_manager.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart'
+ show CompletionRequest, CompletionResult;
import 'package:analysis_server/src/services/completion/completion_manager.dart';
import 'package:analysis_server/src/services/search/search_engine.dart';
import 'package:analyzer/src/generated/engine.dart';
diff --git a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
index 0891156..f96f42f 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
@@ -22,6 +22,15 @@
compute() async {
for (ClassElement type in unitElement.types) {
+ // always include Object and its members
+ if (type.supertype == null) {
+ _addImplementedClass(type);
+ type.accessors.forEach(_addImplementedMember);
+ type.fields.forEach(_addImplementedMember);
+ type.methods.forEach(_addImplementedMember);
+ continue;
+ }
+ // analyze ancestors
subtypes = await getSubClasses(searchEngine, type);
if (subtypes.isNotEmpty) {
_addImplementedClass(type);
diff --git a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
index 8b87629..f1b9100 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
@@ -74,6 +74,9 @@
}
void _addRegionForNode(AstNode node, Element element) {
+ if (node == null) {
+ return;
+ }
int offset = node.offset;
int length = node.length;
_addRegion(offset, length, element);
@@ -92,6 +95,30 @@
_DartNavigationComputerVisitor(this.computer);
@override
+ visitAnnotation(Annotation node) {
+ Element element = node.element;
+ if (element is ConstructorElement && element.isSynthetic) {
+ element = element.enclosingElement;
+ }
+ Identifier name = node.name;
+ if (name is PrefixedIdentifier) {
+ // use constructor in: @PrefixClass.constructorName
+ Element prefixElement = name.prefix.staticElement;
+ if (prefixElement is ClassElement) {
+ prefixElement = element;
+ }
+ computer._addRegionForNode(name.prefix, prefixElement);
+ // always constructor
+ computer._addRegionForNode(name.identifier, element);
+ } else {
+ computer._addRegionForNode(name, element);
+ }
+ computer._addRegionForNode(node.constructorName, element);
+ // arguments
+ _safelyVisit(node.arguments);
+ }
+
+ @override
visitAssignmentExpression(AssignmentExpression node) {
_safelyVisit(node.leftHandSide);
computer._addRegionForToken(node.operator, node.bestElement);
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index cb7b513..f6c298d 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -557,7 +557,8 @@
List<CompilationUnit> units = server.getResolvedCompilationUnits(file);
if (units.isNotEmpty) {
refactoring = new ExtractLocalRefactoring(units[0], offset, length);
- feedback = new ExtractLocalVariableFeedback([], [], []);
+ feedback = new ExtractLocalVariableFeedback(
+ <int>[], <int>[], <String>[], <int>[], <int>[]);
}
}
if (kind == RefactoringKind.EXTRACT_METHOD) {
@@ -565,8 +566,8 @@
if (units.isNotEmpty) {
refactoring = new ExtractMethodRefactoring(
searchEngine, units[0], offset, length);
- feedback = new ExtractMethodFeedback(
- offset, length, '', [], false, [], [], []);
+ feedback = new ExtractMethodFeedback(offset, length, '', <String>[],
+ false, <RefactoringMethodParameter>[], <int>[], <int>[]);
}
}
if (kind == RefactoringKind.INLINE_LOCAL_VARIABLE) {
diff --git a/pkg/analysis_server/lib/src/generated_protocol.dart b/pkg/analysis_server/lib/src/generated_protocol.dart
index c396864..4c95b37e 100644
--- a/pkg/analysis_server/lib/src/generated_protocol.dart
+++ b/pkg/analysis_server/lib/src/generated_protocol.dart
@@ -3158,12 +3158,18 @@
*
* {
* "file": FilePath
+ * "kind": FileKind
+ * "libraryName": optional String
* "outline": Outline
* }
*/
class AnalysisOutlineParams implements HasToJson {
String _file;
+ FileKind _kind;
+
+ String _libraryName;
+
Outline _outline;
/**
@@ -3180,6 +3186,39 @@
}
/**
+ * The kind of the file.
+ */
+ FileKind get kind => _kind;
+
+ /**
+ * The kind of the file.
+ */
+ void set kind(FileKind value) {
+ assert(value != null);
+ this._kind = value;
+ }
+
+ /**
+ * The name of the library defined by the file using a "library" directive,
+ * or referenced by a "part of" directive. If both "library" and "part of"
+ * directives are present, then the "library" directive takes precedence.
+ * This field will be omitted if the file has neither "library" nor "part of"
+ * directives.
+ */
+ String get libraryName => _libraryName;
+
+ /**
+ * The name of the library defined by the file using a "library" directive,
+ * or referenced by a "part of" directive. If both "library" and "part of"
+ * directives are present, then the "library" directive takes precedence.
+ * This field will be omitted if the file has neither "library" nor "part of"
+ * directives.
+ */
+ void set libraryName(String value) {
+ this._libraryName = value;
+ }
+
+ /**
* The outline associated with the file.
*/
Outline get outline => _outline;
@@ -3192,8 +3231,10 @@
this._outline = value;
}
- AnalysisOutlineParams(String file, Outline outline) {
+ AnalysisOutlineParams(String file, FileKind kind, Outline outline, {String libraryName}) {
this.file = file;
+ this.kind = kind;
+ this.libraryName = libraryName;
this.outline = outline;
}
@@ -3208,13 +3249,23 @@
} else {
throw jsonDecoder.missingKey(jsonPath, "file");
}
+ FileKind kind;
+ if (json.containsKey("kind")) {
+ kind = new FileKind.fromJson(jsonDecoder, jsonPath + ".kind", json["kind"]);
+ } else {
+ throw jsonDecoder.missingKey(jsonPath, "kind");
+ }
+ String libraryName;
+ if (json.containsKey("libraryName")) {
+ libraryName = jsonDecoder._decodeString(jsonPath + ".libraryName", json["libraryName"]);
+ }
Outline outline;
if (json.containsKey("outline")) {
outline = new Outline.fromJson(jsonDecoder, jsonPath + ".outline", json["outline"]);
} else {
throw jsonDecoder.missingKey(jsonPath, "outline");
}
- return new AnalysisOutlineParams(file, outline);
+ return new AnalysisOutlineParams(file, kind, outline, libraryName: libraryName);
} else {
throw jsonDecoder.mismatch(jsonPath, "analysis.outline params", json);
}
@@ -3228,6 +3279,10 @@
Map<String, dynamic> toJson() {
Map<String, dynamic> result = {};
result["file"] = file;
+ result["kind"] = kind.toJson();
+ if (libraryName != null) {
+ result["libraryName"] = libraryName;
+ }
result["outline"] = outline.toJson();
return result;
}
@@ -3243,6 +3298,8 @@
bool operator==(other) {
if (other is AnalysisOutlineParams) {
return file == other.file &&
+ kind == other.kind &&
+ libraryName == other.libraryName &&
outline == other.outline;
}
return false;
@@ -3252,6 +3309,8 @@
int get hashCode {
int hash = 0;
hash = _JenkinsSmiHash.combine(hash, file.hashCode);
+ hash = _JenkinsSmiHash.combine(hash, kind.hashCode);
+ hash = _JenkinsSmiHash.combine(hash, libraryName.hashCode);
hash = _JenkinsSmiHash.combine(hash, outline.hashCode);
return _JenkinsSmiHash.finish(hash);
}
@@ -7288,6 +7347,7 @@
* "location": Location
* "message": String
* "correction": optional String
+ * "hasFix": optional bool
* }
*/
class AnalysisError implements HasToJson {
@@ -7301,6 +7361,8 @@
String _correction;
+ bool _hasFix;
+
/**
* The severity of the error.
*/
@@ -7371,12 +7433,39 @@
this._correction = value;
}
- AnalysisError(AnalysisErrorSeverity severity, AnalysisErrorType type, Location location, String message, {String correction}) {
+ /**
+ * A hint to indicate to interested clients that this error has an associated
+ * fix (or fixes). The absence of this field implies there are not known to
+ * be fixes. Note that since the operation to calculate whether fixes apply
+ * needs to be performant it is possible that complicated tests will be
+ * skipped and a false negative returned. For this reason, this attribute
+ * should be treated as a "hint". Despite the possibility of false negatives,
+ * no false positives should be returned. If a client sees this flag set they
+ * can proceed with the confidence that there are in fact associated fixes.
+ */
+ bool get hasFix => _hasFix;
+
+ /**
+ * A hint to indicate to interested clients that this error has an associated
+ * fix (or fixes). The absence of this field implies there are not known to
+ * be fixes. Note that since the operation to calculate whether fixes apply
+ * needs to be performant it is possible that complicated tests will be
+ * skipped and a false negative returned. For this reason, this attribute
+ * should be treated as a "hint". Despite the possibility of false negatives,
+ * no false positives should be returned. If a client sees this flag set they
+ * can proceed with the confidence that there are in fact associated fixes.
+ */
+ void set hasFix(bool value) {
+ this._hasFix = value;
+ }
+
+ AnalysisError(AnalysisErrorSeverity severity, AnalysisErrorType type, Location location, String message, {String correction, bool hasFix}) {
this.severity = severity;
this.type = type;
this.location = location;
this.message = message;
this.correction = correction;
+ this.hasFix = hasFix;
}
factory AnalysisError.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
@@ -7412,7 +7501,11 @@
if (json.containsKey("correction")) {
correction = jsonDecoder._decodeString(jsonPath + ".correction", json["correction"]);
}
- return new AnalysisError(severity, type, location, message, correction: correction);
+ bool hasFix;
+ if (json.containsKey("hasFix")) {
+ hasFix = jsonDecoder._decodeBool(jsonPath + ".hasFix", json["hasFix"]);
+ }
+ return new AnalysisError(severity, type, location, message, correction: correction, hasFix: hasFix);
} else {
throw jsonDecoder.mismatch(jsonPath, "AnalysisError", json);
}
@@ -7427,6 +7520,9 @@
if (correction != null) {
result["correction"] = correction;
}
+ if (hasFix != null) {
+ result["hasFix"] = hasFix;
+ }
return result;
}
@@ -7440,7 +7536,8 @@
type == other.type &&
location == other.location &&
message == other.message &&
- correction == other.correction;
+ correction == other.correction &&
+ hasFix == other.hasFix;
}
return false;
}
@@ -7453,6 +7550,7 @@
hash = _JenkinsSmiHash.combine(hash, location.hashCode);
hash = _JenkinsSmiHash.combine(hash, message.hashCode);
hash = _JenkinsSmiHash.combine(hash, correction.hashCode);
+ hash = _JenkinsSmiHash.combine(hash, hasFix.hashCode);
return _JenkinsSmiHash.finish(hash);
}
}
@@ -9511,6 +9609,55 @@
}
/**
+ * FileKind
+ *
+ * enum {
+ * LIBRARY
+ * PART
+ * }
+ */
+class FileKind implements Enum {
+ static const LIBRARY = const FileKind._("LIBRARY");
+
+ static const PART = const FileKind._("PART");
+
+ /**
+ * A list containing all of the enum values that are defined.
+ */
+ static const List<FileKind> VALUES = const <FileKind>[LIBRARY, PART];
+
+ final String name;
+
+ const FileKind._(this.name);
+
+ factory FileKind(String name) {
+ switch (name) {
+ case "LIBRARY":
+ return LIBRARY;
+ case "PART":
+ return PART;
+ }
+ throw new Exception('Illegal enum value: $name');
+ }
+
+ factory FileKind.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+ if (json is String) {
+ try {
+ return new FileKind(json);
+ } catch(_) {
+ // Fall through
+ }
+ }
+ throw jsonDecoder.mismatch(jsonPath, "FileKind", json);
+ }
+
+ @override
+ String toString() => "FileKind.$name";
+
+ String toJson() => name;
+}
+
+/**
* FoldingKind
*
* enum {
@@ -14573,12 +14720,18 @@
* extractLocalVariable feedback
*
* {
+ * "coveringExpressionOffsets": List<int>
+ * "coveringExpressionLengths": List<int>
* "names": List<String>
* "offsets": List<int>
* "lengths": List<int>
* }
*/
class ExtractLocalVariableFeedback extends RefactoringFeedback implements HasToJson {
+ List<int> _coveringExpressionOffsets;
+
+ List<int> _coveringExpressionLengths;
+
List<String> _names;
List<int> _offsets;
@@ -14586,6 +14739,36 @@
List<int> _lengths;
/**
+ * The offsets of the expressions that cover the specified selection, from
+ * the down most to the up most.
+ */
+ List<int> get coveringExpressionOffsets => _coveringExpressionOffsets;
+
+ /**
+ * The offsets of the expressions that cover the specified selection, from
+ * the down most to the up most.
+ */
+ void set coveringExpressionOffsets(List<int> value) {
+ assert(value != null);
+ this._coveringExpressionOffsets = value;
+ }
+
+ /**
+ * The lengths of the expressions that cover the specified selection, from
+ * the down most to the up most.
+ */
+ List<int> get coveringExpressionLengths => _coveringExpressionLengths;
+
+ /**
+ * The lengths of the expressions that cover the specified selection, from
+ * the down most to the up most.
+ */
+ void set coveringExpressionLengths(List<int> value) {
+ assert(value != null);
+ this._coveringExpressionLengths = value;
+ }
+
+ /**
* The proposed names for the local variable.
*/
List<String> get names => _names;
@@ -14632,7 +14815,9 @@
this._lengths = value;
}
- ExtractLocalVariableFeedback(List<String> names, List<int> offsets, List<int> lengths) {
+ ExtractLocalVariableFeedback(List<int> coveringExpressionOffsets, List<int> coveringExpressionLengths, List<String> names, List<int> offsets, List<int> lengths) {
+ this.coveringExpressionOffsets = coveringExpressionOffsets;
+ this.coveringExpressionLengths = coveringExpressionLengths;
this.names = names;
this.offsets = offsets;
this.lengths = lengths;
@@ -14643,6 +14828,18 @@
json = {};
}
if (json is Map) {
+ List<int> coveringExpressionOffsets;
+ if (json.containsKey("coveringExpressionOffsets")) {
+ coveringExpressionOffsets = jsonDecoder._decodeList(jsonPath + ".coveringExpressionOffsets", json["coveringExpressionOffsets"], jsonDecoder._decodeInt);
+ } else {
+ throw jsonDecoder.missingKey(jsonPath, "coveringExpressionOffsets");
+ }
+ List<int> coveringExpressionLengths;
+ if (json.containsKey("coveringExpressionLengths")) {
+ coveringExpressionLengths = jsonDecoder._decodeList(jsonPath + ".coveringExpressionLengths", json["coveringExpressionLengths"], jsonDecoder._decodeInt);
+ } else {
+ throw jsonDecoder.missingKey(jsonPath, "coveringExpressionLengths");
+ }
List<String> names;
if (json.containsKey("names")) {
names = jsonDecoder._decodeList(jsonPath + ".names", json["names"], jsonDecoder._decodeString);
@@ -14661,7 +14858,7 @@
} else {
throw jsonDecoder.missingKey(jsonPath, "lengths");
}
- return new ExtractLocalVariableFeedback(names, offsets, lengths);
+ return new ExtractLocalVariableFeedback(coveringExpressionOffsets, coveringExpressionLengths, names, offsets, lengths);
} else {
throw jsonDecoder.mismatch(jsonPath, "extractLocalVariable feedback", json);
}
@@ -14669,6 +14866,8 @@
Map<String, dynamic> toJson() {
Map<String, dynamic> result = {};
+ result["coveringExpressionOffsets"] = coveringExpressionOffsets;
+ result["coveringExpressionLengths"] = coveringExpressionLengths;
result["names"] = names;
result["offsets"] = offsets;
result["lengths"] = lengths;
@@ -14681,7 +14880,9 @@
@override
bool operator==(other) {
if (other is ExtractLocalVariableFeedback) {
- return _listEqual(names, other.names, (String a, String b) => a == b) &&
+ return _listEqual(coveringExpressionOffsets, other.coveringExpressionOffsets, (int a, int b) => a == b) &&
+ _listEqual(coveringExpressionLengths, other.coveringExpressionLengths, (int a, int b) => a == b) &&
+ _listEqual(names, other.names, (String a, String b) => a == b) &&
_listEqual(offsets, other.offsets, (int a, int b) => a == b) &&
_listEqual(lengths, other.lengths, (int a, int b) => a == b);
}
@@ -14691,6 +14892,8 @@
@override
int get hashCode {
int hash = 0;
+ hash = _JenkinsSmiHash.combine(hash, coveringExpressionOffsets.hashCode);
+ hash = _JenkinsSmiHash.combine(hash, coveringExpressionLengths.hashCode);
hash = _JenkinsSmiHash.combine(hash, names.hashCode);
hash = _JenkinsSmiHash.combine(hash, offsets.hashCode);
hash = _JenkinsSmiHash.combine(hash, lengths.hashCode);
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index 198955c..973b831 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -77,6 +77,7 @@
*/
void scheduleNotificationOperations(
AnalysisServer server,
+ Source source,
String file,
LineInfo lineInfo,
AnalysisContext context,
@@ -99,12 +100,10 @@
}
if (server.hasAnalysisSubscription(
protocol.AnalysisService.NAVIGATION, file)) {
- Source source = resolvedDartUnit.element.source;
server.scheduleOperation(new NavigationOperation(context, source));
}
if (server.hasAnalysisSubscription(
protocol.AnalysisService.OCCURRENCES, file)) {
- Source source = resolvedDartUnit.element.source;
server.scheduleOperation(new OccurrencesOperation(context, source));
}
if (server.hasAnalysisSubscription(
@@ -116,8 +115,9 @@
if (dartUnit != null) {
if (server.hasAnalysisSubscription(
protocol.AnalysisService.OUTLINE, file)) {
- server.scheduleOperation(
- new _DartOutlineOperation(context, file, lineInfo, dartUnit));
+ SourceKind sourceKind = context.getKindOf(source);
+ server.scheduleOperation(new _DartOutlineOperation(
+ context, file, lineInfo, sourceKind, dartUnit));
}
}
// errors
@@ -213,11 +213,23 @@
}
void sendAnalysisNotificationOutline(AnalysisServer server, String file,
- LineInfo lineInfo, CompilationUnit dartUnit) {
+ LineInfo lineInfo, SourceKind sourceKind, CompilationUnit dartUnit) {
_sendNotification(server, () {
+ // compute FileKind
+ protocol.FileKind fileKind = protocol.FileKind.LIBRARY;
+ if (sourceKind == SourceKind.LIBRARY) {
+ fileKind = protocol.FileKind.LIBRARY;
+ } else if (sourceKind == SourceKind.PART) {
+ fileKind = protocol.FileKind.PART;
+ }
+ // compute library name
+ String libraryName = _computeLibraryName(dartUnit);
+ // compute Outline
var computer = new DartUnitOutlineComputer(file, lineInfo, dartUnit);
- var outline = computer.compute();
- var params = new protocol.AnalysisOutlineParams(file, outline);
+ protocol.Outline outline = computer.compute();
+ // send notification
+ var params = new protocol.AnalysisOutlineParams(file, fileKind, outline,
+ libraryName: libraryName);
server.sendNotification(params.toNotification());
});
}
@@ -241,6 +253,20 @@
context.analysisOptions = options;
}
+String _computeLibraryName(CompilationUnit unit) {
+ for (Directive directive in unit.directives) {
+ if (directive is LibraryDirective && directive.name != null) {
+ return directive.name.name;
+ }
+ }
+ for (Directive directive in unit.directives) {
+ if (directive is PartOfDirective && directive.libraryName != null) {
+ return directive.libraryName.name;
+ }
+ }
+ return null;
+}
+
/**
* Runs the given notification producing function [f], catching exceptions.
*/
@@ -371,8 +397,8 @@
// Dart
CompilationUnit parsedDartUnit = notice.parsedDartUnit;
CompilationUnit resolvedDartUnit = notice.resolvedDartUnit;
- scheduleNotificationOperations(server, file, notice.lineInfo, context,
- parsedDartUnit, resolvedDartUnit, notice.errors);
+ scheduleNotificationOperations(server, source, file, notice.lineInfo,
+ context, parsedDartUnit, resolvedDartUnit, notice.errors);
// done
server.fileAnalyzed(notice);
}
@@ -455,14 +481,15 @@
class _DartOutlineOperation extends _DartNotificationOperation {
final LineInfo lineInfo;
+ final SourceKind sourceKind;
- _DartOutlineOperation(
- AnalysisContext context, String file, this.lineInfo, CompilationUnit unit)
+ _DartOutlineOperation(AnalysisContext context, String file, this.lineInfo,
+ this.sourceKind, CompilationUnit unit)
: super(context, file, unit);
@override
void perform(AnalysisServer server) {
- sendAnalysisNotificationOutline(server, file, lineInfo, unit);
+ sendAnalysisNotificationOutline(server, file, lineInfo, sourceKind, unit);
}
}
diff --git a/pkg/analysis_server/lib/src/plugin/server_plugin.dart b/pkg/analysis_server/lib/src/plugin/server_plugin.dart
index b88d009..4e227b4 100644
--- a/pkg/analysis_server/lib/src/plugin/server_plugin.dart
+++ b/pkg/analysis_server/lib/src/plugin/server_plugin.dart
@@ -8,7 +8,6 @@
import 'package:analysis_server/analysis/index_core.dart';
import 'package:analysis_server/analysis/navigation_core.dart';
import 'package:analysis_server/analysis/occurrences_core.dart';
-import 'package:analysis_server/completion/completion_core.dart';
import 'package:analysis_server/edit/assist/assist_core.dart';
import 'package:analysis_server/edit/fix/fix_core.dart';
import 'package:analysis_server/plugin/analyzed_files.dart';
@@ -26,6 +25,7 @@
import 'package:analysis_server/src/domains/analysis/occurrences_dart.dart';
import 'package:analysis_server/src/edit/edit_domain.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart';
import 'package:analysis_server/src/search/search_domain.dart';
import 'package:analysis_server/src/services/correction/assist_internal.dart';
import 'package:analysis_server/src/services/correction/fix_internal.dart';
diff --git a/pkg/analysis_server/lib/src/protocol_server.dart b/pkg/analysis_server/lib/src/protocol_server.dart
index a9dd5dd..705b7aa 100644
--- a/pkg/analysis_server/lib/src/protocol_server.dart
+++ b/pkg/analysis_server/lib/src/protocol_server.dart
@@ -5,6 +5,7 @@
library protocol.server;
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/search/search_engine.dart'
as engine;
import 'package:analyzer/src/generated/ast.dart' as engine;
@@ -92,8 +93,9 @@
var type = new AnalysisErrorType(errorCode.type.name);
String message = error.message;
String correction = error.correction;
+ bool fix = hasFix(error.errorCode);
return new AnalysisError(severity, type, location, message,
- correction: correction);
+ correction: correction, hasFix: fix);
}
/**
diff --git a/pkg/analysis_server/lib/plugin/completion.dart b/pkg/analysis_server/lib/src/provisional/completion/completion.dart
similarity index 90%
rename from pkg/analysis_server/lib/plugin/completion.dart
rename to pkg/analysis_server/lib/src/provisional/completion/completion.dart
index 9b1c4b5..9a71bc0 100644
--- a/pkg/analysis_server/lib/plugin/completion.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/completion.dart
@@ -23,10 +23,10 @@
* ...
* }
*/
-library analysis_server.plugin.completion;
+library analysis_server.src.provisional.completion.completion;
-import 'package:analysis_server/completion/completion_core.dart';
import 'package:analysis_server/src/plugin/server_plugin.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart';
import 'package:plugin/plugin.dart';
/**
diff --git a/pkg/analysis_server/lib/completion/completion_core.dart b/pkg/analysis_server/lib/src/provisional/completion/completion_core.dart
similarity index 97%
rename from pkg/analysis_server/lib/completion/completion_core.dart
rename to pkg/analysis_server/lib/src/provisional/completion/completion_core.dart
index 5003faf..f38d541 100644
--- a/pkg/analysis_server/lib/completion/completion_core.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/completion_core.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.
-library analysis_server.completion.completion_core;
+library analysis_server.src.provisional.completion.completion_core;
import 'package:analysis_server/src/protocol.dart';
import 'package:analyzer/file_system/file_system.dart';
diff --git a/pkg/analysis_server/lib/completion/completion_dart.dart b/pkg/analysis_server/lib/src/provisional/completion/completion_dart.dart
similarity index 91%
rename from pkg/analysis_server/lib/completion/completion_dart.dart
rename to pkg/analysis_server/lib/src/provisional/completion/completion_dart.dart
index 1ddd5a0..488f30d 100644
--- a/pkg/analysis_server/lib/completion/completion_dart.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/completion_dart.dart
@@ -2,14 +2,14 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library analysis_server.completion.completion_dart;
+library analysis_server.src.provisional.completion.completion_dart;
-import 'package:analysis_server/completion/completion_core.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
-import 'package:analysis_server/completion/dart/completion_target.dart';
/**
* An object used to produce completions for a specific error within a Dart
@@ -66,9 +66,10 @@
bool get isResolved;
/**
- * Return the compilation unit in which the completion was requested.
+ * Return the completion target. This determines what part of the parse tree
+ * will receive the newly inserted text.
*/
- CompilationUnit get unit;
+ CompletionTarget get target;
/**
* Cached information from a prior code completion operation.
@@ -76,10 +77,9 @@
//DartCompletionCache get cache;
/**
- * Return the completion target. This determines what part of the parse tree
- * will receive the newly inserted text.
+ * Return the compilation unit in which the completion was requested.
*/
- CompletionTarget get target;
+ CompilationUnit get unit;
/**
* Information about the types of suggestions that should be included.
diff --git a/pkg/analysis_server/lib/completion/dart/completion_target.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
similarity index 97%
rename from pkg/analysis_server/lib/completion/dart/completion_target.dart
rename to pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
index a1f315b..b24c610 100644
--- a/pkg/analysis_server/lib/completion/dart/completion_target.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
@@ -1,3 +1,9 @@
+// Copyright (c) 2015, 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.
+
+library analysis_server.src.provisional.completion.dart.completion_target;
+
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/scanner.dart';
diff --git a/pkg/analysis_server/lib/src/provisional/refactoring/refactoring_core.dart b/pkg/analysis_server/lib/src/provisional/refactoring/refactoring_core.dart
new file mode 100644
index 0000000..f1c9f94
--- /dev/null
+++ b/pkg/analysis_server/lib/src/provisional/refactoring/refactoring_core.dart
@@ -0,0 +1,102 @@
+// Copyright (c) 2015, 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.
+
+library analysis_server.edit.refactoring.refactoring_core;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/protocol.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+/**
+ * Abstract interface for all refactorings.
+ */
+abstract class Refactoring {
+ /**
+ * Return the ids of source edits that are not known to be valid.
+ *
+ * An edit is not known to be valid if there was insufficient type information
+ * for the server to be able to determine whether or not the code needs to be
+ * modified, such as when a member is being renamed and there is a reference
+ * to a member from an unknown type. This field will be omitted if the change
+ * field is omitted or if there are no potential edits for the refactoring.
+ */
+ List<String> get potentialEditIds;
+
+ /**
+ * Return the human readable name of this refactoring.
+ */
+ String get refactoringName;
+
+ /**
+ * Checks all conditions - [checkInitialConditions] and
+ * [checkFinalConditions] to decide if refactoring can be performed.
+ */
+ Future<RefactoringStatus> checkAllConditions();
+
+ /**
+ * Validates environment to check if this refactoring can be performed.
+ *
+ * This check may be slow, because many refactorings use search engine.
+ */
+ Future<RefactoringStatus> checkFinalConditions();
+
+ /**
+ * Validates arguments to check if this refactoring can be performed.
+ *
+ * This check should be quick because it is used often as arguments change.
+ */
+ Future<RefactoringStatus> checkInitialConditions();
+
+ /**
+ * Return the [Change] to apply to perform this refactoring.
+ */
+ Future<SourceChange> createChange();
+
+ /**
+ * Return `true` if the [Change] created by refactoring may be unsafe,
+ * so we want user to review the [Change] to ensure that he understands it.
+ */
+ bool requiresPreview();
+}
+
+/**
+ *
+ *
+ * Clients are expected to subtype this class when implementing plugins.
+ */
+abstract class RefactoringContributor {
+ /**
+ *
+ */
+ Refactoring createRefactoring(AnalysisContext context, RefactoringKind kind,
+ Source source, int offset, int length);
+
+ /**
+ *
+ */
+ List<RefactoringKind> getAvailableRefactorings(
+ AnalysisContext context, Source source, int offset, int length);
+}
+
+/**
+ *
+ *
+ * Clients are not expected to subtype this class.
+ */
+abstract class RefactoringKind {
+ factory RefactoringKind(String name, bool requiresOptions) {
+ } // TODO(brianwilkerson) Redirect to impl class.
+ bool get requiresOptions;
+}
+
+/**
+ *
+ *
+ * Clients are not expected to subtype this class.
+ */
+abstract class RefactoringStatus {
+ // TODO(brianwilkerson) Fill this in.
+}
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index c5eb6bf..883f50c4e 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -206,6 +206,11 @@
static const String CLIENT_VERSION = "client-version";
/**
+ * The name of the option used to disable the use of the new task model.
+ */
+ static const String DISABLE_NEW_TASK_MODEL = "disable-new-task-model";
+
+ /**
* The name of the option used to enable incremental resolution of API
* changes.
*/
@@ -218,11 +223,6 @@
static const String ENABLE_INSTRUMENTATION_OPTION = "enable-instrumentation";
/**
- * The name of the option used to enable the use of the new task model.
- */
- static const String ENABLE_NEW_TASK_MODEL = "enable-new-task-model";
-
- /**
* The name of the option used to set the file read mode.
*/
static const String FILE_READ_MODE = "file-read-mode";
@@ -395,9 +395,7 @@
//
// Enable the new task model, if appropriate.
//
- if (results[ENABLE_NEW_TASK_MODEL]) {
- AnalysisEngine.instance.useTaskModel = true;
- }
+ AnalysisEngine.instance.useTaskModel = !results[DISABLE_NEW_TASK_MODEL];
//
// Process all of the plugins so that extensions are registered.
//
@@ -470,6 +468,11 @@
parser.addOption(CLIENT_ID,
help: "an identifier used to identify the client");
parser.addOption(CLIENT_VERSION, help: "the version of the client");
+ parser.addFlag(DISABLE_NEW_TASK_MODEL,
+ help: "disable the use of the new task model",
+ defaultsTo: false,
+ hide: true,
+ negatable: false);
parser.addFlag(ENABLE_INCREMENTAL_RESOLUTION_API,
help: "enable using incremental resolution for API changes",
defaultsTo: false,
@@ -478,11 +481,6 @@
help: "enable sending instrumentation information to a server",
defaultsTo: false,
negatable: false);
- parser.addFlag(ENABLE_NEW_TASK_MODEL,
- help: "enable the use of the new task model",
- defaultsTo: false,
- hide: true,
- negatable: false);
parser.addFlag(HELP_OPTION,
help: "print this help message without starting a server",
defaultsTo: false,
diff --git a/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart
index 61194fc..4f7780d 100644
--- a/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart
@@ -141,23 +141,20 @@
}
}
}
- if (parent is InstanceCreationExpression) {
- ConstructorName constructorName = parent.constructorName;
- if (constructorName != null) {
- String name = constructorName.toSource();
- if (name.length > 0) {
- /*
- * If a local declaration is found, then return null
- * indicating that suggestions were added
- * and no further action is necessary
- */
- if (new _LocalArgSuggestionBuilder(request, request.offset, name)
- .visit(node)) {
- return null;
- }
- return new _ArgSuggestionBuilder(request, name);
- }
+ String constructorName;
+ if (parent is Annotation && parent.name != null) {
+ constructorName = parent.name.toSource();
+ }
+ if (parent is InstanceCreationExpression &&
+ parent.constructorName != null) {
+ constructorName = parent.constructorName.toSource();
+ }
+ if (constructorName != null && constructorName.length > 0) {
+ if (new _LocalArgSuggestionBuilder(
+ request, request.offset, constructorName).visit(node)) {
+ return null;
}
+ return new _ArgSuggestionBuilder(request, constructorName);
}
}
return null;
diff --git a/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart b/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart
index 2b391ca..e3c44ce 100644
--- a/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart
@@ -4,10 +4,10 @@
library services.completion.computer.dart.relevance;
-import 'package:analysis_server/completion/completion_dart.dart';
import 'package:analysis_server/src/protocol_server.dart' as protocol;
import 'package:analysis_server/src/protocol_server.dart'
show CompletionSuggestion, CompletionSuggestionKind;
+import 'package:analysis_server/src/provisional/completion/completion_dart.dart';
import 'package:analysis_server/src/services/completion/contribution_sorter.dart';
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart'
show DART_RELEVANCE_COMMON_USAGE;
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_core.dart b/pkg/analysis_server/lib/src/services/completion/completion_core.dart
index a8ed44b..68fa732 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_core.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_core.dart
@@ -4,7 +4,7 @@
library analysis_server.src.services.completion.completion_dart;
-import 'package:analysis_server/completion/completion_core.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_dart.dart b/pkg/analysis_server/lib/src/services/completion/completion_dart.dart
index 4304295..1cfff04 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_dart.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_dart.dart
@@ -4,9 +4,9 @@
library analysis_server.src.services.completion.completion_dart;
-import 'package:analysis_server/completion/completion_core.dart';
-import 'package:analysis_server/completion/completion_dart.dart';
-import 'package:analysis_server/completion/dart/completion_target.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart';
+import 'package:analysis_server/src/provisional/completion/completion_dart.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
import 'package:analysis_server/src/services/completion/completion_core.dart';
import 'package:analyzer/src/generated/ast.dart';
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
index ebc5054..178d76c 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
@@ -6,10 +6,10 @@
import 'dart:async';
-import 'package:analysis_server/completion/completion_core.dart'
- show CompletionRequest, CompletionResult;
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart'
+ show CompletionRequest, CompletionResult;
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
import 'package:analysis_server/src/services/search/search_engine.dart';
import 'package:analyzer/file_system/file_system.dart';
@@ -273,11 +273,9 @@
CompletionResultImpl(this.replacementOffset, this.replacementLength,
this.suggestions, this.last);
- @override
- // TODO(brianwilkerson) Figure out whether this is correct.
- bool get hasNewSuggestions => suggestions.isNotEmpty;
-
- @override
+ /**
+ * Return `true` if this is the last completion result that will be produced.
+ */
bool get isLast => last;
}
diff --git a/pkg/analysis_server/lib/src/services/completion/contribution_sorter.dart b/pkg/analysis_server/lib/src/services/completion/contribution_sorter.dart
index 737a837..3a5217b 100644
--- a/pkg/analysis_server/lib/src/services/completion/contribution_sorter.dart
+++ b/pkg/analysis_server/lib/src/services/completion/contribution_sorter.dart
@@ -4,8 +4,8 @@
library services.completion.sorter;
-import 'package:analysis_server/completion/completion_dart.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_dart.dart';
/**
* The abstract class `ContributionSorter` defines the behavior of objects
diff --git a/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
index ae177f2..2f19c64 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
@@ -6,12 +6,13 @@
import 'dart:async';
-import 'package:analysis_server/completion/completion_core.dart'
- show CompletionRequest;
-import 'package:analysis_server/completion/completion_dart.dart' as newApi;
-import 'package:analysis_server/completion/dart/completion_target.dart';
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart'
+ show CompletionRequest;
+import 'package:analysis_server/src/provisional/completion/completion_dart.dart'
+ as newApi;
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
import 'package:analysis_server/src/services/completion/arglist_contributor.dart';
import 'package:analysis_server/src/services/completion/combinator_contributor.dart';
import 'package:analysis_server/src/services/completion/common_usage_computer.dart';
@@ -182,7 +183,10 @@
});
contributionSorter.sort(
new OldRequestWrapper(request), request.suggestions);
- sendResults(request, todo.isEmpty);
+
+ if (todo.isEmpty) {
+ sendResults(request, todo.isEmpty);
+ }
return todo;
});
}
diff --git a/pkg/analysis_server/lib/src/services/completion/inherited_contributor.dart b/pkg/analysis_server/lib/src/services/completion/inherited_contributor.dart
index 11d0631..410eb81 100644
--- a/pkg/analysis_server/lib/src/services/completion/inherited_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/inherited_contributor.dart
@@ -4,11 +4,11 @@
library services.completion.computer.dart.invocation;
-import 'package:analysis_server/completion/completion_dart.dart';
import 'package:analysis_server/src/protocol_server.dart'
show CompletionSuggestion, CompletionSuggestionKind, SourceChange;
import 'package:analysis_server/src/protocol_server.dart' as protocol
hide CompletionSuggestion, CompletionSuggestionKind;
+import 'package:analysis_server/src/provisional/completion/completion_dart.dart';
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart'
show DART_RELEVANCE_HIGH;
import 'package:analysis_server/utilities/change_builder_dart.dart';
diff --git a/pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart b/pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart
index 6aa3536..fe9ef14 100644
--- a/pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart
@@ -1,4 +1,5 @@
// Copyright (c) 2014, 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.
@@ -70,6 +71,9 @@
}
}
_addStatementKeywords(node);
+ if (_inCatchClause(node)) {
+ _addSuggestion(Keyword.RETHROW, DART_RELEVANCE_KEYWORD - 1);
+ }
}
@override
@@ -446,7 +450,6 @@
Keyword.VOID,
Keyword.WHILE
]);
- _addSuggestion(Keyword.RETHROW, DART_RELEVANCE_KEYWORD - 1);
}
void _addSuggestion(Keyword keyword,
@@ -481,6 +484,9 @@
return body != null && body.isAsynchronous;
}
+ bool _inCatchClause(Block node) =>
+ node.getAncestor((p) => p is CatchClause) != null;
+
bool _inClassMemberBody(AstNode node) {
while (true) {
AstNode body = node.getAncestor((n) => n is FunctionBody);
diff --git a/pkg/analysis_server/lib/src/services/completion/local_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/local_reference_contributor.dart
index 6fdb2b6..181f259 100644
--- a/pkg/analysis_server/lib/src/services/completion/local_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/local_reference_contributor.dart
@@ -351,9 +351,20 @@
class _LocalVisitor extends LocalDeclarationVisitor {
final DartCompletionRequest request;
final OpType optype;
+ int privateMemberRelevance = DART_RELEVANCE_DEFAULT;
_LocalVisitor(this.request, int offset, this.optype) : super(offset) {
includeLocalInheritedTypes = !optype.inStaticMethodBody;
+ if (request.replacementLength > 0) {
+ var contents = request.context.getContents(request.source);
+ if (contents != null &&
+ contents.data != null &&
+ contents.data.startsWith('_', request.replacementOffset)) {
+ // If user typed identifier starting with '_'
+ // then do not suppress the relevance of private members
+ privateMemberRelevance = null;
+ }
+ }
}
@override
@@ -554,6 +565,10 @@
id, isDeprecated, relevance, typeName,
classDecl: classDecl);
if (suggestion != null) {
+ if (privateMemberRelevance != null &&
+ suggestion.completion.startsWith('_')) {
+ suggestion.relevance = privateMemberRelevance;
+ }
request.addSuggestion(suggestion);
suggestion.element = createElement(request.source, elemKind, id,
isAbstract: isAbstract,
diff --git a/pkg/analysis_server/lib/src/services/completion/optype.dart b/pkg/analysis_server/lib/src/services/completion/optype.dart
index 5a04322..dc38919 100644
--- a/pkg/analysis_server/lib/src/services/completion/optype.dart
+++ b/pkg/analysis_server/lib/src/services/completion/optype.dart
@@ -4,7 +4,7 @@
library services.completion.dart.optype;
-import 'package:analysis_server/completion/dart/completion_target.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/scanner.dart';
@@ -295,6 +295,16 @@
}
@override
+ void visitFieldFormalParameter(FieldFormalParameter node) {
+ if (entity == node.identifier) {
+ optype.isPrefixed = true;
+ } else {
+ optype.includeReturnValueSuggestions = true;
+ optype.includeTypeNameSuggestions = true;
+ }
+ }
+
+ @override
void visitForEachStatement(ForEachStatement node) {
if (identical(entity, node.identifier)) {
optype.includeTypeNameSuggestions = true;
@@ -449,16 +459,6 @@
}
@override
- void visitFieldFormalParameter(FieldFormalParameter node) {
- if (entity == node.identifier) {
- optype.isPrefixed = true;
- } else {
- optype.includeReturnValueSuggestions = true;
- optype.includeTypeNameSuggestions = true;
- }
- }
-
- @override
void visitNormalFormalParameter(NormalFormalParameter node) {
optype.includeReturnValueSuggestions = true;
optype.includeTypeNameSuggestions = true;
diff --git a/pkg/analysis_server/lib/src/services/completion/uri_contributor.dart b/pkg/analysis_server/lib/src/services/completion/uri_contributor.dart
index cb32012..6d19260 100644
--- a/pkg/analysis_server/lib/src/services/completion/uri_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/uri_contributor.dart
@@ -48,13 +48,22 @@
}
@override
+ visitExportDirective(ExportDirective node) {
+ visitNamespaceDirective(node);
+ }
+
+ @override
visitImportDirective(ImportDirective node) {
+ visitNamespaceDirective(node);
+ }
+
+ visitNamespaceDirective(NamespaceDirective node) {
StringLiteral uri = node.uri;
if (uri is SimpleStringLiteral) {
int offset = request.offset;
if (uri.offset < offset &&
(offset < uri.end || offset == uri.offset + 1)) {
- // Handle degenerate case where import is only line in file
+ // Handle degenerate case where import or export is only line in file
// and there is no semicolon
visitSimpleStringLiteral(uri);
}
@@ -64,7 +73,7 @@
@override
visitSimpleStringLiteral(SimpleStringLiteral node) {
AstNode parent = node.parent;
- if (parent is ImportDirective && parent.uri == node) {
+ if (parent is NamespaceDirective && parent.uri == node) {
String partial = node.literal.lexeme.substring(
node.contentsOffset - node.offset, request.offset - node.offset);
request.replacementOffset = node.contentsOffset;
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index e1f81f6..d00a24f 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -10,6 +10,7 @@
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/parser.dart';
/**
* Compute and return the fixes available for the given [error]. The error was
@@ -38,6 +39,63 @@
}
/**
+ * Return true if this [errorCode] is likely to have a fix associated with it.
+ */
+bool hasFix(ErrorCode errorCode) => errorCode ==
+ StaticWarningCode.UNDEFINED_CLASS_BOOLEAN ||
+ errorCode == StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER ||
+ errorCode == StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS ||
+ errorCode == StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR ||
+ errorCode ==
+ StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE ||
+ errorCode ==
+ StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO ||
+ errorCode ==
+ StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_THREE ||
+ errorCode ==
+ StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR ||
+ errorCode ==
+ StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS ||
+ errorCode == StaticWarningCode.CAST_TO_NON_TYPE ||
+ errorCode == StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME ||
+ errorCode == StaticWarningCode.UNDEFINED_CLASS ||
+ errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED ||
+ errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1 ||
+ errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2 ||
+ errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS ||
+ errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER ||
+ errorCode ==
+ CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE ||
+ errorCode == CompileTimeErrorCode.INVALID_ANNOTATION ||
+ errorCode == CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_EXPLICIT ||
+ errorCode == CompileTimeErrorCode.PART_OF_NON_PART ||
+ errorCode ==
+ CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT ||
+ errorCode == CompileTimeErrorCode.URI_DOES_NOT_EXIST ||
+ errorCode == HintCode.DEAD_CODE ||
+ errorCode == HintCode.DIVISION_OPTIMIZATION ||
+ errorCode == HintCode.TYPE_CHECK_IS_NOT_NULL ||
+ errorCode == HintCode.TYPE_CHECK_IS_NULL ||
+ errorCode == HintCode.UNDEFINED_GETTER ||
+ errorCode == HintCode.UNDEFINED_SETTER ||
+ errorCode == HintCode.UNNECESSARY_CAST ||
+ errorCode == HintCode.UNUSED_CATCH_CLAUSE ||
+ errorCode == HintCode.UNUSED_CATCH_STACK ||
+ errorCode == HintCode.UNUSED_IMPORT ||
+ errorCode == HintCode.UNDEFINED_METHOD ||
+ errorCode == ParserErrorCode.EXPECTED_TOKEN ||
+ errorCode == ParserErrorCode.GETTER_WITH_PARAMETERS ||
+ errorCode == ParserErrorCode.VAR_AS_TYPE_NAME ||
+ errorCode == StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE ||
+ errorCode == StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER ||
+ errorCode == StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION ||
+ errorCode == StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT ||
+ errorCode == StaticTypeWarningCode.UNDEFINED_FUNCTION ||
+ errorCode == StaticTypeWarningCode.UNDEFINED_GETTER ||
+ errorCode == StaticTypeWarningCode.UNDEFINED_METHOD ||
+ errorCode == StaticTypeWarningCode.UNDEFINED_SETTER;
+
+/**
* An enumeration of possible quick fix kinds.
*/
class DartFixKind {
diff --git a/pkg/analysis_server/lib/src/services/index/index.dart b/pkg/analysis_server/lib/src/services/index/index.dart
index 3a44b4f..5767b4c 100644
--- a/pkg/analysis_server/lib/src/services/index/index.dart
+++ b/pkg/analysis_server/lib/src/services/index/index.dart
@@ -82,9 +82,6 @@
IndexableObjectKind get kind => IndexableNameKind.INSTANCE;
@override
- int get length => 0;
-
- @override
int get offset {
return -1;
}
@@ -127,6 +124,12 @@
throw new UnsupportedError(
'Indexable names cannot be decoded through their kind');
}
+
+ @override
+ int encodeHash(StringToInt stringToInt, IndexableObject indexable) {
+ String name = (indexable as IndexableName).name;
+ return stringToInt(name);
+ }
}
/**
diff --git a/pkg/analysis_server/lib/src/services/index/index_contributor.dart b/pkg/analysis_server/lib/src/services/index/index_contributor.dart
index ae1ec69..44ce967 100644
--- a/pkg/analysis_server/lib/src/services/index/index_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/index/index_contributor.dart
@@ -778,8 +778,8 @@
void _recordTopLevelElementDefinition(Element element) {
if (element != null) {
IndexableElement indexable = new IndexableElement(element);
- int offset = indexable.offset;
- int length = indexable.length;
+ int offset = element.nameOffset;
+ int length = element.nameLength;
LocationImpl location = new LocationImpl(indexable, offset, length);
recordRelationshipElement(
_libraryElement, IndexConstants.DEFINES, location);
diff --git a/pkg/analysis_server/lib/src/services/index/indexable_element.dart b/pkg/analysis_server/lib/src/services/index/indexable_element.dart
index 8df94c0..a2d3d64 100644
--- a/pkg/analysis_server/lib/src/services/index/indexable_element.dart
+++ b/pkg/analysis_server/lib/src/services/index/indexable_element.dart
@@ -10,6 +10,7 @@
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_general.dart';
/**
* A wrapper around an [Element] that implements the [IndexableObject] interface.
@@ -36,12 +37,6 @@
IndexableObjectKind get kind => IndexableElementKind.forElement(element);
@override
- int get length => element.nameLength;
-
- @override
- String get name => element.displayName;
-
- @override
int get offset {
if (element is ConstructorElement) {
return element.enclosingElement.nameOffset;
@@ -67,7 +62,7 @@
/**
* A table mapping element kinds to the corresponding indexable element kind.
*/
- static Map<ElementKind, IndexableElementKind> _kindMap =
+ static final Map<ElementKind, IndexableElementKind> _kindMap =
new HashMap<ElementKind, IndexableElementKind>();
/**
@@ -75,7 +70,7 @@
* of constructors associated with a class) to the indexable element kind used
* to represent it.
*/
- static Map<int, IndexableElementKind> _constructorKinds =
+ static final Map<int, IndexableElementKind> _constructorKinds =
new HashMap<int, IndexableElementKind>();
@override
@@ -145,6 +140,22 @@
return null;
}
+ @override
+ int encodeHash(StringToInt stringToInt, IndexableObject indexable) {
+ Element element = (indexable as IndexableElement).element;
+ String elementName = element.displayName;
+ int elementNameId = stringToInt(elementName);
+ if (indexable is IndexableElement) {
+ LibraryElement libraryElement = indexable.element.library;
+ if (libraryElement != null) {
+ String libraryPath = libraryElement.source.fullName;
+ int libraryPathId = stringToInt(libraryPath);
+ return JenkinsSmiHash.combine(libraryPathId, elementNameId);
+ }
+ }
+ return elementNameId;
+ }
+
/**
* Return the indexable element kind representing the given [element].
*/
diff --git a/pkg/analysis_server/lib/src/services/index/store/codec.dart b/pkg/analysis_server/lib/src/services/index/store/codec.dart
index 07925f3..c865aa4 100644
--- a/pkg/analysis_server/lib/src/services/index/store/codec.dart
+++ b/pkg/analysis_server/lib/src/services/index/store/codec.dart
@@ -8,11 +8,8 @@
import 'package:analysis_server/analysis/index_core.dart';
import 'package:analysis_server/src/services/index/index.dart';
-import 'package:analysis_server/src/services/index/indexable_element.dart';
-import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_general.dart';
/**
* A helper that encodes/decodes [AnalysisContext]s from/to integers.
@@ -79,7 +76,6 @@
*/
IndexableObject decode(
AnalysisContext context, int fileId, int offset, int kindId) {
- String filePath = _stringCodec.decode(fileId);
IndexableObjectKind kind = IndexableObjectKind.getKind(kindId);
if (kind == null) {
return null;
@@ -87,6 +83,7 @@
String name = _stringCodec.decode(offset);
return new IndexableName(name);
}
+ String filePath = _stringCodec.decode(fileId);
return kind.decode(context, filePath, offset);
}
@@ -113,11 +110,7 @@
String name = indexable.name;
return _stringCodec.encode(name);
}
- int offset = indexable.offset;
- if (offset < 0) {
- return _stringCodec.encode(indexable.name);
- }
- return offset;
+ return indexable.offset;
}
/**
@@ -132,19 +125,7 @@
* Returns an integer that corresponds to the name of [indexable].
*/
int encodeHash(IndexableObject indexable) {
- // TODO(brianwilkerson) Consider moving this to IndexableObjectKind so that
- // we don't have to break encapsulation.
- String elementName = indexable.name; // was: indexable.displayName;
- int elementNameId = _stringCodec.encode(elementName);
- if (indexable is IndexableElement) {
- LibraryElement libraryElement = indexable.element.library;
- if (libraryElement != null) {
- String libraryPath = libraryElement.source.fullName;
- int libraryPathId = _stringCodec.encode(libraryPath);
- return JenkinsSmiHash.combine(libraryPathId, elementNameId);
- }
- }
- return elementNameId;
+ return indexable.kind.encodeHash(_stringCodec.encode, indexable);
}
}
diff --git a/pkg/analysis_server/lib/src/services/index/store/split_store.dart b/pkg/analysis_server/lib/src/services/index/store/split_store.dart
index 9c51d6a..57b1734 100644
--- a/pkg/analysis_server/lib/src/services/index/store/split_store.dart
+++ b/pkg/analysis_server/lib/src/services/index/store/split_store.dart
@@ -1005,8 +1005,8 @@
nodeDeclarations[_currentNodeNameId] = declarations;
}
// record LocationData
- declarations
- .add(new _TopElementData(_elementCodec, new IndexableElement(element)));
+ declarations.add(new _TopElementData(
+ _elementCodec, element.displayName, new IndexableElement(element)));
}
@override
@@ -1154,12 +1154,9 @@
final int elementId3;
factory _TopElementData(
- ElementCodec elementCodec, IndexableObject indexable) {
- return new _TopElementData._(
- indexable.name,
- elementCodec.encode1(indexable),
- elementCodec.encode2(indexable),
- elementCodec.encode3(indexable));
+ ElementCodec elementCodec, String name, IndexableObject indexable) {
+ return new _TopElementData._(name, elementCodec.encode1(indexable),
+ elementCodec.encode2(indexable), elementCodec.encode3(indexable));
}
_TopElementData._(
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename.dart b/pkg/analysis_server/lib/src/services/refactoring/rename.dart
index bd97527..a9bdb74 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename.dart
@@ -17,6 +17,7 @@
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_core.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'package:path/path.dart' as pathos;
/**
* Returns `true` if two given [Element]s are [LocalElement]s and have
@@ -52,6 +53,18 @@
return librarySourcesOfSource.contains(librarySourceOfElement);
}
+bool isElementInPubCache(Element element) {
+ Source source = element.source;
+ String path = source.fullName;
+ return isPathInPubCache(path);
+}
+
+bool isElementInSdkOrPubCache(Element element) {
+ Source source = element.source;
+ String path = source.fullName;
+ return source.isInSystemLibrary || isPathInPubCache(path);
+}
+
/**
* Checks if the given [Element] is in the given [AnalysisContext].
*/
@@ -59,6 +72,23 @@
return element.context == context;
}
+bool isPathInPubCache(String path) {
+ List<String> parts = pathos.split(path);
+ if (parts.contains('.pub-cache')) {
+ return true;
+ }
+ for (int i = 0; i < parts.length - 1; i++) {
+ if (parts[i] == 'Pub' && parts[i + 1] == 'Cache') {
+ return true;
+ }
+ if (parts[i] == 'third_party' &&
+ (parts[i + 1] == 'pkg' || parts[i + 1] == 'pkg_tested')) {
+ return true;
+ }
+ }
+ return false;
+}
+
/**
* Checks if the given unqualified [SearchMatch] intersects with visibility
* range of [localElement].
@@ -145,6 +175,13 @@
getElementQualifiedName(element));
result.addFatalError(message);
}
+ if (isElementInPubCache(element)) {
+ String message = format(
+ "The {0} '{1}' is defined in a pub package, so cannot be renamed.",
+ getElementKindName(element),
+ getElementQualifiedName(element));
+ result.addFatalError(message);
+ }
return new Future.value(result);
}
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
index e0f9a77..4d70e06 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
@@ -100,6 +100,11 @@
if (reference.isResolved) {
continue;
}
+ // ignore references from SDK and pub cache
+ if (isElementInSdkOrPubCache(reference.element)) {
+ print('ignore: $reference');
+ continue;
+ }
// check the element being renamed is accessible
{
LibraryElement whereLibrary = reference.element.library;
diff --git a/pkg/analysis_server/lib/src/status/get_handler.dart b/pkg/analysis_server/lib/src/status/get_handler.dart
index abf8f00..c85db7b 100644
--- a/pkg/analysis_server/lib/src/status/get_handler.dart
+++ b/pkg/analysis_server/lib/src/status/get_handler.dart
@@ -323,6 +323,7 @@
results.add(COMPILATION_UNIT_CONSTANTS);
results.add(COMPILATION_UNIT_ELEMENT);
results.add(HINTS);
+ results.add(LINTS);
results.add(INFER_STATIC_VARIABLE_TYPES_ERRORS);
results.add(INFERABLE_STATIC_VARIABLES_IN_UNIT);
results.add(LIBRARY_UNIT_ERRORS);
diff --git a/pkg/analysis_server/pubspec.yaml b/pkg/analysis_server/pubspec.yaml
index 0029437..95fcbe5 100644
--- a/pkg/analysis_server/pubspec.yaml
+++ b/pkg/analysis_server/pubspec.yaml
@@ -6,7 +6,7 @@
environment:
sdk: '>=1.9.0 <2.0.0'
dependencies:
- analyzer: '>=0.26.1+3 <0.27.0'
+ analyzer: '>=0.26.1+7 <0.27.0'
args: '>=0.13.0 <0.14.0'
dart_style: '>=0.2.0 <0.3.0'
logging: any
diff --git a/pkg/analysis_server/test/analysis/get_hover_test.dart b/pkg/analysis_server/test/analysis/get_hover_test.dart
index bda7c91..61520dc 100644
--- a/pkg/analysis_server/test/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/analysis/get_hover_test.dart
@@ -168,6 +168,31 @@
});
}
+ test_expression_parameter() {
+ addTestFile('''
+library my.library;
+class A {
+ /// The method documentation.
+ m(int p) {
+ }
+}
+''');
+ return prepareHover('p) {').then((HoverInformation hover) {
+ // element
+ expect(hover.containingLibraryName, isNull);
+ expect(hover.containingLibraryPath, isNull);
+ expect(hover.containingClassDescription, isNull);
+ expect(hover.dartdoc, 'The method documentation.');
+ expect(hover.elementDescription, 'int p');
+ expect(hover.elementKind, 'parameter');
+ // types
+ expect(hover.staticType, 'int');
+ expect(hover.propagatedType, isNull);
+ // no parameter
+ expect(hover.parameter, isNull);
+ });
+ }
+
test_expression_syntheticGetter() {
addTestFile('''
library my.library;
diff --git a/pkg/analysis_server/test/analysis/notification_errors_test.dart b/pkg/analysis_server/test/analysis/notification_errors_test.dart
index e03a380..aa841e3 100644
--- a/pkg/analysis_server/test/analysis/notification_errors_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_errors_test.dart
@@ -7,6 +7,7 @@
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/domain_analysis.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:unittest/unittest.dart';
@@ -35,6 +36,24 @@
server.handlers = [new AnalysisDomainHandler(server),];
}
+ test_importError() {
+ createProject();
+
+ addTestFile('''
+import 'does_not_exist.dart';
+''');
+ return waitForTasksFinished().then((_) {
+ List<AnalysisError> errors = filesErrors[testFile];
+ // Verify that we are generating only 1 error for the bad URI.
+ // https://github.com/dart-lang/sdk/issues/23754
+ expect(errors, hasLength(1));
+ AnalysisError error = errors[0];
+ expect(error.severity, AnalysisErrorSeverity.ERROR);
+ expect(error.type, AnalysisErrorType.COMPILE_TIME_ERROR);
+ expect(error.message, startsWith('Target of URI does not exist'));
+ });
+ }
+
test_notInAnalysisRoot() {
createProject();
String otherFile = '/other.dart';
diff --git a/pkg/analysis_server/test/analysis/notification_implemented_test.dart b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
index a26ff56..fc72b72 100644
--- a/pkg/analysis_server/test/analysis/notification_implemented_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
@@ -37,6 +37,9 @@
if (length == -1) {
length = findIdentifierLength(search);
}
+ if (implementedClasses == null) {
+ fail('No notification of impemented classes was received');
+ }
for (ImplementedClass clazz in implementedClasses) {
if (clazz.offset == offset && clazz.length == length) {
return;
@@ -57,6 +60,9 @@
if (length == -1) {
length = findIdentifierLength(search);
}
+ if (implementedMembers == null) {
+ fail('No notification of impemented members was received');
+ }
for (ImplementedMember member in implementedMembers) {
if (member.offset == offset && member.length == length) {
return;
@@ -77,6 +83,9 @@
if (length == -1) {
length = findIdentifierLength(search);
}
+ if (implementedMembers == null) {
+ fail('No notification of impemented members was received');
+ }
for (ImplementedMember member in implementedMembers) {
if (member.offset == offset) {
fail('Unexpected implemented member at $offset'
@@ -90,16 +99,12 @@
return createLocalMemoryIndex();
}
+ /**
+ * Subscribe for `IMPLEMENTED` and wait for the notification.
+ */
Future prepareImplementedElements() {
- addAnalysisSubscription(AnalysisService.IMPLEMENTED, testFile);
- Future waitForNotification(int times) {
- if (times == 0 || implementedClasses != null) {
- return new Future.value();
- }
- return new Future.delayed(
- Duration.ZERO, () => waitForNotification(times - 1));
- }
- return waitForNotification(100);
+ subscribeForImplemented();
+ return waitForImplementedElements();
}
void processNotification(Notification notification) {
@@ -117,6 +122,10 @@
createProject();
}
+ void subscribeForImplemented() {
+ addAnalysisSubscription(AnalysisService.IMPLEMENTED, testFile);
+ }
+
test_afterAnalysis() async {
addTestFile('''
class A {}
@@ -127,6 +136,25 @@
assertHasImplementedClass('A {');
}
+ test_afterIncrementalResolution() async {
+ subscribeForImplemented();
+ addTestFile('''
+class A {}
+class B extends A {}
+''');
+ await prepareImplementedElements();
+ assertHasImplementedClass('A {');
+ // add a space
+ implementedClasses = null;
+ testCode = '''
+class A {}
+class B extends A {}
+''';
+ server.updateContent('1', {testFile: new AddContentOverlay(testCode)});
+ await waitForImplementedElements();
+ assertHasImplementedClass('A {');
+ }
+
test_class_extended() async {
addTestFile('''
class A {}
@@ -286,4 +314,15 @@
await prepareImplementedElements();
assertHasImplementedMember('f(_) {} // A');
}
+
+ Future waitForImplementedElements() {
+ Future waitForNotification(int times) {
+ if (times == 0 || implementedClasses != null) {
+ return new Future.value();
+ }
+ return new Future.delayed(
+ new Duration(milliseconds:1), () => waitForNotification(times - 1));
+ }
+ return waitForNotification(30000);
+ }
}
diff --git a/pkg/analysis_server/test/analysis/notification_navigation_test.dart b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
index fee0d6f..6ef6b57 100644
--- a/pkg/analysis_server/test/analysis/notification_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
@@ -215,6 +215,113 @@
});
}
+ test_annotationConstructor_implicit() async {
+ addTestFile('''
+class A {
+}
+@A()
+main() {
+}
+''');
+ await prepareNavigation();
+ assertHasRegionString('A()', 'A'.length);
+ assertHasTarget('A {');
+ }
+
+ test_annotationConstructor_importPrefix() async {
+ addFile(
+ '$testFolder/my_annotation.dart',
+ r'''
+library an;
+class MyAnnotation {
+ const MyAnnotation();
+ const MyAnnotation.named();
+}
+''');
+ addTestFile('''
+import 'my_annotation.dart' as man;
+@man.MyAnnotation()
+@man.MyAnnotation.named()
+main() {
+}
+''');
+ await prepareNavigation();
+ assertHasRegion('MyAnnotation()');
+ assertHasRegion('MyAnnotation.named()');
+ assertHasRegion('named()');
+ {
+ assertHasRegion('man.MyAnnotation()');
+ assertHasTarget('man;');
+ }
+ {
+ assertHasRegion('man.MyAnnotation.named()');
+ assertHasTarget('man;');
+ }
+ }
+
+ test_annotationConstructor_named() async {
+ addTestFile('''
+class A {
+ const A.named(p);
+}
+@A.named(0)
+main() {
+}
+''');
+ await prepareNavigation();
+ {
+ assertHasRegion('A.named(0)');
+ assertHasTarget('named(p);');
+ }
+ {
+ assertHasRegion('named(0)');
+ assertHasTarget('named(p);');
+ }
+ }
+
+ test_annotationConstructor_unnamed() async {
+ addTestFile('''
+class A {
+ const A();
+}
+@A()
+main() {
+}
+''');
+ await prepareNavigation();
+ assertHasRegionString('A()', 'A'.length);
+ assertHasTarget('A();', 0);
+ }
+
+ test_annotationField() async {
+ addTestFile('''
+const myan = new Object();
+@myan // ref
+main() {
+}
+''');
+ await prepareNavigation();
+ assertHasRegion('myan // ref');
+ assertHasTarget('myan = new Object();');
+ }
+
+ test_annotationField_importPrefix() async {
+ addFile(
+ '$testFolder/mayn.dart',
+ r'''
+library an;
+const myan = new Object();
+''');
+ addTestFile('''
+import 'mayn.dart' as man;
+@man.myan // ref
+main() {
+}
+''');
+ await prepareNavigation();
+ assertHasRegion('myan // ref');
+ }
+
test_class_fromSDK() {
addTestFile('''
int V = 42;
diff --git a/pkg/analysis_server/test/analysis/notification_outline_test.dart b/pkg/analysis_server/test/analysis/notification_outline_test.dart
index fdac6b5..4840a2e 100644
--- a/pkg/analysis_server/test/analysis/notification_outline_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_outline_test.dart
@@ -21,6 +21,8 @@
@reflectiveTest
class _AnalysisNotificationOutlineTest extends AbstractAnalysisTest {
+ FileKind fileKind;
+ String libraryName;
Outline outline;
Future prepareOutline() {
@@ -32,6 +34,8 @@
if (notification.event == ANALYSIS_OUTLINE) {
var params = new AnalysisOutlineParams.fromNotification(notification);
if (params.file == testFile) {
+ fileKind = params.kind;
+ libraryName = params.libraryName;
outline = params.outline;
}
}
@@ -311,6 +315,43 @@
});
}
+ test_libraryName_hasLibraryDirective() async {
+ addTestFile('''
+library my.lib;
+''');
+ await prepareOutline();
+ expect(fileKind, FileKind.LIBRARY);
+ expect(libraryName, 'my.lib');
+ }
+
+ test_libraryName_hasLibraryPartOfDirectives() async {
+ addTestFile('''
+part of lib.in.part.of;
+library my.lib;
+''');
+ await prepareOutline();
+ expect(fileKind, FileKind.LIBRARY);
+ expect(libraryName, 'my.lib');
+ }
+
+ test_libraryName_hasPartOfDirective() async {
+ addTestFile('''
+part of my.lib;
+''');
+ await prepareOutline();
+ expect(fileKind, FileKind.PART);
+ expect(libraryName, 'my.lib');
+ }
+
+ test_libraryName_noDirectives() async {
+ addTestFile('''
+class A {}
+''');
+ await prepareOutline();
+ expect(fileKind, FileKind.LIBRARY);
+ expect(libraryName, isNull);
+ }
+
test_localFunctions() {
addTestFile('''
class A {
diff --git a/pkg/analysis_server/test/analysis/test_all.dart b/pkg/analysis_server/test/analysis/test_all.dart
index a14781f..468d420 100644
--- a/pkg/analysis_server/test/analysis/test_all.dart
+++ b/pkg/analysis_server/test/analysis/test_all.dart
@@ -27,7 +27,7 @@
*/
main() {
initializeTestEnvironment();
- group('search', () {
+ group('analysis', () {
get_errors_test.main();
get_hover_test.main();
get_navigation_test.main();
diff --git a/pkg/analysis_server/test/completion_test.dart b/pkg/analysis_server/test/completion_test.dart
index d602bde..7fc8d23 100644
--- a/pkg/analysis_server/test/completion_test.dart
+++ b/pkg/analysis_server/test/completion_test.dart
@@ -2851,7 +2851,7 @@
// test analysis of untyped fields and top-level vars
buildTests('test035', '''class Y {final x='hi';mth() {x.!1length;}}''',
- <String>["1+length"]);
+ <String>["1+length"], failingTests: '1');
// TODO(scheglov) decide what to do with Type for untyped field (not
// supported by the new store)
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 1202ef3..c1ccc99 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -6,9 +6,6 @@
import 'dart:async';
-import 'package:analysis_server/completion/completion_core.dart'
- show CompletionRequest, CompletionResult;
-import 'package:analysis_server/completion/completion_dart.dart' as newApi;
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/channel/channel.dart';
import 'package:analysis_server/src/constants.dart';
@@ -17,6 +14,10 @@
import 'package:analysis_server/src/domain_completion.dart';
import 'package:analysis_server/src/plugin/server_plugin.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart'
+ show CompletionRequest, CompletionResult;
+import 'package:analysis_server/src/provisional/completion/completion_dart.dart'
+ as newApi;
import 'package:analysis_server/src/services/completion/completion_manager.dart';
import 'package:analysis_server/src/services/completion/contribution_sorter.dart';
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
diff --git a/pkg/analysis_server/test/edit/organize_directives_test.dart b/pkg/analysis_server/test/edit/organize_directives_test.dart
index deb4ed9..821e4a4 100644
--- a/pkg/analysis_server/test/edit/organize_directives_test.dart
+++ b/pkg/analysis_server/test/edit/organize_directives_test.dart
@@ -65,6 +65,28 @@
response, isResponseFailure('0', RequestErrorCode.FILE_NOT_ANALYZED));
}
+ Future test_OK_remove_duplicateImports_withSamePrefix() {
+ addTestFile('''
+library lib;
+
+import 'dart:async' as async;
+import 'dart:async' as async;
+
+main() {
+ async.Future f;
+}
+''');
+ return _assertOrganized(r'''
+library lib;
+
+import 'dart:async' as async;
+
+main() {
+ async.Future f;
+}
+''');
+ }
+
Future test_OK_remove_unresolvedDirectives() {
addFile('$testFolder/existing_part1.dart', 'part of lib;');
addFile('$testFolder/existing_part2.dart', 'part of lib;');
diff --git a/pkg/analysis_server/test/integration/integration_test_methods.dart b/pkg/analysis_server/test/integration/integration_test_methods.dart
index 836f884..8ab5dca 100644
--- a/pkg/analysis_server/test/integration/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/integration_test_methods.dart
@@ -829,6 +829,18 @@
*
* The file with which the outline is associated.
*
+ * kind ( FileKind )
+ *
+ * The kind of the file.
+ *
+ * libraryName ( optional String )
+ *
+ * The name of the library defined by the file using a "library" directive,
+ * or referenced by a "part of" directive. If both "library" and "part of"
+ * directives are present, then the "library" directive takes precedence.
+ * This field will be omitted if the file has neither "library" nor "part
+ * of" directives.
+ *
* outline ( Outline )
*
* The outline associated with the file.
diff --git a/pkg/analysis_server/test/integration/integration_tests.dart b/pkg/analysis_server/test/integration/integration_tests.dart
index ed2d62a..6e7273e 100644
--- a/pkg/analysis_server/test/integration/integration_tests.dart
+++ b/pkg/analysis_server/test/integration/integration_tests.dart
@@ -597,7 +597,7 @@
{bool debugServer: false,
int diagnosticPort,
bool profileServer: false,
- bool newTaskModel: false,
+ bool newTaskModel: true,
bool useAnalysisHighlight2: false}) {
if (_process != null) {
throw new Exception('Process already started');
@@ -627,9 +627,11 @@
if (useAnalysisHighlight2) {
arguments.add('--useAnalysisHighlight2');
}
- if (newTaskModel) {
- arguments.add('--${analysisServer.Driver.ENABLE_NEW_TASK_MODEL}');
+ if (!newTaskModel) {
+ arguments.add('--${analysisServer.Driver.DISABLE_NEW_TASK_MODEL}');
}
+ print('Launching $serverPath');
+ print('$dartBinary ${arguments.join(' ')}');
return Process.start(dartBinary, arguments).then((Process process) {
_process = process;
process.exitCode.then((int code) {
diff --git a/pkg/analysis_server/test/integration/protocol_matchers.dart b/pkg/analysis_server/test/integration/protocol_matchers.dart
index 4d2bc54..347976e 100644
--- a/pkg/analysis_server/test/integration/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/protocol_matchers.dart
@@ -468,13 +468,18 @@
*
* {
* "file": FilePath
+ * "kind": FileKind
+ * "libraryName": optional String
* "outline": Outline
* }
*/
final Matcher isAnalysisOutlineParams = new LazyMatcher(() => new MatchesJsonObject(
"analysis.outline params", {
"file": isFilePath,
+ "kind": isFileKind,
"outline": isOutline
+ }, optionalFields: {
+ "libraryName": isString
}));
/**
@@ -1024,6 +1029,7 @@
* "location": Location
* "message": String
* "correction": optional String
+ * "hasFix": optional bool
* }
*/
final Matcher isAnalysisError = new LazyMatcher(() => new MatchesJsonObject(
@@ -1033,7 +1039,8 @@
"location": isLocation,
"message": isString
}, optionalFields: {
- "correction": isString
+ "correction": isString,
+ "hasFix": isBool
}));
/**
@@ -1379,6 +1386,19 @@
]);
/**
+ * FileKind
+ *
+ * enum {
+ * LIBRARY
+ * PART
+ * }
+ */
+final Matcher isFileKind = new MatchesEnum("FileKind", [
+ "LIBRARY",
+ "PART"
+]);
+
+/**
* FilePath
*
* String
@@ -2221,6 +2241,8 @@
* extractLocalVariable feedback
*
* {
+ * "coveringExpressionOffsets": List<int>
+ * "coveringExpressionLengths": List<int>
* "names": List<String>
* "offsets": List<int>
* "lengths": List<int>
@@ -2228,6 +2250,8 @@
*/
final Matcher isExtractLocalVariableFeedback = new LazyMatcher(() => new MatchesJsonObject(
"extractLocalVariable feedback", {
+ "coveringExpressionOffsets": isListOf(isInt),
+ "coveringExpressionLengths": isListOf(isInt),
"names": isListOf(isString),
"offsets": isListOf(isInt),
"lengths": isListOf(isInt)
diff --git a/pkg/analysis_server/test/protocol_server_test.dart b/pkg/analysis_server/test/protocol_server_test.dart
index 7abbe3f..d770e35 100644
--- a/pkg/analysis_server/test/protocol_server_test.dart
+++ b/pkg/analysis_server/test/protocol_server_test.dart
@@ -72,7 +72,8 @@
START_COLUMN: 2
},
MESSAGE: 'my message',
- CORRECTION: 'my correction'
+ CORRECTION: 'my correction',
+ HAS_FIX : false
});
}
@@ -89,7 +90,8 @@
START_LINE: 3,
START_COLUMN: 2
},
- MESSAGE: 'my message'
+ MESSAGE: 'my message',
+ HAS_FIX : false
});
}
@@ -106,7 +108,8 @@
START_LINE: -1,
START_COLUMN: -1
},
- MESSAGE: 'my message'
+ MESSAGE: 'my message',
+ HAS_FIX : false
});
}
}
diff --git a/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart b/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart
index 433448b..959b027 100644
--- a/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart
@@ -90,6 +90,17 @@
contributor = new ArgListContributor();
}
+ test_Annotation_local_constructor_named_param() {
+ //
+ addTestSource('''
+class A { A({int one, String two: 'defaultValue'}) { } }
+@A(^) main() { }''');
+ computeFast();
+ return computeFull((bool result) {
+ assertSuggestArguments(namedArguments: ['one', 'two']);
+ });
+ }
+
test_ArgumentList_getter() {
addTestSource('class A {int get foo => 7; main() {foo(^)}');
computeFast();
diff --git a/pkg/analysis_server/test/services/completion/completion_computer_test.dart b/pkg/analysis_server/test/services/completion/completion_computer_test.dart
index 0cdeff9..dddf75e 100644
--- a/pkg/analysis_server/test/services/completion/completion_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/completion_computer_test.dart
@@ -6,10 +6,10 @@
import 'dart:async';
-import 'package:analysis_server/completion/completion_core.dart'
- show CompletionRequest, CompletionResult;
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart'
+ show CompletionRequest, CompletionResult;
import 'package:analysis_server/src/services/completion/completion_manager.dart';
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
import 'package:analysis_server/src/services/index/index.dart';
@@ -94,26 +94,24 @@
switch (++count) {
case 1:
contributor1.assertCalls(context, source, 0, searchEngine);
+ expect(contributor1.fastCount, equals(1));
+ expect(contributor1.fullCount, equals(0));
contributor2.assertCalls(context, source, 0, searchEngine);
- expect(isLast, isFalse);
- expect(r.suggestions, hasLength(1));
- expect(r.suggestions, contains(suggestion1));
- resolveLibrary();
- break;
- case 2:
- contributor1.assertFull(0);
- contributor2.assertFull(1);
+ expect(contributor2.fastCount, equals(1));
+ expect(contributor2.fullCount, equals(1));
expect(isLast, isTrue);
expect(r.suggestions, hasLength(2));
expect(r.suggestions, contains(suggestion1));
expect(r.suggestions, contains(suggestion2));
+ resolveLibrary();
break;
default:
fail('unexpected');
}
}, onDone: () {
done = true;
- expect(count, equals(2));
+ // There is only one notification
+ expect(count, equals(1));
});
return pumpEventQueue().then((_) {
expect(done, isTrue);
@@ -134,7 +132,11 @@
switch (++count) {
case 1:
contributor1.assertCalls(context, source, 0, searchEngine);
+ expect(contributor1.fastCount, equals(1));
+ expect(contributor1.fullCount, equals(0));
contributor2.assertCalls(context, source, 0, searchEngine);
+ expect(contributor2.fastCount, equals(1));
+ expect(contributor2.fullCount, equals(0));
expect(isLast, isTrue);
expect(r.suggestions, hasLength(2));
expect(r.suggestions, contains(suggestion1));
@@ -170,14 +172,11 @@
MockCompletionContributor(this.fastSuggestion, this.fullSuggestion);
- assertCalls(AnalysisContext context, Source source, int offset,
- SearchEngine searchEngine) {
+ assertCalls(AnalysisContext context, Source source, int offset, SearchEngine searchEngine) {
expect(request.context, equals(context));
expect(request.source, equals(source));
expect(request.offset, equals(offset));
expect(request.searchEngine, equals(searchEngine));
- expect(this.fastCount, equals(1));
- expect(this.fullCount, equals(0));
}
assertFull(int fullCount) {
diff --git a/pkg/analysis_server/test/services/completion/completion_target_test.dart b/pkg/analysis_server/test/services/completion/completion_target_test.dart
index 6d0e52f..169874b 100644
--- a/pkg/analysis_server/test/services/completion/completion_target_test.dart
+++ b/pkg/analysis_server/test/services/completion/completion_target_test.dart
@@ -4,7 +4,7 @@
library test.services.completion.target;
-import 'package:analysis_server/completion/dart/completion_target.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/services/completion/completion_test_util.dart b/pkg/analysis_server/test/services/completion/completion_test_util.dart
index 94d9058..e9b24b4 100644
--- a/pkg/analysis_server/test/services/completion/completion_test_util.dart
+++ b/pkg/analysis_server/test/services/completion/completion_test_util.dart
@@ -10,9 +10,9 @@
import 'package:analysis_server/src/protocol.dart' as protocol
show Element, ElementKind;
import 'package:analysis_server/src/protocol.dart' hide Element, ElementKind;
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
import 'package:analysis_server/src/services/completion/common_usage_computer.dart';
import 'package:analysis_server/src/services/completion/completion_manager.dart';
-import 'package:analysis_server/completion/dart/completion_target.dart';
import 'package:analysis_server/src/services/completion/dart_completion_cache.dart';
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
import 'package:analysis_server/src/services/completion/imported_reference_contributor.dart';
@@ -1357,7 +1357,8 @@
//assertSuggestImportedTopLevelVar('T3', 'int', COMPLETION_RELEVANCE_LOW);
assertNotSuggested('_T4');
assertSuggestLocalTopLevelVar('T5', 'int');
- assertSuggestLocalTopLevelVar('_T6', null);
+ assertSuggestLocalTopLevelVar('_T6', null,
+ relevance: DART_RELEVANCE_DEFAULT);
assertNotSuggested('==');
assertSuggestLocalGetter('T7', 'String');
assertSuggestLocalSetter('T8');
@@ -3473,7 +3474,8 @@
expect(getterF.element.isDeprecated, isTrue);
expect(getterF.element.isPrivate, isFalse);
}
- CompletionSuggestion getterG = assertSuggestLocalGetter('_g', null);
+ CompletionSuggestion getterG = assertSuggestLocalGetter('_g', null,
+ relevance: DART_RELEVANCE_DEFAULT);
if (getterG != null) {
expect(getterG.element.isDeprecated, isFalse);
expect(getterG.element.isPrivate, isTrue);
@@ -3528,7 +3530,8 @@
return computeFull((bool result) {
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
- CompletionSuggestion methodA = assertSuggestLocalMethod('_a', 'A', 'Z');
+ CompletionSuggestion methodA = assertSuggestLocalMethod('_a', 'A', 'Z',
+ relevance: DART_RELEVANCE_DEFAULT);
if (methodA != null) {
expect(methodA.element.isDeprecated, isFalse);
expect(methodA.element.isPrivate, isTrue);
diff --git a/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart b/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart
index bf3c027..882efd9 100644
--- a/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart
@@ -85,7 +85,6 @@
Keyword.FOR,
Keyword.IF,
Keyword.NEW,
- Keyword.RETHROW,
Keyword.RETURN,
Keyword.SUPER,
Keyword.SWITCH,
@@ -107,7 +106,6 @@
Keyword.FOR,
Keyword.IF,
Keyword.NEW,
- Keyword.RETHROW,
Keyword.RETURN,
Keyword.SUPER,
Keyword.SWITCH,
@@ -130,7 +128,6 @@
Keyword.FOR,
Keyword.IF,
Keyword.NEW,
- Keyword.RETHROW,
Keyword.RETURN,
Keyword.SUPER,
Keyword.SWITCH,
@@ -153,7 +150,6 @@
Keyword.FOR,
Keyword.IF,
Keyword.NEW,
- Keyword.RETHROW,
Keyword.RETURN,
Keyword.SWITCH,
Keyword.THROW,
@@ -171,7 +167,6 @@
Keyword.FOR,
Keyword.IF,
Keyword.NEW,
- Keyword.RETHROW,
Keyword.RETURN,
Keyword.SWITCH,
Keyword.THROW,
@@ -191,7 +186,6 @@
Keyword.FOR,
Keyword.IF,
Keyword.NEW,
- Keyword.RETHROW,
Keyword.RETURN,
Keyword.SWITCH,
Keyword.THROW,
@@ -613,6 +607,16 @@
relevance: DART_RELEVANCE_KEYWORD);
}
+ test_catch() {
+ addTestSource('main() {try {} catch (e) {^}}}');
+ expect(computeFast(), isTrue);
+ var keywords = <Keyword>[];
+ keywords.addAll(STMT_START_OUTSIDE_CLASS);
+ keywords.add(Keyword.RETHROW);
+ assertSuggestKeywords(keywords,
+ relevance: DART_RELEVANCE_KEYWORD);
+ }
+
test_for_break_continue2() {
addTestSource('class A {foo() {for (int x in myList) {^}}}');
expect(computeFast(), isTrue);
diff --git a/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart
index cb29f97..94c0717 100644
--- a/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart
@@ -793,6 +793,20 @@
assertSuggestMethod('m', 'B', null, relevance: DART_RELEVANCE_LOCAL_METHOD);
}
+ test_prioritization_private() {
+ addTestSource('main() {var ab; var _ab; _^}');
+ expect(computeFast(), isTrue);
+ assertSuggestLocalVariable('ab', null);
+ assertSuggestLocalVariable('_ab', null);
+ }
+
+ test_prioritization_public() {
+ addTestSource('main() {var ab; var _ab; a^}');
+ expect(computeFast(), isTrue);
+ assertSuggestLocalVariable('ab', null);
+ assertSuggestLocalVariable('_ab', null, relevance: DART_RELEVANCE_DEFAULT);
+ }
+
test_shadowed_name() {
addTestSource('var a; class A { var a; m() { ^ } }');
expect(computeFast(), isTrue);
diff --git a/pkg/analysis_server/test/services/completion/optype_test.dart b/pkg/analysis_server/test/services/completion/optype_test.dart
index e2c654c..a2bf5c8 100644
--- a/pkg/analysis_server/test/services/completion/optype_test.dart
+++ b/pkg/analysis_server/test/services/completion/optype_test.dart
@@ -4,7 +4,7 @@
library test.services.completion.contributor.dart.optype;
-import 'package:analysis_server/completion/dart/completion_target.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
import 'package:analysis_server/src/services/completion/optype.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart';
diff --git a/pkg/analysis_server/test/services/completion/uri_contributor_test.dart b/pkg/analysis_server/test/services/completion/uri_contributor_test.dart
index 9742dbd..4a046a1 100644
--- a/pkg/analysis_server/test/services/completion/uri_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/uri_contributor_test.dart
@@ -186,6 +186,16 @@
csKind: CompletionSuggestionKind.IMPORT);
}
+ test_export_package2() {
+ addPackageSource('foo', 'foo.dart', 'library foo;');
+ addPackageSource('foo', 'baz/too.dart', 'library too;');
+ addPackageSource('bar', 'bar.dart', 'library bar;');
+ addTestSource('export "package:foo/baz/^" import');
+ computeFast();
+ assertSuggest('package:foo/baz/too.dart',
+ csKind: CompletionSuggestionKind.IMPORT);
+ }
+
test_import_package_missing_lib() {
var pkgSrc = addPackageSource('bar', 'bar.dart', 'library bar;');
provider.deleteFolder(dirname(pkgSrc.fullName));
diff --git a/pkg/analysis_server/test/services/correction/organize_directives_test.dart b/pkg/analysis_server/test/services/correction/organize_directives_test.dart
index 6c817b5..833cc49 100644
--- a/pkg/analysis_server/test/services/correction/organize_directives_test.dart
+++ b/pkg/analysis_server/test/services/correction/organize_directives_test.dart
@@ -22,6 +22,29 @@
class OrganizeDirectivesTest extends AbstractSingleUnitTest {
List<AnalysisError> testErrors;
+ void test_keep_duplicateImports_withDifferentPrefix() {
+ _computeUnitAndErrors(r'''
+import 'dart:async' as async1;
+import 'dart:async' as async2;
+
+main() {
+ async1.Future f;
+ async2.Stream s;
+}''');
+ // validate change
+ _assertOrganize(
+ r'''
+import 'dart:async' as async1;
+import 'dart:async' as async2;
+
+main() {
+ async1.Future f;
+ async2.Stream s;
+}''',
+ removeUnresolved: true,
+ removeUnused: true);
+ }
+
void test_remove_duplicateImports() {
_computeUnitAndErrors(r'''
import 'dart:async';
@@ -42,6 +65,46 @@
removeUnused: true);
}
+ void test_remove_duplicateImports_differentText_uri() {
+ _computeUnitAndErrors(r'''
+import 'dart:async' as async;
+import "dart:async" as async;
+
+main() {
+ async.Future f;
+}''');
+ // validate change
+ _assertOrganize(
+ r'''
+import 'dart:async' as async;
+
+main() {
+ async.Future f;
+}''',
+ removeUnresolved: true,
+ removeUnused: true);
+ }
+
+ void test_remove_duplicateImports_withSamePrefix() {
+ _computeUnitAndErrors(r'''
+import 'dart:async' as async;
+import 'dart:async' as async;
+
+main() {
+ async.Future f;
+}''');
+ // validate change
+ _assertOrganize(
+ r'''
+import 'dart:async' as async;
+
+main() {
+ async.Future f;
+}''',
+ removeUnresolved: true,
+ removeUnused: true);
+ }
+
void test_remove_unresolvedDirectives() {
addSource('/existing_part1.dart', 'part of lib;');
addSource('/existing_part2.dart', 'part of lib;');
diff --git a/pkg/analysis_server/test/services/index/store/codec_test.dart b/pkg/analysis_server/test/services/index/store/codec_test.dart
index 43dbe33..5e6d180 100644
--- a/pkg/analysis_server/test/services/index/store/codec_test.dart
+++ b/pkg/analysis_server/test/services/index/store/codec_test.dart
@@ -93,7 +93,7 @@
int id2 = codec.encode2(indexable);
int id3 = codec.encode3(indexable);
expect(id1, isNonNegative);
- expect(id2, isNonNegative);
+ expect(id2, -1);
expect(id3, IndexableElementKind.forElement(element).index);
validateDecode(id1, id2, id3, element);
}
@@ -106,7 +106,7 @@
int id2 = codec.encode2(indexable);
int id3 = codec.encode3(indexable);
expect(id1, isNonNegative);
- expect(id2, isNonNegative);
+ expect(id2, -1);
expect(id3, IndexableElementKind.forElement(element).index);
validateDecode(id1, id2, id3, element);
}
@@ -260,6 +260,7 @@
expect(id1, -1);
expect(id2, isNonNegative);
expect(id3, IndexableNameKind.INSTANCE.index);
+ expect(codec.decode(context, id1, id2, id3), indexable);
}
void test_encode_LibraryElement() {
@@ -274,7 +275,7 @@
int id2 = codec.encode2(indexable);
int id3 = codec.encode3(indexable);
expect(id1, isNonNegative);
- expect(id2, isNonNegative);
+ expect(id2, -1);
expect(id3, IndexableElementKind.forElement(element).index);
validateDecode(id1, id2, id3, element);
}
diff --git a/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart b/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
index 3f0ee70..d0b312b 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
@@ -582,6 +582,43 @@
assertPotentialEdits(['test(); // 1', 'test(); // 2']);
}
+ test_createChange_MethodElement_potential_inPubCache() async {
+ String pkgLib = '/.pub-cache/lib.dart';
+ indexUnit(
+ pkgLib,
+ r'''
+processObj(p) {
+ p.test();
+}
+''');
+ indexTestUnit('''
+import '$pkgLib';
+class A {
+ test() {}
+}
+main(var a) {
+ a.test();
+}
+''');
+ // configure refactoring
+ createRenameRefactoringAtString('test() {}');
+ expect(refactoring.refactoringName, 'Rename Method');
+ expect(refactoring.oldName, 'test');
+ refactoring.newName = 'newName';
+ // validate change
+ await assertSuccessfulRefactoring('''
+import '/.pub-cache/lib.dart';
+class A {
+ newName() {}
+}
+main(var a) {
+ a.newName();
+}
+''');
+ SourceFileEdit fileEdit = refactoringChange.getFileEdit(pkgLib);
+ expect(fileEdit, isNull);
+ }
+
test_createChange_MethodElement_potential_private_otherLibrary() async {
indexUnit(
'/lib.dart',
diff --git a/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart b/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
index 4c799d1..8e38f8f 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
@@ -224,6 +224,48 @@
assertRefactoringStatusOK(status);
}
+ test_checkInitialConditions_inPubCache_posix() async {
+ addSource(
+ '/.pub-cache/lib.dart',
+ r'''
+class A {}
+''');
+ indexTestUnit('''
+import '/.pub-cache/lib.dart';
+main() {
+ A a;
+}
+''');
+ createRenameRefactoringAtString('A a');
+ // check status
+ refactoring.newName = 'NewName';
+ RefactoringStatus status = await refactoring.checkInitialConditions();
+ assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL,
+ expectedMessage:
+ "The class 'A' is defined in a pub package, so cannot be renamed.");
+ }
+
+ test_checkInitialConditions_inPubCache_windows() async {
+ addSource(
+ '/Pub/Cache/lib.dart',
+ r'''
+class A {}
+''');
+ indexTestUnit('''
+import '/Pub/Cache/lib.dart';
+main() {
+ A a;
+}
+''');
+ createRenameRefactoringAtString('A a');
+ // check status
+ refactoring.newName = 'NewName';
+ RefactoringStatus status = await refactoring.checkInitialConditions();
+ assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL,
+ expectedMessage:
+ "The class 'A' is defined in a pub package, so cannot be renamed.");
+ }
+
test_checkInitialConditions_inSDK() async {
indexTestUnit('''
main() {
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/AnalysisError.java b/pkg/analysis_server/tool/spec/generated/java/types/AnalysisError.java
index c85d882..baf27c0 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/AnalysisError.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/AnalysisError.java
@@ -72,14 +72,26 @@
private final String correction;
/**
+ * A hint to indicate to interested clients that this error has an associated fix (or fixes). The
+ * absence of this field implies there are not known to be fixes. Note that since the operation to
+ * calculate whether fixes apply needs to be performant it is possible that complicated tests will
+ * be skipped and a false negative returned. For this reason, this attribute should be treated as a
+ * "hint". Despite the possibility of false negatives, no false positives should be returned. If a
+ * client sees this flag set they can proceed with the confidence that there are in fact associated
+ * fixes.
+ */
+ private final Boolean hasFix;
+
+ /**
* Constructor for {@link AnalysisError}.
*/
- public AnalysisError(String severity, String type, Location location, String message, String correction) {
+ public AnalysisError(String severity, String type, Location location, String message, String correction, Boolean hasFix) {
this.severity = severity;
this.type = type;
this.location = location;
this.message = message;
this.correction = correction;
+ this.hasFix = hasFix;
}
@Override
@@ -91,7 +103,8 @@
ObjectUtilities.equals(other.type, type) &&
ObjectUtilities.equals(other.location, location) &&
ObjectUtilities.equals(other.message, message) &&
- ObjectUtilities.equals(other.correction, correction);
+ ObjectUtilities.equals(other.correction, correction) &&
+ ObjectUtilities.equals(other.hasFix, hasFix);
}
return false;
}
@@ -102,7 +115,8 @@
Location location = Location.fromJson(jsonObject.get("location").getAsJsonObject());
String message = jsonObject.get("message").getAsString();
String correction = jsonObject.get("correction") == null ? null : jsonObject.get("correction").getAsString();
- return new AnalysisError(severity, type, location, message, correction);
+ Boolean hasFix = jsonObject.get("hasFix") == null ? null : jsonObject.get("hasFix").getAsBoolean();
+ return new AnalysisError(severity, type, location, message, correction, hasFix);
}
public static List<AnalysisError> fromJsonArray(JsonArray jsonArray) {
@@ -127,6 +141,19 @@
}
/**
+ * A hint to indicate to interested clients that this error has an associated fix (or fixes). The
+ * absence of this field implies there are not known to be fixes. Note that since the operation to
+ * calculate whether fixes apply needs to be performant it is possible that complicated tests will
+ * be skipped and a false negative returned. For this reason, this attribute should be treated as a
+ * "hint". Despite the possibility of false negatives, no false positives should be returned. If a
+ * client sees this flag set they can proceed with the confidence that there are in fact associated
+ * fixes.
+ */
+ public Boolean getHasFix() {
+ return hasFix;
+ }
+
+ /**
* The location associated with the error.
*/
public Location getLocation() {
@@ -163,6 +190,7 @@
builder.append(location);
builder.append(message);
builder.append(correction);
+ builder.append(hasFix);
return builder.toHashCode();
}
@@ -175,6 +203,9 @@
if (correction != null) {
jsonObject.addProperty("correction", correction);
}
+ if (hasFix != null) {
+ jsonObject.addProperty("hasFix", hasFix);
+ }
return jsonObject;
}
@@ -191,7 +222,9 @@
builder.append("message=");
builder.append(message + ", ");
builder.append("correction=");
- builder.append(correction);
+ builder.append(correction + ", ");
+ builder.append("hasFix=");
+ builder.append(hasFix);
builder.append("]");
return builder.toString();
}
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/ExtractLocalVariableFeedback.java b/pkg/analysis_server/tool/spec/generated/java/types/ExtractLocalVariableFeedback.java
index c329329..e00506d 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/ExtractLocalVariableFeedback.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/ExtractLocalVariableFeedback.java
@@ -42,6 +42,18 @@
public static final List<ExtractLocalVariableFeedback> EMPTY_LIST = Lists.newArrayList();
/**
+ * The offsets of the expressions that cover the specified selection, from the down most to the up
+ * most.
+ */
+ private final int[] coveringExpressionOffsets;
+
+ /**
+ * The lengths of the expressions that cover the specified selection, from the down most to the up
+ * most.
+ */
+ private final int[] coveringExpressionLengths;
+
+ /**
* The proposed names for the local variable.
*/
private final List<String> names;
@@ -61,7 +73,9 @@
/**
* Constructor for {@link ExtractLocalVariableFeedback}.
*/
- public ExtractLocalVariableFeedback(List<String> names, int[] offsets, int[] lengths) {
+ public ExtractLocalVariableFeedback(int[] coveringExpressionOffsets, int[] coveringExpressionLengths, List<String> names, int[] offsets, int[] lengths) {
+ this.coveringExpressionOffsets = coveringExpressionOffsets;
+ this.coveringExpressionLengths = coveringExpressionLengths;
this.names = names;
this.offsets = offsets;
this.lengths = lengths;
@@ -72,6 +86,8 @@
if (obj instanceof ExtractLocalVariableFeedback) {
ExtractLocalVariableFeedback other = (ExtractLocalVariableFeedback) obj;
return
+ Arrays.equals(other.coveringExpressionOffsets, coveringExpressionOffsets) &&
+ Arrays.equals(other.coveringExpressionLengths, coveringExpressionLengths) &&
ObjectUtilities.equals(other.names, names) &&
Arrays.equals(other.offsets, offsets) &&
Arrays.equals(other.lengths, lengths);
@@ -80,10 +96,12 @@
}
public static ExtractLocalVariableFeedback fromJson(JsonObject jsonObject) {
+ int[] coveringExpressionOffsets = JsonUtilities.decodeIntArray(jsonObject.get("coveringExpressionOffsets").getAsJsonArray());
+ int[] coveringExpressionLengths = JsonUtilities.decodeIntArray(jsonObject.get("coveringExpressionLengths").getAsJsonArray());
List<String> names = JsonUtilities.decodeStringList(jsonObject.get("names").getAsJsonArray());
int[] offsets = JsonUtilities.decodeIntArray(jsonObject.get("offsets").getAsJsonArray());
int[] lengths = JsonUtilities.decodeIntArray(jsonObject.get("lengths").getAsJsonArray());
- return new ExtractLocalVariableFeedback(names, offsets, lengths);
+ return new ExtractLocalVariableFeedback(coveringExpressionOffsets, coveringExpressionLengths, names, offsets, lengths);
}
public static List<ExtractLocalVariableFeedback> fromJsonArray(JsonArray jsonArray) {
@@ -99,6 +117,22 @@
}
/**
+ * The lengths of the expressions that cover the specified selection, from the down most to the up
+ * most.
+ */
+ public int[] getCoveringExpressionLengths() {
+ return coveringExpressionLengths;
+ }
+
+ /**
+ * The offsets of the expressions that cover the specified selection, from the down most to the up
+ * most.
+ */
+ public int[] getCoveringExpressionOffsets() {
+ return coveringExpressionOffsets;
+ }
+
+ /**
* The lengths of the expressions that would be replaced by a reference to the variable. The
* lengths correspond to the offsets. In other words, for a given expression, if the offset of that
* expression is offsets[i], then the length of that expression is lengths[i].
@@ -124,6 +158,8 @@
@Override
public int hashCode() {
HashCodeBuilder builder = new HashCodeBuilder();
+ builder.append(coveringExpressionOffsets);
+ builder.append(coveringExpressionLengths);
builder.append(names);
builder.append(offsets);
builder.append(lengths);
@@ -132,6 +168,16 @@
public JsonObject toJson() {
JsonObject jsonObject = new JsonObject();
+ JsonArray jsonArrayCoveringExpressionOffsets = new JsonArray();
+ for (int elt : coveringExpressionOffsets) {
+ jsonArrayCoveringExpressionOffsets.add(new JsonPrimitive(elt));
+ }
+ jsonObject.add("coveringExpressionOffsets", jsonArrayCoveringExpressionOffsets);
+ JsonArray jsonArrayCoveringExpressionLengths = new JsonArray();
+ for (int elt : coveringExpressionLengths) {
+ jsonArrayCoveringExpressionLengths.add(new JsonPrimitive(elt));
+ }
+ jsonObject.add("coveringExpressionLengths", jsonArrayCoveringExpressionLengths);
JsonArray jsonArrayNames = new JsonArray();
for (String elt : names) {
jsonArrayNames.add(new JsonPrimitive(elt));
@@ -154,6 +200,10 @@
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("[");
+ builder.append("coveringExpressionOffsets=");
+ builder.append(StringUtils.join(coveringExpressionOffsets, ", ") + ", ");
+ builder.append("coveringExpressionLengths=");
+ builder.append(StringUtils.join(coveringExpressionLengths, ", ") + ", ");
builder.append("names=");
builder.append(StringUtils.join(names, ", ") + ", ");
builder.append("offsets=");
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/FileKind.java b/pkg/analysis_server/tool/spec/generated/java/types/FileKind.java
new file mode 100644
index 0000000..d9ba7bb
--- /dev/null
+++ b/pkg/analysis_server/tool/spec/generated/java/types/FileKind.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, the Dart project authors.
+ *
+ * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ *
+ * This file has been automatically generated. Please do not edit it manually.
+ * To regenerate the file, use the script "pkg/analysis_server/tool/spec/generate_files".
+ */
+package org.dartlang.analysis.server.protocol;
+
+/**
+ * An enumeration of the kinds of files.
+ *
+ * @coverage dart.server.generated.types
+ */
+public class FileKind {
+
+ public static final String LIBRARY = "LIBRARY";
+
+ public static final String PART = "PART";
+
+}
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index c913011..a48d987 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -6,7 +6,7 @@
</head>
<body>
<h1>Analysis Server API Specification</h1>
- <h1 style="color:#999999">Version <version>1.9.0</version></h1>
+ <h1 style="color:#999999">Version <version>1.12.0</version></h1>
<p>
This document contains a specification of the API provided by the
analysis server. The API in this document is currently under
@@ -1044,6 +1044,23 @@
The file with which the outline is associated.
</p>
</field>
+ <field name="kind">
+ <ref>FileKind</ref>
+ <p>
+ The kind of the file.
+ </p>
+ </field>
+ <field name="libraryName" optional="true">
+ <ref>String</ref>
+ <p>
+ The name of the library defined by the file using a "library"
+ directive, or referenced by a "part of" directive. If both
+ "library" and "part of" directives are present, then the
+ "library" directive takes precedence.
+ This field will be omitted if the file has neither "library"
+ nor "part of" directives.
+ </p>
+ </field>
<field name="outline">
<ref>Outline</ref>
<p>
@@ -2010,6 +2027,21 @@
message associated with the error code.
</p>
</field>
+ <field name="hasFix" optional="true">
+ <ref>bool</ref>
+ <p>
+ A hint to indicate to interested clients that this error has
+ an associated fix (or fixes). The absence of this field implies
+ there are not known to be fixes. Note that since the operation
+ to calculate whether fixes apply needs to be performant it is
+ possible that complicated tests will be skipped and a false
+ negative returned. For this reason, this attribute should be
+ treated as a "hint". Despite the possibility of false negatives,
+ no false positives should be returned. If a client sees this
+ flag set they can proceed with the confidence that there are in
+ fact associated fixes.
+ </p>
+ </field>
</object>
</type>
<type name="AnalysisErrorFixes">
@@ -2551,6 +2583,15 @@
<value><code>LAUNCH_DATA</code></value>
</enum>
</type>
+ <type name="FileKind">
+ <p>
+ An enumeration of the kinds of files.
+ </p>
+ <enum>
+ <value><code>LIBRARY</code></value>
+ <value><code>PART</code></value>
+ </enum>
+ </type>
<type name="FilePath">
<ref>String</ref>
<p>
@@ -3985,14 +4026,28 @@
</refactoring>
<refactoring kind="EXTRACT_LOCAL_VARIABLE">
<p>
- Create a local variable initialized by a specified
- expression.
+ Create a local variable initialized by the expression that covers
+ the specified selection.
</p>
<p>
- It is an error if the range contains anything other than a
- complete expression (no partial expressions are allowed).
+ It is an error if the selection range is not covered by a
+ complete expression.
</p>
<feedback>
+ <field name="coveringExpressionOffsets">
+ <list><ref>int</ref></list>
+ <p>
+ The offsets of the expressions that cover the specified
+ selection, from the down most to the up most.
+ </p>
+ </field>
+ <field name="coveringExpressionLengths">
+ <list><ref>int</ref></list>
+ <p>
+ The lengths of the expressions that cover the specified
+ selection, from the down most to the up most.
+ </p>
+ </field>
<field name="names">
<list><ref>String</ref></list>
<p>
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index b39f429..c555f1b 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -27,7 +27,6 @@
import 'package:analyzer/src/generated/java_core.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/scanner.dart';
import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_collection.dart';
@@ -572,31 +571,13 @@
if (source == null) {
return null;
}
- CompilationUnit unit = parseCompilationUnit(source);
- if (unit == null) {
+ SourceRange docRange = element.docRange;
+ if (docRange == null) {
return null;
}
- NodeLocator locator = new NodeLocator(element.nameOffset);
- AstNode nameNode = locator.searchWithin(unit);
- while (nameNode != null) {
- if (nameNode is AnnotatedNode) {
- Comment comment = nameNode.documentationComment;
- if (comment == null) {
- return null;
- }
- StringBuffer buffer = new StringBuffer();
- List<Token> tokens = comment.tokens;
- for (int i = 0; i < tokens.length; i++) {
- if (i > 0) {
- buffer.write("\n");
- }
- buffer.write(tokens[i].lexeme);
- }
- return buffer.toString();
- }
- nameNode = nameNode.parent;
- }
- return null;
+ String code = getContents(source).data;
+ String comment = code.substring(docRange.offset, docRange.end);
+ return comment.replaceAll('\r\n', '\n');
}
@override
@@ -1157,7 +1138,7 @@
new LibrarySpecificUnit(librarySource, librarySource);
entry = getCacheEntry(unit);
setValue(HINTS, AnalysisError.NO_ERRORS);
- // dartEntry.setValue(LINTS, AnalysisError.NO_ERRORS);
+ setValue(LINTS, AnalysisError.NO_ERRORS);
setValue(INFER_STATIC_VARIABLE_TYPES_ERRORS, AnalysisError.NO_ERRORS);
setValue(LIBRARY_UNIT_ERRORS, AnalysisError.NO_ERRORS);
setValue(PARTIALLY_RESOLVE_REFERENCES_ERRORS, AnalysisError.NO_ERRORS);
@@ -1654,16 +1635,16 @@
return;
}
}
-// if (lintsEnabled) {
-// state = unitEntry.getState(LINTS);
-// if (state == CacheState.INVALID ||
-// (isPriority && state == CacheState.FLUSHED)) {
-// sources.add(source);
-// return;
-// } else if (state == CacheState.ERROR) {
-// return;
-// }
-// }
+ if (lintsEnabled) {
+ state = unitEntry.getState(LINTS);
+ if (state == CacheState.INVALID ||
+ (isPriority && state == CacheState.FLUSHED)) {
+ sources.add(source);
+ return;
+ } else if (state == CacheState.ERROR) {
+ return;
+ }
+ }
}
}
// } else if (kind == SourceKind.HTML) {
@@ -1896,8 +1877,7 @@
sourceEntry,
unitEntry,
oldUnit,
- analysisOptions.incrementalApi,
- analysisOptions);
+ analysisOptions.incrementalApi);
bool success = resolver.resolve(newCode);
AnalysisEngine.instance.instrumentationService.logPerformance(
AnalysisPerformanceKind.INCREMENTAL,
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index bff8b4e..30aa17e 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -2462,6 +2462,12 @@
String get displayName;
/**
+ * Return the source range of the documentation comment for this element,
+ * or `null` if this element does not or cannot have a documentation.
+ */
+ SourceRange get docRange;
+
+ /**
* Return the element that either physically or logically encloses this
* element. This will be `null` if this element is a library because libraries
* are the top-level elements in the model.
@@ -2828,6 +2834,17 @@
ElementLocation _cachedLocation;
/**
+ * The offset to the beginning of the documentation comment,
+ * or `null` if this element does not have a documentation comment.
+ */
+ int _docRangeOffset;
+
+ /**
+ * The length of the documentation comment range for this element.
+ */
+ int _docRangeLength;
+
+ /**
* Initialize a newly created element to have the given [name] at the given
* [_nameOffset].
*/
@@ -2853,6 +2870,14 @@
String get displayName => _name;
@override
+ SourceRange get docRange {
+ if (_docRangeOffset != null && _docRangeLength != null) {
+ return new SourceRange(_docRangeOffset, _docRangeLength);
+ }
+ return null;
+ }
+
+ @override
Element get enclosingElement => _enclosingElement;
/**
@@ -3102,6 +3127,14 @@
}
/**
+ * Set the documentation comment source range for this element.
+ */
+ void setDocRange(int offset, int length) {
+ _docRangeOffset = offset;
+ _docRangeLength = length;
+ }
+
+ /**
* Set whether the given [modifier] is associated with this element to
* correspond to the given [value].
*/
@@ -7917,6 +7950,9 @@
@override
String get displayName => _baseElement.displayName;
+ @override
+ SourceRange get docRange => _baseElement.docRange;
+
int get id => _baseElement.id;
@override
@@ -8427,6 +8463,9 @@
String get displayName => _name;
@override
+ SourceRange get docRange => null;
+
+ @override
Element get enclosingElement => null;
@override
diff --git a/pkg/analyzer/lib/src/generated/element_handle.dart b/pkg/analyzer/lib/src/generated/element_handle.dart
index 35af627..338a279 100644
--- a/pkg/analyzer/lib/src/generated/element_handle.dart
+++ b/pkg/analyzer/lib/src/generated/element_handle.dart
@@ -337,6 +337,9 @@
String get displayName => actualElement.displayName;
@override
+ SourceRange get docRange => actualElement.docRange;
+
+ @override
Element get enclosingElement => actualElement.enclosingElement;
@override
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index a57cc05..9560bff 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -1641,31 +1641,13 @@
if (source == null) {
return null;
}
- CompilationUnit unit = parseCompilationUnit(source);
- if (unit == null) {
+ SourceRange docRange = element.docRange;
+ if (docRange == null) {
return null;
}
- NodeLocator locator = new NodeLocator(element.nameOffset);
- AstNode nameNode = locator.searchWithin(unit);
- while (nameNode != null) {
- if (nameNode is AnnotatedNode) {
- Comment comment = nameNode.documentationComment;
- if (comment == null) {
- return null;
- }
- StringBuffer buffer = new StringBuffer();
- List<Token> tokens = comment.tokens;
- for (int i = 0; i < tokens.length; i++) {
- if (i > 0) {
- buffer.write("\n");
- }
- buffer.write(tokens[i].lexeme);
- }
- return buffer.toString();
- }
- nameNode = nameNode.parent;
- }
- return null;
+ String code = getContents(source).data;
+ String comment = code.substring(docRange.offset, docRange.end);
+ return comment.replaceAll('\r\n', '\n');
}
@override
@@ -4886,8 +4868,7 @@
null,
null,
oldUnit,
- analysisOptions.incrementalApi,
- analysisOptions);
+ analysisOptions.incrementalApi);
bool success = resolver.resolve(newCode);
AnalysisEngine.instance.instrumentationService.logPerformance(
AnalysisPerformanceKind.INCREMENTAL,
@@ -8792,8 +8773,10 @@
AnalysisEngine.instance.instrumentationService
.logFileRead(source.fullName, _modificationTime, _content);
} catch (exception, stackTrace) {
- errors.add(new AnalysisError(
- source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [exception]));
+ if (source.exists()) {
+ errors.add(new AnalysisError(
+ source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [exception]));
+ }
throw new AnalysisException("Could not get contents of $source",
new CaughtException(exception, stackTrace));
}
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 832bb00..7c8516e 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -943,7 +943,6 @@
@override
Object visitPropertyAccess(PropertyAccess node) {
- bool isConditional = node.operator.type == sc.TokenType.QUESTION_PERIOD;
ClassElement typeReference =
ElementResolver.getTypeReference(node.realTarget);
SimpleIdentifier propertyName = node.propertyName;
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 46cd677..15bbec9 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -493,6 +493,24 @@
_assertCompatibleParameter(node.parameter, element);
} else if (node is FieldFormalParameter) {
_assertTrue(element.isInitializingFormal);
+ DartType parameterType = element.type;
+ if (node.type == null && node.parameters == null) {
+ FieldFormalParameterElement parameterElement = element;
+ if (!parameterElement.hasImplicitType) {
+ _assertTrue(parameterType == null || parameterType.isDynamic);
+ }
+ if (parameterElement.field != null) {
+ _assertEquals(node.identifier.name, element.name);
+ }
+ } else {
+ if (node.parameters != null) {
+ _assertTrue(parameterType is FunctionType);
+ FunctionType parameterFunctionType = parameterType;
+ _assertSameType(node.type, parameterFunctionType.returnType);
+ } else {
+ _assertSameType(node.type, parameterType);
+ }
+ }
_assertCompatibleParameters(node.parameters, element.parameters);
} else if (node is FunctionTypedFormalParameter) {
_assertFalse(element.isInitializingFormal);
@@ -1044,8 +1062,6 @@
_context.invalidateLibraryHints(_librarySource);
// update entry errors
_updateEntry();
- // notify unit
- _definingUnit.afterIncrementalResolution();
// OK
return true;
} finally {
@@ -1223,6 +1239,7 @@
void _shiftEntryErrors_NEW() {
_shiftErrors_NEW(HINTS);
+ _shiftErrors_NEW(LINTS);
_shiftErrors_NEW(INFER_STATIC_VARIABLE_TYPES_ERRORS);
_shiftErrors_NEW(LIBRARY_UNIT_ERRORS);
_shiftErrors_NEW(PARTIALLY_RESOLVE_REFERENCES_ERRORS);
@@ -1279,6 +1296,7 @@
try {
_definingUnit
.accept(new _ElementNameOffsetUpdater(_updateOffset, _updateDelta));
+ _definingUnit.afterIncrementalResolution();
} finally {
timer.stop('update element offsets');
}
@@ -1303,6 +1321,7 @@
newUnitEntry.setState(USED_IMPORTED_ELEMENTS, CacheState.INVALID);
newUnitEntry.setState(USED_LOCAL_ELEMENTS, CacheState.INVALID);
newUnitEntry.setState(HINTS, CacheState.INVALID);
+ newUnitEntry.setState(LINTS, CacheState.INVALID);
}
void _updateEntry_OLD() {
@@ -1392,7 +1411,6 @@
CacheEntry _newUnitEntry;
final CompilationUnit _oldUnit;
- final AnalysisOptions _options;
CompilationUnitElement _unitElement;
int _updateOffset;
@@ -1411,8 +1429,7 @@
this._newSourceEntry,
this._newUnitEntry,
this._oldUnit,
- bool resolveApiChanges,
- this._options) {
+ bool resolveApiChanges) {
_resolveApiChanges = resolveApiChanges;
}
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 0a197f5..908c297 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -44,6 +44,10 @@
typedef void VoidFunction();
+typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited);
+
+typedef bool _SubtypeChecker<T>(T t1, T t2);
+
/**
* Instances of the class `BestPracticesVerifier` traverse an AST structure looking for
* violations of Dart best practices.
@@ -2511,6 +2515,7 @@
//
constructors = _createDefaultConstructors(interfaceType);
}
+ _setDocRange(element, node);
element.abstract = node.isAbstract;
element.accessors = holder.accessors;
element.constructors = constructors;
@@ -2584,6 +2589,7 @@
SimpleIdentifier constructorName = node.name;
ConstructorElementImpl element =
new ConstructorElementImpl.forNode(constructorName);
+ _setDocRange(element, node);
if (node.externalKeyword != null) {
element.external = true;
}
@@ -2688,6 +2694,7 @@
SimpleIdentifier enumName = node.name;
ClassElementImpl enumElement = new ClassElementImpl.forNode(enumName);
enumElement.enum2 = true;
+ _setDocRange(enumElement, node);
InterfaceTypeImpl enumType = new InterfaceTypeImpl(enumElement);
enumElement.type = enumType;
// The equivalent code for enums in the spec shows a single constructor,
@@ -2760,6 +2767,7 @@
SimpleIdentifier functionName = node.name;
FunctionElementImpl element =
new FunctionElementImpl.forNode(functionName);
+ _setDocRange(element, node);
if (node.externalKeyword != null) {
element.external = true;
}
@@ -2806,6 +2814,7 @@
if (node.isGetter) {
PropertyAccessorElementImpl getter =
new PropertyAccessorElementImpl.forNode(propertyNameNode);
+ _setDocRange(getter, node);
if (node.externalKeyword != null) {
getter.external = true;
}
@@ -2831,6 +2840,7 @@
} else {
PropertyAccessorElementImpl setter =
new PropertyAccessorElementImpl.forNode(propertyNameNode);
+ _setDocRange(setter, node);
if (node.externalKeyword != null) {
setter.external = true;
}
@@ -2917,6 +2927,7 @@
List<TypeParameterElement> typeParameters = holder.typeParameters;
FunctionTypeAliasElementImpl element =
new FunctionTypeAliasElementImpl.forNode(aliasName);
+ _setDocRange(element, node);
element.parameters = parameters;
element.typeParameters = typeParameters;
FunctionTypeImpl type = new FunctionTypeImpl.forTypedef(element);
@@ -2988,6 +2999,7 @@
}
MethodElementImpl element =
new MethodElementImpl(nameOfMethod, methodName.offset);
+ _setDocRange(element, node);
element.abstract = node.isAbstract;
if (node.externalKeyword != null) {
element.external = true;
@@ -3024,6 +3036,7 @@
if (node.isGetter) {
PropertyAccessorElementImpl getter =
new PropertyAccessorElementImpl.forNode(propertyNameNode);
+ _setDocRange(getter, node);
if (node.externalKeyword != null) {
getter.external = true;
}
@@ -3049,6 +3062,7 @@
} else {
PropertyAccessorElementImpl setter =
new PropertyAccessorElementImpl.forNode(propertyNameNode);
+ _setDocRange(setter, node);
if (node.externalKeyword != null) {
setter.external = true;
}
@@ -3185,6 +3199,9 @@
field = new FieldElementImpl.forNode(fieldName);
}
element = field;
+ if (node.parent.parent is FieldDeclaration) {
+ _setDocRange(element, node.parent.parent);
+ }
if ((node.parent as VariableDeclarationList).type == null) {
field.hasImplicitType = true;
}
@@ -3350,6 +3367,17 @@
}
/**
+ * If the given [node] has a documentation comment, remember its range
+ * into the given [element].
+ */
+ void _setDocRange(ElementImpl element, AnnotatedNode node) {
+ Comment comment = node.documentationComment;
+ if (comment != null && comment.isDocumentation) {
+ element.setDocRange(comment.offset, comment.length);
+ }
+ }
+
+ /**
* Sets the visible source range for formal parameter.
*/
void _setParameterVisibleRange(
@@ -7060,6 +7088,7 @@
.buildCompilationUnit(
librarySource, definingCompilationUnit, librarySource);
NodeList<Directive> directives = definingCompilationUnit.directives;
+ LibraryDirective libraryDirective = null;
LibraryIdentifier libraryNameNode = null;
bool hasPartDirective = false;
FunctionElement entryPoint =
@@ -7077,6 +7106,7 @@
//
if (directive is LibraryDirective) {
if (libraryNameNode == null) {
+ libraryDirective = directive;
libraryNameNode = directive.name;
directivesToResolve.add(directive);
}
@@ -7135,6 +7165,7 @@
//
LibraryElementImpl libraryElement = new LibraryElementImpl.forNode(
_analysisContext.getContextFor(librarySource), libraryNameNode);
+ _setDocRange(libraryElement, libraryDirective);
libraryElement.definingCompilationUnit = definingCompilationUnitElement;
if (entryPoint != null) {
libraryElement.entryPoint = entryPoint;
@@ -7166,6 +7197,7 @@
.buildCompilationUnit(
librarySource, definingCompilationUnit, librarySource);
NodeList<Directive> directives = definingCompilationUnit.directives;
+ LibraryDirective libraryDirective = null;
LibraryIdentifier libraryNameNode = null;
bool hasPartDirective = false;
FunctionElement entryPoint =
@@ -7183,6 +7215,7 @@
//
if (directive is LibraryDirective) {
if (libraryNameNode == null) {
+ libraryDirective = directive;
libraryNameNode = directive.name;
directivesToResolve.add(directive);
}
@@ -7243,6 +7276,7 @@
//
LibraryElementImpl libraryElement = new LibraryElementImpl.forNode(
_analysisContext.getContextFor(librarySource), libraryNameNode);
+ _setDocRange(libraryElement, libraryDirective);
libraryElement.definingCompilationUnit = definingCompilationUnitElement;
if (entryPoint != null) {
libraryElement.entryPoint = entryPoint;
@@ -7346,6 +7380,19 @@
}
}
}
+
+ /**
+ * If the given [node] has a documentation comment, remember its range
+ * into the given [element].
+ */
+ void _setDocRange(ElementImpl element, LibraryDirective node) {
+ if (node != null) {
+ Comment comment = node.documentationComment;
+ if (comment != null && comment.isDocumentation) {
+ element.setDocRange(comment.offset, comment.length);
+ }
+ }
+ }
}
/**
@@ -8928,46 +8975,6 @@
}
/**
- * Instances of the class `TypeAliasInfo` hold information about a [TypeAlias].
- */
-class LibraryResolver2_TypeAliasInfo {
- final ResolvableLibrary _library;
-
- final Source _source;
-
- final FunctionTypeAlias _typeAlias;
-
- /**
- * Initialize a newly created information holder with the given information.
- *
- * @param library the library containing the type alias
- * @param source the source of the file containing the type alias
- * @param typeAlias the type alias being remembered
- */
- LibraryResolver2_TypeAliasInfo(this._library, this._source, this._typeAlias);
-}
-
-/**
- * Instances of the class `TypeAliasInfo` hold information about a [TypeAlias].
- */
-class LibraryResolver_TypeAliasInfo {
- final Library _library;
-
- final Source _source;
-
- final FunctionTypeAlias _typeAlias;
-
- /**
- * Initialize a newly created information holder with the given information.
- *
- * @param library the library containing the type alias
- * @param source the source of the file containing the type alias
- * @param typeAlias the type alias being remembered
- */
- LibraryResolver_TypeAliasInfo(this._library, this._source, this._typeAlias);
-}
-
-/**
* Instances of the class `LibraryScope` implement a scope containing all of the names defined
* in a given library.
*/
@@ -9261,8 +9268,7 @@
*
* @return a table containing the same mappings as those defined by this namespace
*/
- Map<String, Element> get definedNames =>
- new HashMap<String, Element>.from(_definedNames);
+ Map<String, Element> get definedNames => _definedNames;
/**
* Return the element in this namespace that is available to the containing scope using the given
@@ -9412,7 +9418,7 @@
List<NamespaceCombinator> combinators) {
for (NamespaceCombinator combinator in combinators) {
if (combinator is HideElementCombinator) {
- _hide(definedNames, combinator.hiddenNames);
+ definedNames = _hide(definedNames, combinator.hiddenNames);
} else if (combinator is ShowElementCombinator) {
definedNames = _show(definedNames, combinator.shownNames);
} else {
@@ -9491,24 +9497,22 @@
}
/**
- * Hide all of the given names by removing them from the given collection of defined names.
- *
- * @param definedNames the names that were defined before this operation
- * @param hiddenNames the names to be hidden
+ * Return a new map of names which has all the names from [definedNames]
+ * with exception of [hiddenNames].
*/
- void _hide(HashMap<String, Element> definedNames, List<String> hiddenNames) {
+ Map<String, Element> _hide(
+ HashMap<String, Element> definedNames, List<String> hiddenNames) {
+ HashMap<String, Element> newNames =
+ new HashMap<String, Element>.from(definedNames);
for (String name in hiddenNames) {
- definedNames.remove(name);
- definedNames.remove("$name=");
+ newNames.remove(name);
+ newNames.remove("$name=");
}
+ return newNames;
}
/**
- * Show only the given names by removing all other names from the given collection of defined
- * names.
- *
- * @param definedNames the names that were defined before this operation
- * @param shownNames the names to be shown
+ * Return a new map of names which has only [shownNames] from [definedNames].
*/
HashMap<String, Element> _show(
HashMap<String, Element> definedNames, List<String> shownNames) {
@@ -10544,6 +10548,14 @@
*/
DartType overrideVariable(VariableElement element, DartType potentialType,
bool allowPrecisionLoss) {
+ // TODO(scheglov) type propagation for instance/top-level fields
+ // was disabled because it depends on the order or visiting.
+ // If both field and its client are in the same unit, and we visit
+ // the client before the field, then propagated type is not set yet.
+ if (element is PropertyInducingElement) {
+ return null;
+ }
+
if (potentialType == null || potentialType.isBottom) {
return null;
}
@@ -10576,18 +10588,6 @@
allowPrecisionLoss ||
!currentType.isMoreSpecificThan(potentialType) ||
potentialType.isMoreSpecificThan(currentType)) {
- // TODO(scheglov) type propagation for instance/top-level fields
- // was disabled because it depends on the order or visiting.
- // If both field and its client are in the same unit, and we visit
- // the client before the field, then propagated type is not set yet.
-// if (element is PropertyInducingElement) {
-// PropertyInducingElement variable = element;
-// if (!variable.isConst && !variable.isFinal) {
-// return;
-// }
-// (variable as PropertyInducingElementImpl).propagatedType =
-// potentialType;
-// }
_overrideManager.setType(element, potentialType);
return potentialType;
}
@@ -12723,6 +12723,310 @@
}
/**
+ * Implementation of [TypeSystem] using the strong mode rules.
+ * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md
+ */
+class StrongTypeSystemImpl implements TypeSystem {
+ final _specTypeSystem = new TypeSystemImpl();
+
+ StrongTypeSystemImpl();
+
+ @override
+ DartType getLeastUpperBound(
+ TypeProvider typeProvider, DartType type1, DartType type2) {
+ // TODO(leafp): Implement a strong mode version of this.
+ return _specTypeSystem.getLeastUpperBound(typeProvider, type1, type2);
+ }
+
+ // TODO(leafp): Document the rules in play here
+ @override
+ bool isAssignableTo(DartType fromType, DartType toType) {
+ // An actual subtype
+ if (isSubtypeOf(fromType, toType)) {
+ return true;
+ }
+
+ // Don't allow implicit downcasts between function types
+ // and call method objects, as these will almost always fail.
+ if ((fromType is FunctionType && _getCallMethodType(toType) != null) ||
+ (toType is FunctionType && _getCallMethodType(fromType) != null)) {
+ return false;
+ }
+
+ // If the subtype relation goes the other way, allow the implicit downcast.
+ // TODO(leafp): Emit warnings and hints for these in some way.
+ // TODO(leafp): Consider adding a flag to disable these? Or just rely on
+ // --warnings-as-errors?
+ if (isSubtypeOf(toType, fromType) ||
+ _specTypeSystem.isAssignableTo(toType, fromType)) {
+ // TODO(leafp): error if type is known to be exact (literal,
+ // instance creation).
+ // TODO(leafp): Warn on composite downcast.
+ // TODO(leafp): hint on object/dynamic downcast.
+ // TODO(leafp): Consider allowing assignment casts.
+ return true;
+ }
+
+ return false;
+ }
+
+ @override
+ bool isSubtypeOf(DartType leftType, DartType rightType) {
+ return _isSubtypeOf(leftType, rightType, null);
+ }
+
+ FunctionType _getCallMethodType(DartType t) {
+ if (t is InterfaceType) {
+ ClassElement element = t.element;
+ InheritanceManager manager = new InheritanceManager(element.library);
+ FunctionType callType = manager.lookupMemberType(t, "call");
+ return callType;
+ }
+ return null;
+ }
+
+ // Given a type t, if t is an interface type with a call method
+ // defined, return the function type for the call method, otherwise
+ // return null.
+ _GuardedSubtypeChecker<DartType> _guard(
+ _GuardedSubtypeChecker<DartType> check) {
+ return (DartType t1, DartType t2, Set<Element> visited) {
+ Element element = t1.element;
+ if (visited == null) {
+ visited = new HashSet<Element>();
+ }
+ if (element == null || !visited.add(element)) {
+ return false;
+ }
+ try {
+ return check(t1, t2, visited);
+ } finally {
+ visited.remove(element);
+ }
+ };
+ }
+
+ bool _isBottom(DartType t, {bool dynamicIsBottom: false}) {
+ return (t.isDynamic && dynamicIsBottom) || t.isBottom;
+ }
+
+ // Guard against loops in the class hierarchy
+ /**
+ * Check that [f1] is a subtype of [f2].
+ * [fuzzyArrows] indicates whether or not the f1 and f2 should be
+ * treated as fuzzy arrow types (and hence dynamic parameters to f2 treated
+ * as bottom).
+ */
+ bool _isFunctionSubtypeOf(FunctionType f1, FunctionType f2,
+ {bool fuzzyArrows: true}) {
+ final r1s = f1.normalParameterTypes;
+ final o1s = f1.optionalParameterTypes;
+ final n1s = f1.namedParameterTypes;
+ final r2s = f2.normalParameterTypes;
+ final o2s = f2.optionalParameterTypes;
+ final n2s = f2.namedParameterTypes;
+ final ret1 = f1.returnType;
+ final ret2 = f2.returnType;
+
+ // A -> B <: C -> D if C <: A and
+ // either D is void or B <: D
+ if (!ret2.isVoid && !isSubtypeOf(ret1, ret2)) {
+ return false;
+ }
+
+ // Reject if one has named and the other has optional
+ if (n1s.length > 0 && o2s.length > 0) {
+ return false;
+ }
+ if (n2s.length > 0 && o1s.length > 0) {
+ return false;
+ }
+
+ // Rebind _isSubtypeOf for convenience
+ _SubtypeChecker<DartType> parameterSubtype = (DartType t1, DartType t2) =>
+ _isSubtypeOf(t1, t2, null, dynamicIsBottom: fuzzyArrows);
+
+ // f2 has named parameters
+ if (n2s.length > 0) {
+ // Check that every named parameter in f2 has a match in f1
+ for (String k2 in n2s.keys) {
+ if (!n1s.containsKey(k2)) {
+ return false;
+ }
+ if (!parameterSubtype(n2s[k2], n1s[k2])) {
+ return false;
+ }
+ }
+ }
+ // If we get here, we either have no named parameters,
+ // or else the named parameters match and we have no optional
+ // parameters
+
+ // If f1 has more required parameters, reject
+ if (r1s.length > r2s.length) {
+ return false;
+ }
+
+ // If f2 has more required + optional parameters, reject
+ if (r2s.length + o2s.length > r1s.length + o1s.length) {
+ return false;
+ }
+
+ // The parameter lists must look like the following at this point
+ // where rrr is a region of required, and ooo is a region of optionals.
+ // f1: rrr ooo ooo ooo
+ // f2: rrr rrr ooo
+ int rr = r1s.length; // required in both
+ int or = r2s.length - r1s.length; // optional in f1, required in f2
+ int oo = o2s.length; // optional in both
+
+ for (int i = 0; i < rr; ++i) {
+ if (!parameterSubtype(r2s[i], r1s[i])) {
+ return false;
+ }
+ }
+ for (int i = 0, j = rr; i < or; ++i, ++j) {
+ if (!parameterSubtype(r2s[j], o1s[i])) {
+ return false;
+ }
+ }
+ for (int i = or, j = 0; i < oo; ++i, ++j) {
+ if (!parameterSubtype(o2s[j], o1s[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool _isInterfaceSubtypeOf(
+ InterfaceType i1, InterfaceType i2, Set<Element> visited) {
+ // Guard recursive calls
+ _GuardedSubtypeChecker<InterfaceType> guardedInterfaceSubtype =
+ _guard(_isInterfaceSubtypeOf);
+
+ if (i1 == i2) {
+ return true;
+ }
+
+ if (i1.element == i2.element) {
+ List<DartType> tArgs1 = i1.typeArguments;
+ List<DartType> tArgs2 = i2.typeArguments;
+
+ assert(tArgs1.length == tArgs2.length);
+
+ for (int i = 0; i < tArgs1.length; i++) {
+ DartType t1 = tArgs1[i];
+ DartType t2 = tArgs2[i];
+ if (!isSubtypeOf(t1, t2)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ if (i2.isDartCoreFunction && i1.element.getMethod("call") != null) {
+ return true;
+ }
+
+ if (i1.isObject) {
+ return false;
+ }
+
+ if (guardedInterfaceSubtype(i1.superclass, i2, visited)) {
+ return true;
+ }
+
+ for (final parent in i1.interfaces) {
+ if (guardedInterfaceSubtype(parent, i2, visited)) {
+ return true;
+ }
+ }
+
+ for (final parent in i1.mixins) {
+ if (guardedInterfaceSubtype(parent, i2, visited)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited,
+ {bool dynamicIsBottom: false}) {
+ // Guard recursive calls
+ _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf);
+
+ if (t1 == t2) {
+ return true;
+ }
+
+ // The types are void, dynamic, bottom, interface types, function types
+ // and type parameters. We proceed by eliminating these different classes
+ // from consideration.
+
+ // Trivially true.
+ if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) ||
+ _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) {
+ return true;
+ }
+
+ // Trivially false.
+ if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) ||
+ _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) {
+ return false;
+ }
+
+ // S <: T where S is a type variable
+ // T is not dynamic or object (handled above)
+ // S != T (handled above)
+ // So only true if bound of S is S' and
+ // S' <: T
+ if (t1 is TypeParameterType) {
+ DartType bound = t1.element.bound;
+ if (bound == null) return false;
+ return guardedSubtype(bound, t2, visited);
+ }
+
+ if (t2 is TypeParameterType) {
+ return false;
+ }
+
+ if (t1.isVoid || t2.isVoid) {
+ return false;
+ }
+
+ // We've eliminated void, dynamic, bottom, and type parameters. The only
+ // cases are the combinations of interface type and function type.
+
+ // A function type can only subtype an interface type if
+ // the interface type is Function
+ if (t1 is FunctionType && t2 is InterfaceType) {
+ return t2.isDartCoreFunction;
+ }
+
+ // An interface type can only subtype a function type if
+ // the interface type declares a call method with a type
+ // which is a super type of the function type.
+ if (t1 is InterfaceType && t2 is FunctionType) {
+ var callType = _getCallMethodType(t1);
+ return (callType != null) && _isFunctionSubtypeOf(callType, t2);
+ }
+
+ // Two interface types
+ if (t1 is InterfaceType && t2 is InterfaceType) {
+ return _isInterfaceSubtypeOf(t1, t2, visited);
+ }
+
+ return _isFunctionSubtypeOf(t1 as FunctionType, t2 as FunctionType);
+ }
+
+ // TODO(leafp): Document the rules in play here
+ bool _isTop(DartType t, {bool dynamicIsBottom: false}) {
+ return (t.isDynamic && !dynamicIsBottom) || t.isObject;
+ }
+}
+
+/**
* Instances of this class manage the knowledge of what the set of subtypes are for a given type.
*/
class SubtypeManager {
@@ -14956,15 +15260,6 @@
*/
abstract class TypeSystem {
/**
- * Create either a strong mode or regular type system based on context.
- */
- static TypeSystem create(AnalysisContext context) {
- return (context.analysisOptions.strongMode)
- ? new StrongTypeSystemImpl()
- : new TypeSystemImpl();
- }
-
- /**
* Compute the least upper bound of two types.
*/
DartType getLeastUpperBound(
@@ -14981,6 +15276,15 @@
* if leftType <: rightType).
*/
bool isSubtypeOf(DartType leftType, DartType rightType);
+
+ /**
+ * Create either a strong mode or regular type system based on context.
+ */
+ static TypeSystem create(AnalysisContext context) {
+ return (context.analysisOptions.strongMode)
+ ? new StrongTypeSystemImpl()
+ : new TypeSystemImpl();
+ }
}
/**
@@ -15080,313 +15384,6 @@
}
}
-typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited);
-typedef bool _SubtypeChecker<T>(T t1, T t2);
-
-/**
- * Implementation of [TypeSystem] using the strong mode rules.
- * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md
- */
-class StrongTypeSystemImpl implements TypeSystem {
- StrongTypeSystemImpl();
-
- final _specTypeSystem = new TypeSystemImpl();
-
- @override
- DartType getLeastUpperBound(
- TypeProvider typeProvider, DartType type1, DartType type2) {
- // TODO(leafp): Implement a strong mode version of this.
- return _specTypeSystem.getLeastUpperBound(typeProvider, type1, type2);
- }
-
- // TODO(leafp): Document the rules in play here
- @override
- bool isAssignableTo(DartType toType, DartType fromType) {
- // An actual subtype
- if (isSubtypeOf(fromType, toType)) {
- return true;
- }
-
- // Don't allow implicit downcasts between function types
- // and call method objects, as these will almost always fail.
- if ((fromType is FunctionType && _getCallMethodType(toType) != null) ||
- (toType is FunctionType && _getCallMethodType(fromType) != null)) {
- return false;
- }
-
- // If the subtype relation goes the other way, allow the implicit downcast.
- // TODO(leafp): Emit warnings and hints for these in some way.
- // TODO(leafp): Consider adding a flag to disable these? Or just rely on
- // --warnings-as-errors?
- if (isSubtypeOf(toType, fromType) ||
- _specTypeSystem.isAssignableTo(toType, fromType)) {
- // TODO(leafp): error if type is known to be exact (literal,
- // instance creation).
- // TODO(leafp): Warn on composite downcast.
- // TODO(leafp): hint on object/dynamic downcast.
- // TODO(leafp): Consider allowing assignment casts.
- return true;
- }
-
- return false;
- }
-
- bool _isBottom(DartType t, {bool dynamicIsBottom: false}) {
- return (t.isDynamic && dynamicIsBottom) || t.isBottom;
- }
-
- bool _isTop(DartType t, {bool dynamicIsBottom: false}) {
- return (t.isDynamic && !dynamicIsBottom) || t.isObject;
- }
-
- // Given a type t, if t is an interface type with a call method
- // defined, return the function type for the call method, otherwise
- // return null.
- FunctionType _getCallMethodType(DartType t) {
- if (t is InterfaceType) {
- ClassElement element = t.element;
- InheritanceManager manager = new InheritanceManager(element.library);
- FunctionType callType = manager.lookupMemberType(t, "call");
- return callType;
- }
- return null;
- }
-
- /**
- * Check that [f1] is a subtype of [f2].
- * [fuzzyArrows] indicates whether or not the f1 and f2 should be
- * treated as fuzzy arrow types (and hence dynamic parameters to f2 treated
- * as bottom).
- */
- bool _isFunctionSubtypeOf(FunctionType f1, FunctionType f2,
- {bool fuzzyArrows: true}) {
- final r1s = f1.normalParameterTypes;
- final o1s = f1.optionalParameterTypes;
- final n1s = f1.namedParameterTypes;
- final r2s = f2.normalParameterTypes;
- final o2s = f2.optionalParameterTypes;
- final n2s = f2.namedParameterTypes;
- final ret1 = f1.returnType;
- final ret2 = f2.returnType;
-
- // A -> B <: C -> D if C <: A and
- // either D is void or B <: D
- if (!ret2.isVoid && !isSubtypeOf(ret1, ret2)) {
- return false;
- }
-
- // Reject if one has named and the other has optional
- if (n1s.length > 0 && o2s.length > 0) {
- return false;
- }
- if (n2s.length > 0 && o1s.length > 0) {
- return false;
- }
-
- // Rebind _isSubtypeOf for convenience
- _SubtypeChecker<DartType> parameterSubtype = (DartType t1, DartType t2) =>
- _isSubtypeOf(t1, t2, null, dynamicIsBottom: fuzzyArrows);
-
- // f2 has named parameters
- if (n2s.length > 0) {
- // Check that every named parameter in f2 has a match in f1
- for (String k2 in n2s.keys) {
- if (!n1s.containsKey(k2)) {
- return false;
- }
- if (!parameterSubtype(n2s[k2], n1s[k2])) {
- return false;
- }
- }
- }
- // If we get here, we either have no named parameters,
- // or else the named parameters match and we have no optional
- // parameters
-
- // If f1 has more required parameters, reject
- if (r1s.length > r2s.length) {
- return false;
- }
-
- // If f2 has more required + optional parameters, reject
- if (r2s.length + o2s.length > r1s.length + o1s.length) {
- return false;
- }
-
- // The parameter lists must look like the following at this point
- // where rrr is a region of required, and ooo is a region of optionals.
- // f1: rrr ooo ooo ooo
- // f2: rrr rrr ooo
- int rr = r1s.length; // required in both
- int or = r2s.length - r1s.length; // optional in f1, required in f2
- int oo = o2s.length; // optional in both
-
- for (int i = 0; i < rr; ++i) {
- if (!parameterSubtype(r2s[i], r1s[i])) {
- return false;
- }
- }
- for (int i = 0, j = rr; i < or; ++i, ++j) {
- if (!parameterSubtype(r2s[j], o1s[i])) {
- return false;
- }
- }
- for (int i = or, j = 0; i < oo; ++i, ++j) {
- if (!parameterSubtype(o2s[j], o1s[i])) {
- return false;
- }
- }
- return true;
- }
-
- // Guard against loops in the class hierarchy
- _GuardedSubtypeChecker<DartType> _guard(
- _GuardedSubtypeChecker<DartType> check) {
- return (DartType t1, DartType t2, Set<Element> visited) {
- Element element = t1.element;
- if (visited == null) {
- visited = new HashSet<Element>();
- }
- if (element == null || !visited.add(element)) {
- return false;
- }
- try {
- return check(t1, t2, visited);
- } finally {
- visited.remove(element);
- }
- };
- }
-
- bool _isInterfaceSubtypeOf(
- InterfaceType i1, InterfaceType i2, Set<Element> visited) {
- // Guard recursive calls
- _GuardedSubtypeChecker<InterfaceType> guardedInterfaceSubtype =
- _guard(_isInterfaceSubtypeOf);
-
- if (i1 == i2) {
- return true;
- }
-
- if (i1.element == i2.element) {
- List<DartType> tArgs1 = i1.typeArguments;
- List<DartType> tArgs2 = i2.typeArguments;
-
- assert(tArgs1.length == tArgs2.length);
-
- for (int i = 0; i < tArgs1.length; i++) {
- DartType t1 = tArgs1[i];
- DartType t2 = tArgs2[i];
- if (!isSubtypeOf(t1, t2)) {
- return false;
- }
- }
- return true;
- }
-
- if (i2.isDartCoreFunction && i1.element.getMethod("call") != null) {
- return true;
- }
-
- if (i1.isObject) {
- return false;
- }
-
- if (guardedInterfaceSubtype(i1.superclass, i2, visited)) {
- return true;
- }
-
- for (final parent in i1.interfaces) {
- if (guardedInterfaceSubtype(parent, i2, visited)) {
- return true;
- }
- }
-
- for (final parent in i1.mixins) {
- if (guardedInterfaceSubtype(parent, i2, visited)) {
- return true;
- }
- }
-
- return false;
- }
-
- bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited,
- {bool dynamicIsBottom: false}) {
- // Guard recursive calls
- _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf);
-
- if (t1 == t2) {
- return true;
- }
-
- // The types are void, dynamic, bottom, interface types, function types
- // and type parameters. We proceed by eliminating these different classes
- // from consideration.
-
- // Trivially true.
- if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) ||
- _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) {
- return true;
- }
-
- // Trivially false.
- if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) ||
- _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) {
- return false;
- }
-
- // S <: T where S is a type variable
- // T is not dynamic or object (handled above)
- // S != T (handled above)
- // So only true if bound of S is S' and
- // S' <: T
- if (t1 is TypeParameterType) {
- DartType bound = t1.element.bound;
- if (bound == null) return false;
- return guardedSubtype(bound, t2, visited);
- }
-
- if (t2 is TypeParameterType) {
- return false;
- }
-
- if (t1.isVoid || t2.isVoid) {
- return false;
- }
-
- // We've eliminated void, dynamic, bottom, and type parameters. The only
- // cases are the combinations of interface type and function type.
-
- // A function type can only subtype an interface type if
- // the interface type is Function
- if (t1 is FunctionType && t2 is InterfaceType) {
- return t2.isDartCoreFunction;
- }
-
- // An interface type can only subtype a function type if
- // the interface type declares a call method with a type
- // which is a super type of the function type.
- if (t1 is InterfaceType && t2 is FunctionType) {
- var callType = _getCallMethodType(t1);
- return (callType != null) && _isFunctionSubtypeOf(callType, t2);
- }
-
- // Two interface types
- if (t1 is InterfaceType && t2 is InterfaceType) {
- return _isInterfaceSubtypeOf(t1, t2, visited);
- }
-
- return _isFunctionSubtypeOf(t1 as FunctionType, t2 as FunctionType);
- }
-
- // TODO(leafp): Document the rules in play here
- @override
- bool isSubtypeOf(DartType leftType, DartType rightType) {
- return _isSubtypeOf(leftType, rightType, null);
- }
-}
-
/**
* Instances of the class [UnusedLocalElementsVerifier] traverse an element
* structure looking for cases of [HintCode.UNUSED_ELEMENT],
diff --git a/pkg/analyzer/lib/src/generated/testing/ast_factory.dart b/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
index 86f1e04..bb758b3 100644
--- a/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
@@ -377,6 +377,11 @@
TypeName type, String identifier) =>
declaredIdentifier2(null, type, identifier);
+ static Comment documentationComment(
+ List<Token> tokens, List<CommentReference> references) {
+ return new Comment(tokens, CommentType.DOCUMENTATION, references);
+ }
+
static DoStatement doStatement(Statement body, Expression condition) =>
new DoStatement(
TokenFactory.tokenFromKeyword(Keyword.DO),
diff --git a/pkg/analyzer/lib/src/plugin/engine_plugin.dart b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
index 75debaa..f720367 100644
--- a/pkg/analyzer/lib/src/plugin/engine_plugin.dart
+++ b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
@@ -159,8 +159,6 @@
void _registerDartErrorsForSource(RegisterExtension registerExtension) {
String id = DART_ERRORS_FOR_SOURCE_EXTENSION_POINT_ID;
- registerExtension(id, BUILD_DIRECTIVES_ERRORS);
- registerExtension(id, BUILD_LIBRARY_ERRORS);
registerExtension(id, PARSE_ERRORS);
registerExtension(id, SCAN_ERRORS);
}
@@ -203,6 +201,7 @@
registerExtension(taskId, GatherUsedImportedElementsTask.DESCRIPTOR);
registerExtension(taskId, GatherUsedLocalElementsTask.DESCRIPTOR);
registerExtension(taskId, GenerateHintsTask.DESCRIPTOR);
+ registerExtension(taskId, GenerateLintsTask.DESCRIPTOR);
registerExtension(taskId, InferInstanceMembersInUnitTask.DESCRIPTOR);
registerExtension(taskId, InferStaticVariableTypesInUnitTask.DESCRIPTOR);
registerExtension(taskId, InferStaticVariableTypeTask.DESCRIPTOR);
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index 8ce9084..2091fdc 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -21,7 +21,9 @@
import 'package:analyzer/src/generated/scanner.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/visitors.dart';
import 'package:analyzer/src/plugin/engine_plugin.dart';
+import 'package:analyzer/src/services/lint.dart';
import 'package:analyzer/src/task/driver.dart';
import 'package:analyzer/src/task/general.dart';
import 'package:analyzer/src/task/html.dart';
@@ -291,6 +293,17 @@
'LIBRARY_UNIT_ERRORS', AnalysisError.NO_ERRORS);
/**
+ * The errors produced while generating lints for a compilation unit.
+ *
+ * The list will be empty if there were no errors, but will not be `null`.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<AnalysisError> LINTS =
+ new ListResultDescriptor<AnalysisError>(
+ 'LINT_ERRORS', AnalysisError.NO_ERRORS);
+
+/**
* The errors produced while parsing a compilation unit.
*
* The list will be empty if there were no errors, but will not be `null`.
@@ -537,7 +550,7 @@
//
// Build or reuse CompilationUnitElement.
//
- unit = AstCloner.clone(unit);
+// unit = AstCloner.clone(unit);
AnalysisCache analysisCache =
(context as InternalAnalysisContext).analysisCache;
CompilationUnitElement element =
@@ -573,7 +586,7 @@
static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
LibrarySpecificUnit unit = target;
return <String, TaskInput>{
- PARSED_UNIT_INPUT_NAME: PARSED_UNIT.of(unit.unit)
+ PARSED_UNIT_INPUT_NAME: PARSED_UNIT.of(unit.unit, flushOnAccess: true)
};
}
@@ -2419,6 +2432,92 @@
}
/**
+ * A task that generates [LINTS] for a unit.
+ */
+class GenerateLintsTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the [RESOLVED_UNIT8] input.
+ */
+ static const String RESOLVED_UNIT_INPUT = 'RESOLVED_UNIT';
+
+ /**
+ * The name of a list of [USED_LOCAL_ELEMENTS] for each library unit input.
+ */
+ static const String USED_LOCAL_ELEMENTS_INPUT = 'USED_LOCAL_ELEMENTS';
+
+ /**
+ * The name of a list of [USED_IMPORTED_ELEMENTS] for each library unit input.
+ */
+ static const String USED_IMPORTED_ELEMENTS_INPUT = 'USED_IMPORTED_ELEMENTS';
+
+ /**
+ * 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(
+ 'GenerateLintsTask', createTask, buildInputs, <ResultDescriptor>[LINTS]);
+
+ GenerateLintsTask(InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ AnalysisOptions analysisOptions = context.analysisOptions;
+ if (!analysisOptions.lint) {
+ outputs[LINTS] = AnalysisError.NO_ERRORS;
+ return;
+ }
+ //
+ // Prepare collectors.
+ //
+ RecordingErrorListener errorListener = new RecordingErrorListener();
+ Source source = getRequiredSource();
+ ErrorReporter errorReporter = new ErrorReporter(errorListener, source);
+ //
+ // Prepare inputs.
+ //
+ CompilationUnit unit = getRequiredInput(RESOLVED_UNIT_INPUT);
+
+ //
+ // Generate lints.
+ //
+ LintGenerator.LINTERS.forEach((l) => l.reporter = errorReporter);
+ Iterable<AstVisitor> visitors =
+ LintGenerator.LINTERS.map((l) => l.getVisitor()).toList();
+ unit.accept(new DelegatingAstVisitor(visitors.where((v) => v != null)));
+
+ //
+ // Record outputs.
+ //
+ outputs[LINTS] = errorListener.errors;
+ }
+
+ /**
+ * Return a map from the names of the inputs of this kind of task to the task
+ * input descriptors describing those inputs for a task with the
+ * given [target].
+ */
+ static Map<String, TaskInput> buildInputs(AnalysisTarget target) =>
+ <String, TaskInput>{RESOLVED_UNIT_INPUT: RESOLVED_UNIT.of(target)};
+
+ /**
+ * Create a [GenerateLintsTask] based on the given [target] in
+ * the given [context].
+ */
+ static GenerateLintsTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new GenerateLintsTask(context, target);
+ }
+}
+
+/**
* A task that ensures that all of the inferrable instance members in a
* compilation unit have had their type inferred.
*/
@@ -2804,11 +2903,26 @@
*/
class LibraryUnitErrorsTask extends SourceBasedAnalysisTask {
/**
+ * The name of the [BUILD_DIRECTIVES_ERRORS] input.
+ */
+ static const String BUILD_DIRECTIVES_ERRORS_INPUT = 'BUILD_DIRECTIVES_ERRORS';
+
+ /**
+ * The name of the [BUILD_LIBRARY_ERRORS] input.
+ */
+ static const String BUILD_LIBRARY_ERRORS_INPUT = 'BUILD_LIBRARY_ERRORS';
+
+ /**
* The name of the [HINTS] input.
*/
static const String HINTS_INPUT = 'HINTS';
/**
+ * The name of the [LINTS] input.
+ */
+ static const String LINTS_INPUT = 'LINTS';
+
+ /**
* The name of the [INFER_STATIC_VARIABLE_TYPES_ERRORS] input.
*/
static const String INFER_STATIC_VARIABLE_TYPES_ERRORS_INPUT =
@@ -2864,7 +2978,10 @@
// Prepare inputs.
//
List<List<AnalysisError>> errorLists = <List<AnalysisError>>[];
+ errorLists.add(getRequiredInput(BUILD_DIRECTIVES_ERRORS_INPUT));
+ errorLists.add(getRequiredInput(BUILD_LIBRARY_ERRORS_INPUT));
errorLists.add(getRequiredInput(HINTS_INPUT));
+ errorLists.add(getRequiredInput(LINTS_INPUT));
errorLists.add(getRequiredInput(INFER_STATIC_VARIABLE_TYPES_ERRORS_INPUT));
errorLists.add(getRequiredInput(PARTIALLY_RESOLVE_REFERENCES_ERRORS_INPUT));
errorLists.add(getRequiredInput(RESOLVE_FUNCTION_BODIES_ERRORS_INPUT));
@@ -2884,8 +3001,9 @@
*/
static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
LibrarySpecificUnit unit = target;
- return <String, TaskInput>{
+ Map<String, TaskInput> inputs = <String, TaskInput>{
HINTS_INPUT: HINTS.of(unit),
+ LINTS_INPUT: LINTS.of(unit),
INFER_STATIC_VARIABLE_TYPES_ERRORS_INPUT:
INFER_STATIC_VARIABLE_TYPES_ERRORS.of(unit),
PARTIALLY_RESOLVE_REFERENCES_ERRORS_INPUT:
@@ -2896,6 +3014,18 @@
VARIABLE_REFERENCE_ERRORS_INPUT: VARIABLE_REFERENCE_ERRORS.of(unit),
VERIFY_ERRORS_INPUT: VERIFY_ERRORS.of(unit)
};
+ Source source = unit.source;
+ if (unit.library == source) {
+ inputs[BUILD_DIRECTIVES_ERRORS_INPUT] =
+ BUILD_DIRECTIVES_ERRORS.of(source);
+ inputs[BUILD_LIBRARY_ERRORS_INPUT] = BUILD_LIBRARY_ERRORS.of(source);
+ } else {
+ inputs[BUILD_DIRECTIVES_ERRORS_INPUT] =
+ new ConstantTaskInput(AnalysisError.NO_ERRORS);
+ inputs[BUILD_LIBRARY_ERRORS_INPUT] =
+ new ConstantTaskInput(AnalysisError.NO_ERRORS);
+ }
+ return inputs;
}
/**
@@ -3730,7 +3860,7 @@
LibrarySpecificUnit unit = target;
return <String, TaskInput>{
LIBRARY_INPUT: LIBRARY_ELEMENT1.of(unit.library),
- UNIT_INPUT: RESOLVED_UNIT1.of(unit),
+ UNIT_INPUT: RESOLVED_UNIT3.of(unit),
TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
};
}
@@ -3788,8 +3918,10 @@
message = exception.toString();
}
}
- errorListener.onError(new AnalysisError(
- source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [message]));
+ if (source.exists()) {
+ errorListener.onError(new AnalysisError(
+ source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [message]));
+ }
}
if (target is DartScript) {
DartScript script = target;
@@ -4087,6 +4219,9 @@
}
@override
+ bool get flushOnAccess => false;
+
+ @override
List<Source> get inputValue {
return _libraries.map((LibraryElement library) => library.source).toList();
}
diff --git a/pkg/analyzer/lib/src/task/dart_work_manager.dart b/pkg/analyzer/lib/src/task/dart_work_manager.dart
index 77c4a0a..cc4d4e6 100644
--- a/pkg/analyzer/lib/src/task/dart_work_manager.dart
+++ b/pkg/analyzer/lib/src/task/dart_work_manager.dart
@@ -42,6 +42,7 @@
*/
static final List<ResultDescriptor> _UNIT_ERRORS = <ResultDescriptor>[
HINTS,
+ LINTS,
INFER_STATIC_VARIABLE_TYPES_ERRORS,
LIBRARY_UNIT_ERRORS,
PARTIALLY_RESOLVE_REFERENCES_ERRORS,
diff --git a/pkg/analyzer/lib/src/task/driver.dart b/pkg/analyzer/lib/src/task/driver.dart
index 8daa5cf..3231454 100644
--- a/pkg/analyzer/lib/src/task/driver.dart
+++ b/pkg/analyzer/lib/src/task/driver.dart
@@ -667,6 +667,9 @@
}
} else {
builder.currentValue = inputEntry.getValue(inputResult);
+ if (builder.flushOnAccess) {
+ inputEntry.setState(inputResult, CacheState.FLUSHED);
+ }
}
if (!builder.moveNext()) {
inputs = builder.inputValue;
diff --git a/pkg/analyzer/lib/src/task/inputs.dart b/pkg/analyzer/lib/src/task/inputs.dart
index c93a127..468f313 100644
--- a/pkg/analyzer/lib/src/task/inputs.dart
+++ b/pkg/analyzer/lib/src/task/inputs.dart
@@ -24,6 +24,55 @@
* An input to an [AnalysisTask] that is computed by accessing a single result
* defined on a single target.
*/
+class ConstantTaskInput<V> extends TaskInputImpl<V> {
+ final V value;
+
+ ConstantTaskInput(this.value);
+
+ @override
+ TaskInputBuilder<V> createBuilder() {
+ return new ConstantTaskInputBuilder<V>(this);
+ }
+}
+
+/**
+ * A [TaskInputBuilder] used to build an input based on a [ConstantTaskInput].
+ */
+class ConstantTaskInputBuilder<V> implements TaskInputBuilder<V> {
+ final ConstantTaskInput input;
+
+ ConstantTaskInputBuilder(this.input);
+
+ @override
+ ResultDescriptor get currentResult => null;
+
+ @override
+ AnalysisTarget get currentTarget => null;
+
+ @override
+ void set currentValue(Object value) {
+ throw new StateError('Only supported after moveNext() returns true');
+ }
+
+ @override
+ bool get flushOnAccess => false;
+
+ @override
+ V get inputValue => input.value;
+
+ @override
+ void currentValueNotAvailable() {
+ throw new StateError('Only supported after moveNext() returns true');
+ }
+
+ @override
+ bool moveNext() => false;
+}
+
+/**
+ * An input to an [AnalysisTask] that is computed by accessing a single result
+ * defined on a single target.
+ */
class ListTaskInputImpl<E> extends SimpleTaskInput<List<E>>
with ListTaskInputMixin<E>
implements ListTaskInput<E> {
@@ -32,7 +81,7 @@
* the given [result] associated with the given [target].
*/
ListTaskInputImpl(AnalysisTarget target, ResultDescriptor<List<E>> result)
- : super(target, result);
+ : super._unflushable(target, result);
}
/**
@@ -243,6 +292,9 @@
}
@override
+ bool get flushOnAccess => currentBuilder.flushOnAccess;
+
+ @override
void currentValueNotAvailable() {
if (currentBuilder == null) {
throw new StateError(
@@ -394,6 +446,9 @@
}
@override
+ bool get flushOnAccess => builder.flushOnAccess;
+
+ @override
List<E> get inputValue {
if (builder != null) {
throw new StateError('Result value has not been created');
@@ -445,10 +500,23 @@
final ResultDescriptor<V> result;
/**
+ * Return `true` if the value accessed by this input builder should be flushed
+ * from the cache at the time it is retrieved.
+ */
+ final bool flushOnAccess;
+
+ /**
* Initialize a newly created task input that computes the input by accessing
* the given [result] associated with the given [target].
*/
- SimpleTaskInput(this.target, this.result);
+ SimpleTaskInput(this.target, this.result, {this.flushOnAccess: false});
+
+ /**
+ * Initialize a newly created task input that computes the input by accessing
+ * the given [result] associated with the given [target].
+ */
+ SimpleTaskInput._unflushable(this.target, this.result)
+ : flushOnAccess = false;
@override
TaskInputBuilder<V> createBuilder() => new SimpleTaskInputBuilder<V>(this);
@@ -520,6 +588,9 @@
}
@override
+ bool get flushOnAccess => input.flushOnAccess;
+
+ @override
V get inputValue {
if (_state != _AFTER) {
throw new StateError('Result value has not been created');
@@ -628,6 +699,9 @@
}
@override
+ bool get flushOnAccess => currentBuilder.flushOnAccess;
+
+ @override
Map<String, Object> get inputValue {
if (nameIndex < inputNames.length) {
throw new StateError('Result value has not been created');
@@ -675,11 +749,18 @@
return false;
}
currentBuilder = inputDescriptors[_currentName].createBuilder();
- // NOTE: This assumes that every builder will require at least one result
- // value to be created. If that assumption is every broken, this method will
- // need to be changed to advance until we find a builder that does require
- // a result to be computed (or run out of builders).
- return currentBuilder.moveNext();
+ while (!currentBuilder.moveNext()) {
+ if (currentBuilder.inputValue != null) {
+ inputs[_currentName] = currentBuilder.inputValue;
+ }
+ nameIndex++;
+ if (nameIndex >= inputNames.length) {
+ // There is no next value, so we're done.
+ return false;
+ }
+ currentBuilder = inputDescriptors[_currentName].createBuilder();
+ }
+ return true;
}
}
@@ -774,6 +855,9 @@
}
@override
+ bool get flushOnAccess => currentBuilder.flushOnAccess;
+
+ @override
C get inputValue {
if (currentBuilder != null || _resultValue == null) {
throw new StateError('Result value has not been created');
diff --git a/pkg/analyzer/lib/src/task/model.dart b/pkg/analyzer/lib/src/task/model.dart
index 9ef568e..50c05ee 100644
--- a/pkg/analyzer/lib/src/task/model.dart
+++ b/pkg/analyzer/lib/src/task/model.dart
@@ -29,8 +29,12 @@
: super(name, defaultValue, cachingPolicy: cachingPolicy);
@override
- ListTaskInput<E> of(AnalysisTarget target) =>
- new ListTaskInputImpl<E>(target, this);
+ ListTaskInput<E> of(AnalysisTarget target, {bool flushOnAccess: false}) {
+ if (flushOnAccess) {
+ throw new StateError('Cannot flush a list of values');
+ }
+ return new ListTaskInputImpl<E>(target, this);
+ }
}
/**
@@ -71,8 +75,8 @@
}
@override
- TaskInput<V> of(AnalysisTarget target) =>
- new SimpleTaskInput<V>(target, this);
+ TaskInput<V> of(AnalysisTarget target, {bool flushOnAccess: false}) =>
+ new SimpleTaskInput<V>(target, this, flushOnAccess: flushOnAccess);
@override
String toString() => name;
diff --git a/pkg/analyzer/lib/task/model.dart b/pkg/analyzer/lib/task/model.dart
index 018b349..9d949c3 100644
--- a/pkg/analyzer/lib/task/model.dart
+++ b/pkg/analyzer/lib/task/model.dart
@@ -5,6 +5,7 @@
library analyzer.task.model;
import 'dart:collection';
+import 'dart:developer';
import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask;
import 'package:analyzer/src/generated/error.dart' show AnalysisError;
@@ -84,6 +85,12 @@
static final Map<Type, int> countMap = new HashMap<Type, int>();
/**
+ * A table mapping the types of analysis tasks to user tags used to collect
+ * timing data for the Observatory.
+ */
+ static Map<Type, UserTag> tagMap = new HashMap<Type, UserTag>();
+
+ /**
* A table mapping the types of analysis tasks to stopwatches used to compute
* how much time was spent executing each kind of task.
*/
@@ -228,11 +235,15 @@
//
int count = countMap[runtimeType];
countMap[runtimeType] = count == null ? 1 : count + 1;
+// UserTag tag = tagMap.putIfAbsent(
+// runtimeType, () => new UserTag(runtimeType.toString()));
Stopwatch stopwatch = stopwatchMap[runtimeType];
if (stopwatch == null) {
stopwatch = new Stopwatch();
stopwatchMap[runtimeType] = stopwatch;
}
+// UserTag previousTag = tag.makeCurrent();
+// try {
stopwatch.start();
//
// Actually perform the task.
@@ -245,6 +256,9 @@
} finally {
stopwatch.stop();
}
+// } finally {
+// previousTag.makeCurrent();
+// }
} on AnalysisException {
rethrow;
} catch (exception, stackTrace) {
@@ -272,7 +286,7 @@
E>;
@override
- ListTaskInput<E> of(AnalysisTarget target);
+ ListTaskInput<E> of(AnalysisTarget target, {bool flushOnAccess: false});
}
/**
@@ -387,9 +401,10 @@
/**
* Return a task input that can be used to compute this result for the given
- * [target].
+ * [target]. If [flushOnAccess] is `true` then the value of this result that
+ * is associated with the [target] will be flushed when it is accessed.
*/
- TaskInput<V> of(AnalysisTarget target);
+ TaskInput<V> of(AnalysisTarget target, {bool flushOnAccess: false});
}
/**
@@ -530,6 +545,12 @@
void set currentValue(Object value);
/**
+ * Return `true` if the value accessed by this input builder should be flushed
+ * from the cache at the time it is retrieved.
+ */
+ bool get flushOnAccess;
+
+ /**
* Return the [value] that was computed by this builder.
*
* Throws a [StateError] if [moveNext] has not been invoked or if the last
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 056ec55..022f3f8 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 0.26.1+6
+version: 0.26.1+7
author: Dart Team <misc@dartlang.org>
description: Static analyzer for Dart.
homepage: http://www.dartlang.org
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index 0b878f5..cabe5d7 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -5052,6 +5052,8 @@
String className = "C";
ClassDeclaration classDeclaration =
AstFactory.classDeclaration(null, className, null, null, null, null);
+ classDeclaration.documentationComment = AstFactory.documentationComment(
+ [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
classDeclaration.accept(builder);
List<ClassElement> types = holder.types;
expect(types, hasLength(1));
@@ -5063,6 +5065,7 @@
expect(type.isAbstract, isFalse);
expect(type.isMixinApplication, isFalse);
expect(type.isSynthetic, isFalse);
+ _assertHasDocRange(type, 50, 7);
}
void test_visitClassDeclaration_parameterized() {
@@ -5296,11 +5299,16 @@
AstFactory.formalParameterList(),
null,
AstFactory.blockFunctionBody2());
+ constructorDeclaration.documentationComment = AstFactory
+ .documentationComment(
+ [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
constructorDeclaration.accept(builder);
+
List<ConstructorElement> constructors = holder.constructors;
expect(constructors, hasLength(1));
ConstructorElement constructor = constructors[0];
expect(constructor, isNotNull);
+ _assertHasDocRange(constructor, 50, 7);
expect(constructor.isExternal, isFalse);
expect(constructor.isFactory, isFalse);
expect(constructor.name, "");
@@ -5478,11 +5486,14 @@
String enumName = "E";
EnumDeclaration enumDeclaration =
AstFactory.enumDeclaration2(enumName, ["ONE"]);
+ enumDeclaration.documentationComment = AstFactory.documentationComment(
+ [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
enumDeclaration.accept(builder);
List<ClassElement> enums = holder.enums;
expect(enums, hasLength(1));
ClassElement enumElement = enums[0];
expect(enumElement, isNotNull);
+ _assertHasDocRange(enumElement, 50, 7);
expect(enumElement.name, enumName);
}
@@ -5496,18 +5507,25 @@
AstFactory.variableDeclaration(firstFieldName),
AstFactory.variableDeclaration(secondFieldName)
]);
+ fieldDeclaration.documentationComment = AstFactory.documentationComment(
+ [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
fieldDeclaration.accept(builder);
+
List<FieldElement> fields = holder.fields;
expect(fields, hasLength(2));
+
FieldElement firstField = fields[0];
expect(firstField, isNotNull);
+ _assertHasDocRange(firstField, 50, 7);
expect(firstField.name, firstFieldName);
expect(firstField.initializer, isNull);
expect(firstField.isConst, isFalse);
expect(firstField.isFinal, isFalse);
expect(firstField.isSynthetic, isFalse);
+
FieldElement secondField = fields[1];
expect(secondField, isNotNull);
+ _assertHasDocRange(secondField, 50, 7);
expect(secondField.name, secondFieldName);
expect(secondField.initializer, isNull);
expect(secondField.isConst, isFalse);
@@ -5614,12 +5632,15 @@
functionName,
AstFactory.functionExpression2(
AstFactory.formalParameterList(), AstFactory.blockFunctionBody2()));
+ declaration.documentationComment = AstFactory.documentationComment(
+ [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
declaration.accept(builder);
List<PropertyAccessorElement> accessors = holder.accessors;
expect(accessors, hasLength(1));
PropertyAccessorElement accessor = accessors[0];
expect(accessor, isNotNull);
+ _assertHasDocRange(accessor, 50, 7);
expect(accessor.name, functionName);
expect(declaration.element, same(accessor));
expect(declaration.functionExpression.element, same(accessor));
@@ -5646,12 +5667,15 @@
functionName,
AstFactory.functionExpression2(
AstFactory.formalParameterList(), AstFactory.blockFunctionBody2()));
+ declaration.documentationComment = AstFactory.documentationComment(
+ [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
declaration.accept(builder);
List<FunctionElement> functions = holder.functions;
expect(functions, hasLength(1));
FunctionElement function = functions[0];
expect(function, isNotNull);
+ _assertHasDocRange(function, 50, 7);
expect(function.hasImplicitReturnType, isFalse);
expect(function.name, functionName);
expect(declaration.element, same(function));
@@ -5672,12 +5696,15 @@
functionName,
AstFactory.functionExpression2(
AstFactory.formalParameterList(), AstFactory.blockFunctionBody2()));
+ declaration.documentationComment = AstFactory.documentationComment(
+ [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
declaration.accept(builder);
List<PropertyAccessorElement> accessors = holder.accessors;
expect(accessors, hasLength(1));
PropertyAccessorElement accessor = accessors[0];
expect(accessor, isNotNull);
+ _assertHasDocRange(accessor, 50, 7);
expect(accessor.hasImplicitReturnType, isFalse);
expect(accessor.name, "$functionName=");
expect(declaration.element, same(accessor));
@@ -5747,11 +5774,15 @@
String parameterName = "E";
FunctionTypeAlias aliasNode = AstFactory.typeAlias(
null, aliasName, AstFactory.typeParameterList([parameterName]), null);
+ aliasNode.documentationComment = AstFactory.documentationComment(
+ [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
aliasNode.accept(builder);
+
List<FunctionTypeAliasElement> aliases = holder.typeAliases;
expect(aliases, hasLength(1));
FunctionTypeAliasElement alias = aliases[0];
expect(alias, isNotNull);
+ _assertHasDocRange(alias, 50, 7);
expect(alias.name, aliasName);
expect(alias.parameters, hasLength(0));
List<TypeParameterElement> typeParameters = alias.typeParameters;
@@ -5903,6 +5934,8 @@
AstFactory.identifier3(methodName),
AstFactory.formalParameterList(),
AstFactory.blockFunctionBody2());
+ methodDeclaration.documentationComment = AstFactory.documentationComment(
+ [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
methodDeclaration.accept(builder);
List<FieldElement> fields = holder.fields;
@@ -5914,6 +5947,7 @@
expect(field.setter, isNull);
PropertyAccessorElement getter = field.getter;
expect(getter, isNotNull);
+ _assertHasDocRange(getter, 50, 7);
expect(getter.hasImplicitReturnType, isTrue);
expect(getter.isAbstract, isFalse);
expect(getter.isExternal, isFalse);
@@ -6015,11 +6049,15 @@
AstFactory.identifier3(methodName),
AstFactory.formalParameterList(),
AstFactory.blockFunctionBody2());
+ methodDeclaration.documentationComment = AstFactory.documentationComment(
+ [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
methodDeclaration.accept(builder);
+
List<MethodElement> methods = holder.methods;
expect(methods, hasLength(1));
MethodElement method = methods[0];
expect(method, isNotNull);
+ _assertHasDocRange(method, 50, 7);
expect(method.hasImplicitReturnType, isFalse);
expect(method.name, methodName);
expect(method.functions, hasLength(0));
@@ -6079,6 +6117,8 @@
AstFactory.identifier3(methodName),
AstFactory.formalParameterList(),
AstFactory.blockFunctionBody2());
+ methodDeclaration.documentationComment = AstFactory.documentationComment(
+ [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
methodDeclaration.accept(builder);
List<FieldElement> fields = holder.fields;
@@ -6088,8 +6128,10 @@
expect(field.name, methodName);
expect(field.isSynthetic, isTrue);
expect(field.getter, isNull);
+
PropertyAccessorElement setter = field.setter;
expect(setter, isNotNull);
+ _assertHasDocRange(setter, 50, 7);
expect(setter.hasImplicitReturnType, isFalse);
expect(setter.isAbstract, isFalse);
expect(setter.isExternal, isFalse);
@@ -6654,6 +6696,14 @@
expect(variable.setter, isNull);
}
+ void _assertHasDocRange(
+ Element element, int expectedOffset, int expectedLength) {
+ SourceRange docRange = element.docRange;
+ expect(docRange, isNotNull);
+ expect(docRange.offset, expectedOffset);
+ expect(docRange.length, expectedLength);
+ }
+
void _useParameterInMethod(
FormalParameter formalParameter, int blockOffset, int blockEnd) {
Block block = AstFactory.block();
diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
index 18a45f6..eaef165 100644
--- a/pkg/analyzer/test/generated/incremental_resolver_test.dart
+++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
@@ -834,6 +834,24 @@
''');
}
+ void test_false_fieldFormalParameter_differentField() {
+ _assertDoesNotMatch(
+ r'''
+class A {
+ final aaa;
+ final bbb;
+ A(this.aaa, this.bbb);
+}
+''',
+ r'''
+class A {
+ final aaa;
+ final bbb;
+ A(this.bbb, this.aaa);
+}
+''');
+ }
+
void test_false_fieldFormalParameter_parameters_add() {
_assertDoesNotMatch(
r'''
@@ -930,6 +948,54 @@
''');
}
+ void test_false_fieldFormalParameter_typeAdd() {
+ _assertDoesNotMatch(
+ r'''
+class A {
+ final fff;
+ A(this.fff);
+}
+''',
+ r'''
+class A {
+ final fff;
+ A(int this.fff);
+}
+''');
+ }
+
+ void test_false_fieldFormalParameter_typeEdit() {
+ _assertDoesNotMatch(
+ r'''
+class A {
+ final fff;
+ A(int this.fff);
+}
+''',
+ r'''
+class A {
+ final fff;
+ A(String this.fff);
+}
+''');
+ }
+
+ void test_false_fieldFormalParameter_typeRemove() {
+ _assertDoesNotMatch(
+ r'''
+class A {
+ final fff;
+ A(int this.fff);
+}
+''',
+ r'''
+class A {
+ final fff;
+ A(this.fff);
+}
+''');
+ }
+
void test_false_fieldFormalParameterElement_wasSimple() {
_assertDoesNotMatch(
r'''
@@ -2383,6 +2449,22 @@
''');
}
+ void test_true_fieldFormalParameter_changeName_wasUnresolvedField() {
+ _assertMatches(
+ r'''
+class A {
+ final fff;
+ A(this.unresolved);
+}
+''',
+ r'''
+class A {
+ final fff;
+ A(this.fff);
+}
+''');
+ }
+
void test_true_fieldFormalParameter_function() {
_assertMatches(
r'''
@@ -2987,15 +3069,6 @@
_resolve(_editString('+', '*'), _isFunctionBody);
}
- void test_constructor_fieldFormalParameter() {
- _resolveUnit(r'''
-class A {
- int xy;
- A(this.x);
-}''');
- _resolve(_editString('this.x', 'this.xy'), _isDeclaration);
- }
-
void test_constructor_fieldInitializer_add() {
_resolveUnit(r'''
class A {
@@ -3050,6 +3123,15 @@
_resolve(_editString('+', '*'), _isExpression);
}
+ void test_fieldFormalParameter() {
+ _resolveUnit(r'''
+class A {
+ int xy;
+ A(this.x);
+}''');
+ _resolve(_editString('this.x', 'this.xy'), _isDeclaration);
+ }
+
void test_function_localFunction_add() {
_resolveUnit(r'''
int main() {
@@ -4091,6 +4173,28 @@
''');
}
+ void test_true_todoHint() {
+ _resolveUnit(r'''
+main() {
+ print(1);
+}
+foo() {
+ // TODO
+}
+''');
+ List<AnalysisError> oldErrors = analysisContext.computeErrors(source);
+ _updateAndValidate(r'''
+main() {
+ print(2);
+}
+foo() {
+ // TODO
+}
+''');
+ List<AnalysisError> newErrors = analysisContext.computeErrors(source);
+ _assertEqualErrors(newErrors, oldErrors);
+ }
+
void test_true_wholeConstructor() {
_resolveUnit(r'''
class A {
@@ -4168,28 +4272,6 @@
''');
}
- void test_true_todoHint() {
- _resolveUnit(r'''
-main() {
- print(1);
-}
-foo() {
- // TODO
-}
-''');
- List<AnalysisError> oldErrors = analysisContext.computeErrors(source);
- _updateAndValidate(r'''
-main() {
- print(2);
-}
-foo() {
- // TODO
-}
-''');
- List<AnalysisError> newErrors = analysisContext.computeErrors(source);
- _assertEqualErrors(newErrors, oldErrors);
- }
-
void test_unusedHint_add_wasUsedOnlyInPart() {
Source partSource = addNamedSource(
'/my_unit.dart',
@@ -4440,6 +4522,36 @@
''');
}
+ void test_whitespace_getElementAt() {
+ _resolveUnit(r'''
+class A {}
+class B extends A {}
+''');
+ {
+ ClassElement typeA = oldUnitElement.getType('A');
+ expect(oldUnitElement.getElementAt(typeA.nameOffset), typeA);
+ }
+ {
+ ClassElement typeB = oldUnitElement.getType('B');
+ expect(oldUnitElement.getElementAt(typeB.nameOffset), typeB);
+ }
+ _updateAndValidate(r'''
+class A {}
+
+class B extends A {}
+''');
+ // getElementAt() caches results, it should be notified when offset
+ // are changed.
+ {
+ ClassElement typeA = oldUnitElement.getType('A');
+ expect(oldUnitElement.getElementAt(typeA.nameOffset), typeA);
+ }
+ {
+ ClassElement typeB = oldUnitElement.getType('B');
+ expect(oldUnitElement.getElementAt(typeB.nameOffset), typeB);
+ }
+ }
+
void _assertEqualLineInfo(LineInfo incrLineInfo, LineInfo fullLineInfo) {
for (int offset = 0; offset < 1000; offset++) {
LineInfo_Location incrLocation = incrLineInfo.getLocation(offset);
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 307c41c..1339162 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -995,13 +995,13 @@
final T x = y;
const C();
}
-const y = 1;
+const int y = 1;
var v = const C<String>();
''');
computeLibrarySourceErrors(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH,
- HintCode.INVALID_ASSIGNMENT
+ StaticTypeWarningCode.INVALID_ASSIGNMENT
]);
verify([source]);
}
@@ -1027,11 +1027,11 @@
final T x = y;
const C();
}
-const y = 1;
+const int y = 1;
var v = const C<int>();
''');
computeLibrarySourceErrors(source);
- assertErrors(source, [HintCode.INVALID_ASSIGNMENT]);
+ assertErrors(source, [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
verify([source]);
}
@@ -5931,6 +5931,21 @@
expect(unit.topLevelVariables, hasLength(0));
}
+ void test_libraryElement_docRange() {
+ String code = r'''
+/// My dart doc.
+library lib;
+
+class A {}''';
+ Source librarySource = addSource("/lib.dart", code);
+ LibraryElement element = _buildLibrary(librarySource);
+ expect(element, isNotNull);
+ SourceRange docRange = element.docRange;
+ expect(docRange, isNotNull);
+ expect(docRange.offset, code.indexOf('/// My dart doc.'));
+ expect(docRange.length, '/// My dart doc.'.length);
+ }
+
void test_missingLibraryDirectiveWithPart() {
addSource("/a.dart", "part of lib;");
Source librarySource = addSource("/lib.dart", "part 'a.dart';");
@@ -5989,6 +6004,7 @@
Source librarySource = addSource(
"/lib.dart",
r'''
+/// My dart doc.
library lib;
class A {}''');
@@ -9974,31 +9990,6 @@
}
/**
- * Shared infrastructure for [StaticTypeAnalyzer2Test] and
- * [StrongModeStaticTypeAnalyzer2Test].
- */
-class _StaticTypeAnalyzer2TestShared extends ResolverTestCase {
- String testCode;
- Source testSource;
- CompilationUnit testUnit;
-
- SimpleIdentifier _findIdentifier(String search) {
- SimpleIdentifier identifier = EngineTestCase.findNode(
- testUnit, testCode, search, (node) => node is SimpleIdentifier);
- return identifier;
- }
-
- void _resolveTestUnit(String code) {
- testCode = code;
- testSource = addSource(testCode);
- LibraryElement library = resolve2(testSource);
- assertNoErrors(testSource);
- verify([testSource]);
- testUnit = resolveCompilationUnit(testSource, library);
- }
-}
-
-/**
* Like [StaticTypeAnalyzerTest], but as end-to-end tests.
*/
@reflectiveTest
@@ -11915,25 +11906,11 @@
resetWithOptions(options);
}
- void test_ternaryOperator_null_right() {
+ void test_dynamicObjectGetter_hashCode() {
String code = r'''
main() {
- var foo = (true) ? 3 : null;
-}
-''';
- _resolveTestUnit(code);
-
- SimpleIdentifier identifier = _findIdentifier('foo');
- VariableDeclaration declaration =
- identifier.getAncestor((node) => node is VariableDeclaration);
- expect(declaration.initializer.staticType.name, 'int');
- expect(declaration.initializer.propagatedType, isNull);
- }
-
- void test_ternaryOperator_null_left() {
- String code = r'''
-main() {
- var foo = (true) ? null : 3;
+ dynamic a = null;
+ var foo = a.hashCode;
}
''';
_resolveTestUnit(code);
@@ -11961,38 +11938,6 @@
expect(declaration.initializer.propagatedType, isNull);
}
- void test_dynamicObjectGetter_hashCode() {
- String code = r'''
-main() {
- dynamic a = null;
- var foo = a.hashCode;
-}
-''';
- _resolveTestUnit(code);
-
- SimpleIdentifier identifier = _findIdentifier('foo');
- VariableDeclaration declaration =
- identifier.getAncestor((node) => node is VariableDeclaration);
- expect(declaration.initializer.staticType.name, 'int');
- expect(declaration.initializer.propagatedType, isNull);
- }
-
- void test_pseudoGeneric_max_intInt() {
- String code = r'''
-import 'dart:math';
-main() {
- var foo = max(1, 2);
-}
-''';
- _resolveTestUnit(code);
-
- SimpleIdentifier identifier = _findIdentifier('foo');
- VariableDeclaration declaration =
- identifier.getAncestor((node) => node is VariableDeclaration);
- expect(declaration.initializer.staticType.name, 'int');
- expect(declaration.initializer.propagatedType, isNull);
- }
-
void test_pseudoGeneric_max_doubleDouble() {
String code = r'''
import 'dart:math';
@@ -12009,22 +11954,6 @@
expect(declaration.initializer.propagatedType, isNull);
}
- void test_pseudoGeneric_max_intDouble() {
- String code = r'''
-import 'dart:math';
-main() {
- var foo = max(1, 2.0);
-}
-''';
- _resolveTestUnit(code);
-
- SimpleIdentifier identifier = _findIdentifier('foo');
- VariableDeclaration declaration =
- identifier.getAncestor((node) => node is VariableDeclaration);
- expect(declaration.initializer.staticType.name, 'num');
- expect(declaration.initializer.propagatedType, isNull);
- }
-
void test_pseudoGeneric_max_doubleInt() {
String code = r'''
import 'dart:math';
@@ -12041,6 +11970,38 @@
expect(declaration.initializer.propagatedType, isNull);
}
+ void test_pseudoGeneric_max_intDouble() {
+ String code = r'''
+import 'dart:math';
+main() {
+ var foo = max(1, 2.0);
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'num');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
+ void test_pseudoGeneric_max_intInt() {
+ String code = r'''
+import 'dart:math';
+main() {
+ var foo = max(1, 2);
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'int');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
void test_pseudoGeneric_then() {
String code = r'''
import 'dart:async';
@@ -12055,14 +12016,40 @@
SimpleIdentifier identifier = _findIdentifier('foo');
VariableDeclaration declaration =
identifier.getAncestor((node) => node is VariableDeclaration);
- InterfaceType stringType = typeProvider.stringType;
- InterfaceType futureType = typeProvider.futureType;
- InterfaceType futureOfStringType =
- futureType.substitute4(<DartType>[stringType]);
expect(declaration.initializer.staticType.toString(), "Future<String>");
expect(declaration.initializer.propagatedType, isNull);
}
+
+ void test_ternaryOperator_null_left() {
+ String code = r'''
+main() {
+ var foo = (true) ? null : 3;
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'int');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
+ void test_ternaryOperator_null_right() {
+ String code = r'''
+main() {
+ var foo = (true) ? 3 : null;
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'int');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
}
@reflectiveTest
@@ -12559,6 +12546,18 @@
code, typeProvider.dynamicType, typeProvider.intType);
}
+ void fail_finalPropertyInducingVariable_classMember_instance_unprefixed() {
+ String code = r'''
+class A {
+ final v = 0;
+ m() {
+ v; // marker
+ }
+}''';
+ _assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
void fail_finalPropertyInducingVariable_classMember_static() {
addNamedSource(
"/lib.dart",
@@ -13853,6 +13852,99 @@
assertNoErrors(source);
}
+ void test_objectAccessInference_disabled_for_library_prefix() {
+ String name = 'hashCode';
+ addNamedSource(
+ '/helper.dart',
+ '''
+library helper;
+dynamic get $name => 42;
+''');
+ String code = '''
+import 'helper.dart' as helper;
+main() {
+ helper.$name; // marker
+}''';
+
+ SimpleIdentifier id = _findMarkedIdentifier(code, "; // marker");
+ PrefixedIdentifier prefixedId = id.parent;
+ expect(id.staticType, typeProvider.dynamicType);
+ expect(prefixedId.staticType, typeProvider.dynamicType);
+ }
+
+ void test_objectAccessInference_disabled_for_local_getter() {
+ String name = 'hashCode';
+ String code = '''
+dynamic get $name => null;
+main() {
+ $name; // marker
+}''';
+
+ SimpleIdentifier getter = _findMarkedIdentifier(code, "; // marker");
+ expect(getter.staticType, typeProvider.dynamicType);
+ }
+
+ void test_objectAccessInference_enabled_for_cascades() {
+ String name = 'hashCode';
+ String code = '''
+main() {
+ dynamic obj;
+ obj..$name..$name; // marker
+}''';
+ PropertyAccess access = _findMarkedIdentifier(code, "; // marker").parent;
+ expect(access.staticType, typeProvider.dynamicType);
+ expect(access.realTarget.staticType, typeProvider.dynamicType);
+ }
+
+ void test_objectMethodInference_disabled_for_library_prefix() {
+ String name = 'toString';
+ addNamedSource(
+ '/helper.dart',
+ '''
+library helper;
+dynamic $name = (int x) => x + 42');
+''');
+ String code = '''
+import 'helper.dart' as helper;
+main() {
+ helper.$name(); // marker
+}''';
+ SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
+ MethodInvocation methodInvoke = methodName.parent;
+ expect(methodName.staticType, null, reason: 'library prefix has no type');
+ expect(methodInvoke.staticType, typeProvider.dynamicType);
+ }
+
+ void test_objectMethodInference_disabled_for_local_function() {
+ String name = 'toString';
+ String code = '''
+main() {
+ dynamic $name = () => null;
+ $name(); // marker
+}''';
+ SimpleIdentifier identifier = _findMarkedIdentifier(code, "$name = ");
+ expect(identifier.staticType, typeProvider.dynamicType);
+
+ SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
+ MethodInvocation methodInvoke = methodName.parent;
+ expect(methodName.staticType, typeProvider.dynamicType);
+ expect(methodInvoke.staticType, typeProvider.dynamicType);
+ }
+
+ void test_objectMethodInference_enabled_for_cascades() {
+ String name = 'toString';
+ String code = '''
+main() {
+ dynamic obj;
+ obj..$name()..$name(); // marker
+}''';
+ SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
+ MethodInvocation methodInvoke = methodName.parent;
+
+ expect(methodInvoke.staticType, typeProvider.dynamicType);
+ expect(methodInvoke.realTarget.staticType, typeProvider.dynamicType);
+ }
+
void test_objectMethodOnDynamicExpression_doubleEquals() {
// https://code.google.com/p/dart/issues/detail?id=20342
//
@@ -13906,96 +13998,6 @@
typeProvider.stringType);
}
- void test_objectMethodInference_disabled_for_local_function() {
- String name = 'toString';
- String code = '''
-main() {
- dynamic $name = () => null;
- $name(); // marker
-}''';
- SimpleIdentifier identifier = _findMarkedIdentifier(code, "$name = ");
- expect(identifier.staticType, typeProvider.dynamicType);
-
- SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
- MethodInvocation methodInvoke = methodName.parent;
- expect(methodName.staticType, typeProvider.dynamicType);
- expect(methodInvoke.staticType, typeProvider.dynamicType);
- }
-
- void test_objectMethodInference_disabled_for_library_prefix() {
- String name = 'toString';
- addNamedSource('/helper.dart', '''
-library helper;
-dynamic $name = (int x) => x + 42');
-''');
- String code = '''
-import 'helper.dart' as helper;
-main() {
- helper.$name(); // marker
-}''';
- SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
- MethodInvocation methodInvoke = methodName.parent;
- expect(methodName.staticType, null, reason: 'library prefix has no type');
- expect(methodInvoke.staticType, typeProvider.dynamicType);
- }
-
- void test_objectMethodInference_enabled_for_cascades() {
- String name = 'toString';
- String code = '''
-main() {
- dynamic obj;
- obj..$name()..$name(); // marker
-}''';
- SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
- MethodInvocation methodInvoke = methodName.parent;
-
- expect(methodInvoke.staticType, typeProvider.dynamicType);
- expect(methodInvoke.realTarget.staticType, typeProvider.dynamicType);
- }
-
-
- void test_objectAccessInference_disabled_for_local_getter() {
- String name = 'hashCode';
- String code = '''
-dynamic get $name => null;
-main() {
- $name; // marker
-}''';
-
- SimpleIdentifier getter = _findMarkedIdentifier(code, "; // marker");
- expect(getter.staticType, typeProvider.dynamicType);
- }
-
- void test_objectAccessInference_disabled_for_library_prefix() {
- String name = 'hashCode';
- addNamedSource('/helper.dart', '''
-library helper;
-dynamic get $name => 42;
-''');
- String code = '''
-import 'helper.dart' as helper;
-main() {
- helper.$name; // marker
-}''';
-
- SimpleIdentifier id = _findMarkedIdentifier(code, "; // marker");
- PrefixedIdentifier prefixedId = id.parent;
- expect(id.staticType, typeProvider.dynamicType);
- expect(prefixedId.staticType, typeProvider.dynamicType);
- }
-
- void test_objectAccessInference_enabled_for_cascades() {
- String name = 'hashCode';
- String code = '''
-main() {
- dynamic obj;
- obj..$name..$name; // marker
-}''';
- PropertyAccess access = _findMarkedIdentifier(code, "; // marker").parent;
- expect(access.staticType, typeProvider.dynamicType);
- expect(access.realTarget.staticType, typeProvider.dynamicType);
- }
-
void test_propagatedReturnType_localFunction() {
String code = r'''
main() {
@@ -14833,3 +14835,28 @@
return null;
}
}
+
+/**
+ * Shared infrastructure for [StaticTypeAnalyzer2Test] and
+ * [StrongModeStaticTypeAnalyzer2Test].
+ */
+class _StaticTypeAnalyzer2TestShared extends ResolverTestCase {
+ String testCode;
+ Source testSource;
+ CompilationUnit testUnit;
+
+ SimpleIdentifier _findIdentifier(String search) {
+ SimpleIdentifier identifier = EngineTestCase.findNode(
+ testUnit, testCode, search, (node) => node is SimpleIdentifier);
+ return identifier;
+ }
+
+ void _resolveTestUnit(String code) {
+ testCode = code;
+ testSource = addSource(testCode);
+ LibraryElement library = resolve2(testSource);
+ assertNoErrors(testSource);
+ verify([testSource]);
+ testUnit = resolveCompilationUnit(testSource, library);
+ }
+}
diff --git a/pkg/analyzer/test/generated/type_system_test.dart b/pkg/analyzer/test/generated/type_system_test.dart
index a6c552a..d49c75c 100644
--- a/pkg/analyzer/test/generated/type_system_test.dart
+++ b/pkg/analyzer/test/generated/type_system_test.dart
@@ -791,7 +791,7 @@
DartType top = TypeBuilder.functionType(<DartType>[intType], objectType);
InterfaceType bottom = classBottom.type;
- _checkIsAssignableTo(top, bottom);
+ _checkIsStrictAssignableTo(bottom, top);
}
void test_isAssignableTo_fuzzy_arrows() {
diff --git a/pkg/analyzer/test/source/analysis_options_provider_test.dart b/pkg/analyzer/test/source/analysis_options_provider_test.dart
index 80bf2ad..a251770 100644
--- a/pkg/analyzer/test/source/analysis_options_provider_test.dart
+++ b/pkg/analyzer/test/source/analysis_options_provider_test.dart
@@ -52,6 +52,7 @@
var optionsProvider = new AnalysisOptionsProvider();
Map<String, YamlNode> options =
optionsProvider.getOptions(resourceProvider.getFolder('/'));
+ expect(options, isNotNull);
});
});
group('AnalysisOptionsProvider', () {
@@ -67,7 +68,8 @@
try {
Map<String, YamlNode> options =
optionsProvider.getOptions(resourceProvider.getFolder('/'));
- } catch (e, st) {
+ expect(options, isNotNull);
+ } catch (e) {
exceptionCaught = true;
}
expect(exceptionCaught, isTrue);
diff --git a/pkg/analyzer/test/src/context/context_test.dart b/pkg/analyzer/test/src/context/context_test.dart
index 734c1b2..0544bf5 100644
--- a/pkg/analyzer/test/src/context/context_test.dart
+++ b/pkg/analyzer/test/src/context/context_test.dart
@@ -1500,7 +1500,7 @@
reason: "part changed 3");
_analyzeAll_assertFinished();
expect(context.getResolvedCompilationUnit2(libSource, libSource), isNotNull,
- reason: "library resolved 2");
+ reason: "library resolved 3");
expect(
context.getResolvedCompilationUnit2(partSource, libSource), isNotNull,
reason: "part resolved 3");
diff --git a/pkg/analyzer/test/src/task/dart_test.dart b/pkg/analyzer/test/src/task/dart_test.dart
index 51a86fb..1c94faf 100644
--- a/pkg/analyzer/test/src/task/dart_test.dart
+++ b/pkg/analyzer/test/src/task/dart_test.dart
@@ -15,6 +15,7 @@
import 'package:analyzer/src/generated/scanner.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/services/lint.dart';
import 'package:analyzer/src/task/dart.dart';
import 'package:analyzer/src/task/html.dart';
import 'package:analyzer/task/dart.dart';
@@ -48,6 +49,7 @@
runReflectiveTests(GatherUsedImportedElementsTaskTest);
runReflectiveTests(GatherUsedLocalElementsTaskTest);
runReflectiveTests(GenerateHintsTaskTest);
+ runReflectiveTests(GenerateLintsTaskTest);
runReflectiveTests(InferInstanceMembersInUnitTaskTest);
runReflectiveTests(InferStaticVariableTypesInUnitTaskTest);
runReflectiveTests(InferStaticVariableTypeTaskTest);
@@ -98,6 +100,7 @@
isInstanceOf isGatherUsedLocalElementsTask =
new isInstanceOf<GatherUsedLocalElementsTask>();
isInstanceOf isGenerateHintsTask = new isInstanceOf<GenerateHintsTask>();
+isInstanceOf isGenerateLintsTask = new isInstanceOf<GenerateLintsTask>();
isInstanceOf isInferInstanceMembersInUnitTask =
new isInstanceOf<InferInstanceMembersInUnitTask>();
isInstanceOf isInferStaticVariableTypesInUnitTask =
@@ -122,6 +125,8 @@
isInstanceOf isScanDartTask = new isInstanceOf<ScanDartTask>();
isInstanceOf isVerifyUnitTask = new isInstanceOf<VerifyUnitTask>();
+final LintCode _testLintCode = new LintCode('test lint', 'test lint code');
+
@reflectiveTest
class BuildCompilationUnitElementTaskTest extends _AbstractDartTaskTest {
Source source;
@@ -1876,6 +1881,62 @@
}
@reflectiveTest
+class GenerateLintsTaskTest extends _AbstractDartTaskTest {
+ void enableLints() {
+ AnalysisOptionsImpl options = context.analysisOptions;
+ options.lint = true;
+ context.analysisOptions = options;
+ }
+
+ @override
+ void setUp() {
+ super.setUp();
+ enableLints();
+ }
+
+ @override
+ void tearDown() {
+ LintGenerator.LINTERS.clear();
+ super.tearDown();
+ }
+
+ test_camel_case_types() {
+ Source source = newSource(
+ '/test.dart',
+ '''
+class a { }
+''');
+
+ LintGenerator.LINTERS.clear();
+ LintGenerator.LINTERS.add(new GenerateLintsTaskTest_TestLinter());
+
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+ computeResult(target, LINTS, matcher: isGenerateLintsTask);
+ // validate
+ _fillErrorListener(LINTS);
+ errorListener.assertErrorsWithCodes(<ErrorCode>[_testLintCode]);
+ }
+}
+
+class GenerateLintsTaskTest_AstVisitor extends SimpleAstVisitor {
+ Linter linter;
+ GenerateLintsTaskTest_AstVisitor(this.linter);
+
+ @override
+ visitClassDeclaration(ClassDeclaration node) {
+ if (!new RegExp(r'^([_]*)([A-Z]+[a-z0-9]*)+$')
+ .hasMatch(node.name.toString())) {
+ linter.reporter.reportErrorForNode(_testLintCode, node, []);
+ }
+ }
+}
+
+class GenerateLintsTaskTest_TestLinter extends Linter {
+ @override
+ AstVisitor getVisitor() => new GenerateLintsTaskTest_AstVisitor(this);
+}
+
+@reflectiveTest
class InferInstanceMembersInUnitTaskTest extends _AbstractDartTaskTest {
void test_perform() {
enableStrongMode();
@@ -1973,6 +2034,23 @@
@reflectiveTest
class InferStaticVariableTypesInUnitTaskTest extends _AbstractDartTaskTest {
+ void test_perform_const_field() {
+ enableStrongMode();
+ AnalysisTarget source = newSource(
+ '/test.dart',
+ '''
+class M {
+ static const X = "";
+}
+''');
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6,
+ matcher: isInferStaticVariableTypesInUnitTask);
+ CompilationUnit unit = outputs[RESOLVED_UNIT6];
+ VariableDeclaration declaration = getFieldInClass(unit, 'M', 'X');
+ InterfaceType stringType = context.typeProvider.stringType;
+ expect(declaration.element.type, stringType);
+ }
+
void test_perform_nestedDeclarations() {
enableStrongMode();
AnalysisTarget source = newSource(
@@ -2050,23 +2128,6 @@
InterfaceType intType = context.typeProvider.intType;
expect(expression.staticType, intType);
}
-
- void test_perform_const_field() {
- enableStrongMode();
- AnalysisTarget source = newSource(
- '/test.dart',
- '''
-class M {
- static const X = "";
-}
-''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6,
- matcher: isInferStaticVariableTypesInUnitTask);
- CompilationUnit unit = outputs[RESOLVED_UNIT6];
- VariableDeclaration declaration = getFieldInClass(unit, 'M', 'X');
- InterfaceType stringType = context.typeProvider.stringType;
- expect(declaration.element.type, stringType);
- }
}
@reflectiveTest
@@ -2128,31 +2189,6 @@
expect(outputs[INFER_STATIC_VARIABLE_ERRORS], hasLength(0));
}
- void test_perform_reresolution() {
- AnalysisTarget source = newSource(
- '/test.dart',
- '''
-const topLevel = '';
-class C {
- String field = topLevel;
-}
-''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
- CompilationUnit unit = outputs[RESOLVED_UNIT5];
- VariableDeclaration topLevelDecl = getTopLevelVariable(unit, 'topLevel');
- VariableDeclaration fieldDecl = getFieldInClass(unit, 'C', 'field');
- VariableElement topLevel = topLevelDecl.name.staticElement;
- VariableElement field = fieldDecl.name.staticElement;
-
- computeResult(field, INFERRED_STATIC_VARIABLE,
- matcher: isInferStaticVariableTypeTask);
- InterfaceType stringType = context.typeProvider.stringType;
- expect(topLevel.type, stringType);
- expect(field.type, stringType);
- expect(fieldDecl.initializer.staticType, stringType);
- expect(outputs[INFER_STATIC_VARIABLE_ERRORS], hasLength(0));
- }
-
void test_perform_const() {
AnalysisTarget source = newSource(
'/test.dart',
@@ -2231,6 +2267,31 @@
expect(a.type.isDynamic, isTrue);
expect(outputs[INFER_STATIC_VARIABLE_ERRORS], hasLength(0));
}
+
+ void test_perform_reresolution() {
+ AnalysisTarget source = newSource(
+ '/test.dart',
+ '''
+const topLevel = '';
+class C {
+ String field = topLevel;
+}
+''');
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
+ CompilationUnit unit = outputs[RESOLVED_UNIT5];
+ VariableDeclaration topLevelDecl = getTopLevelVariable(unit, 'topLevel');
+ VariableDeclaration fieldDecl = getFieldInClass(unit, 'C', 'field');
+ VariableElement topLevel = topLevelDecl.name.staticElement;
+ VariableElement field = fieldDecl.name.staticElement;
+
+ computeResult(field, INFERRED_STATIC_VARIABLE,
+ matcher: isInferStaticVariableTypeTask);
+ InterfaceType stringType = context.typeProvider.stringType;
+ expect(topLevel.type, stringType);
+ expect(field.type, stringType);
+ expect(fieldDecl.initializer.staticType, stringType);
+ expect(outputs[INFER_STATIC_VARIABLE_ERRORS], hasLength(0));
+ }
}
@reflectiveTest
@@ -2594,472 +2655,6 @@
}
@reflectiveTest
-class StrongModeInferenceTest extends _AbstractDartTaskTest {
-
- @override
- void setUp() {
- super.setUp();
- enableStrongMode();
- }
-
- // Check that even within a static variable cycle, inferred
- // types get propagated to the members of the cycle.
- void test_perform_cycle() {
- AnalysisTarget source = newSource(
- '/test.dart',
- '''
-var piFirst = true;
-var pi = piFirst ? 3.14 : tau / 2;
-var tau = piFirst ? pi * 2 : 6.28;
-''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
- CompilationUnit unit = outputs[RESOLVED_UNIT8];
- VariableElement piFirst =
- getTopLevelVariable(unit, 'piFirst').name.staticElement;
- VariableElement pi = getTopLevelVariable(unit, 'pi').name.staticElement;
- VariableElement tau = getTopLevelVariable(unit, 'tau').name.staticElement;
- Expression piFirstUse = (getTopLevelVariable(unit, 'tau').initializer
- as ConditionalExpression).condition;
-
- expect(piFirstUse.staticType, context.typeProvider.boolType);
- expect(piFirst.type, context.typeProvider.boolType);
- expect(pi.type.isDynamic, isTrue);
- expect(tau.type.isDynamic, isTrue);
- }
-
- void test_perform_local_explicit_disabled() {
- AnalysisTarget source = newSource(
- '/test.dart',
- '''
- test() {
- int x = 3;
- x = "hi";
- }
-''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
- CompilationUnit unit = outputs[RESOLVED_UNIT8];
-
- InterfaceType intType = context.typeProvider.intType;
- InterfaceType stringType = context.typeProvider.stringType;
-
- List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
- VariableDeclaration decl =
- (statements[0] as VariableDeclarationStatement).variables.variables[0];
- expect(decl.element.type, intType);
- expect(decl.initializer.staticType, intType);
-
- ExpressionStatement statement = statements[1];
- AssignmentExpression assgn = statement.expression;
- expect(assgn.leftHandSide.staticType, intType);
- expect(assgn.rightHandSide.staticType, stringType);
- }
-
- void assertVariableDeclarationTypes(
- VariableDeclaration decl, DartType varType, DartType initializerType) {
- expect(decl.element.type, varType);
- expect(decl.initializer.staticType, initializerType);
- }
-
- void assertVariableDeclarationStatementTypes(
- Statement stmt, DartType varType, DartType initializerType) {
- VariableDeclaration decl =
- (stmt as VariableDeclarationStatement).variables.variables[0];
- assertVariableDeclarationTypes(decl, varType, initializerType);
- }
-
- void assertAssignmentStatementTypes(
- Statement stmt, DartType leftType, DartType rightType) {
- AssignmentExpression assgn = (stmt as ExpressionStatement).expression;
- expect(assgn.leftHandSide.staticType, leftType);
- expect(assgn.rightHandSide.staticType, rightType);
- }
-
- // Test that local variables in method bodies are inferred appropriately
- void test_perform_inference_local_variables() {
- AnalysisTarget source = newSource(
- '/test.dart',
- '''
- test() {
- int x = 3;
- x = "hi";
- var y = 3;
- y = "hi";
- }
-''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
- CompilationUnit unit = outputs[RESOLVED_UNIT8];
-
- InterfaceType intType = context.typeProvider.intType;
- InterfaceType stringType = context.typeProvider.stringType;
-
- List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
-
- assertVariableDeclarationStatementTypes(statements[0], intType, intType);
- assertAssignmentStatementTypes(statements[1], intType, stringType);
- assertVariableDeclarationStatementTypes(statements[2], intType, intType);
- assertAssignmentStatementTypes(statements[3], intType, stringType);
- }
-
- // Test inference interactions between local variables and fields
- void test_perform_inference_local_variables_fields() {
- AnalysisTarget source = newSource(
- '/test.dart',
- '''
- class A {
- int x = 0;
-
- test1() {
- var a = x;
- a = "hi";
- a = 3;
- var b = y;
- b = "hi";
- b = 4;
- var c = z;
- c = "hi";
- c = 4;
- }
-
- int y; // field def after use
- final z = 42; // should infer `int`
- }
-''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
- CompilationUnit unit = outputs[RESOLVED_UNIT8];
-
- InterfaceType intType = context.typeProvider.intType;
- InterfaceType stringType = context.typeProvider.stringType;
-
- List<Statement> statements = getStatementsInMethod(unit, "A", "test1");
-
- assertVariableDeclarationStatementTypes(statements[0], intType, intType);
- assertAssignmentStatementTypes(statements[1], intType, stringType);
- assertAssignmentStatementTypes(statements[2], intType, intType);
-
- assertVariableDeclarationStatementTypes(statements[3], intType, intType);
- assertAssignmentStatementTypes(statements[4], intType, stringType);
- assertAssignmentStatementTypes(statements[5], intType, intType);
-
- assertVariableDeclarationStatementTypes(statements[6], intType, intType);
- assertAssignmentStatementTypes(statements[7], intType, stringType);
- assertAssignmentStatementTypes(statements[8], intType, intType);
-
- assertVariableDeclarationTypes(
- getFieldInClass(unit, "A", "x"), intType, intType);
- assertVariableDeclarationTypes(
- getFieldInClass(unit, "A", "z"), intType, intType);
- }
-
- // Test inference interactions between local variables and top level
- // variables
- void test_perform_inference_local_variables_topLevel() {
- AnalysisTarget source = newSource(
- '/test.dart',
- '''
- int x = 0;
-
- test1() {
- var a = x;
- a = /*severe:StaticTypeError*/"hi";
- a = 3;
- var b = y;
- b = /*severe:StaticTypeError*/"hi";
- b = 4;
- var c = z;
- c = /*severe:StaticTypeError*/"hi";
- c = 4;
- }
-
- int y = 0; // field def after use
- final z = 42; // should infer `int`
-''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
- CompilationUnit unit = outputs[RESOLVED_UNIT8];
-
- InterfaceType intType = context.typeProvider.intType;
- InterfaceType stringType = context.typeProvider.stringType;
-
- List<Statement> statements = getStatementsInTopLevelFunction(unit, "test1");
-
- assertVariableDeclarationStatementTypes(statements[0], intType, intType);
- assertAssignmentStatementTypes(statements[1], intType, stringType);
- assertAssignmentStatementTypes(statements[2], intType, intType);
-
- assertVariableDeclarationStatementTypes(statements[3], intType, intType);
- assertAssignmentStatementTypes(statements[4], intType, stringType);
- assertAssignmentStatementTypes(statements[5], intType, intType);
-
- assertVariableDeclarationStatementTypes(statements[6], intType, intType);
- assertAssignmentStatementTypes(statements[7], intType, stringType);
- assertAssignmentStatementTypes(statements[8], intType, intType);
-
- assertVariableDeclarationTypes(
- getTopLevelVariable(unit, "x"), intType, intType);
- assertVariableDeclarationTypes(
- getTopLevelVariable(unit, "y"), intType, intType);
- assertVariableDeclarationTypes(
- getTopLevelVariable(unit, "z"), intType, intType);
- }
-
- // Test that inference does not propagate from null
- void test_perform_inference_null() {
- AnalysisTarget source = newSource(
- '/test.dart',
- '''
- var x = null;
- var y = 3;
- class A {
- static var x = null;
- static var y = 3;
-
- var x2 = null;
- var y2 = 3;
- }
-
- test() {
- x = "hi";
- y = /*severe:StaticTypeError*/"hi";
- A.x = "hi";
- A.y = /*severe:StaticTypeError*/"hi";
- new A().x2 = "hi";
- new A().y2 = /*severe:StaticTypeError*/"hi";
- }
-''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
- CompilationUnit unit = outputs[RESOLVED_UNIT8];
-
- InterfaceType intType = context.typeProvider.intType;
- InterfaceType stringType = context.typeProvider.stringType;
- DartType bottomType = context.typeProvider.bottomType;
- DartType dynamicType = context.typeProvider.dynamicType;
-
- assertVariableDeclarationTypes(
- getTopLevelVariable(unit, "x"), dynamicType, bottomType);
- assertVariableDeclarationTypes(
- getTopLevelVariable(unit, "y"), intType, intType);
- assertVariableDeclarationTypes(
- getFieldInClass(unit, "A", "x"), dynamicType, bottomType);
- assertVariableDeclarationTypes(
- getFieldInClass(unit, "A", "y"), intType, intType);
- assertVariableDeclarationTypes(
- getFieldInClass(unit, "A", "x2"), dynamicType, bottomType);
- assertVariableDeclarationTypes(
- getFieldInClass(unit, "A", "y2"), intType, intType);
-
- List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
-
- assertAssignmentStatementTypes(statements[0], dynamicType, stringType);
- assertAssignmentStatementTypes(statements[1], intType, stringType);
- assertAssignmentStatementTypes(statements[2], dynamicType, stringType);
- assertAssignmentStatementTypes(statements[3], intType, stringType);
- assertAssignmentStatementTypes(statements[4], dynamicType, stringType);
- assertAssignmentStatementTypes(statements[5], intType, stringType);
- }
-
- // Test inference across units (non-cyclic)
- void test_perform_inference_cross_unit_non_cyclic() {
- AnalysisTarget firstSource = newSource(
- '/a.dart',
- '''
- var x = 2;
- class A { static var x = 2; }
-''');
- AnalysisTarget secondSource = newSource(
- '/test.dart',
- '''
- import 'a.dart';
- var y = x;
- class B { static var y = A.x; }
-
- test1() {
- x = /*severe:StaticTypeError*/"hi";
- y = /*severe:StaticTypeError*/"hi";
- A.x = /*severe:StaticTypeError*/"hi";
- B.y = /*severe:StaticTypeError*/"hi";
- }
-''');
- computeResult(
- new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT8);
- CompilationUnit unit1 = outputs[RESOLVED_UNIT8];
- computeResult(
- new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT8);
- CompilationUnit unit2 = outputs[RESOLVED_UNIT8];
-
- InterfaceType intType = context.typeProvider.intType;
- InterfaceType stringType = context.typeProvider.stringType;
- DartType dynamicType = context.typeProvider.dynamicType;
-
- assertVariableDeclarationTypes(
- getTopLevelVariable(unit1, "x"), intType, intType);
- assertVariableDeclarationTypes(
- getFieldInClass(unit1, "A", "x"), intType, intType);
-
- assertVariableDeclarationTypes(
- getTopLevelVariable(unit2, "y"), intType, intType);
- assertVariableDeclarationTypes(
- getFieldInClass(unit2, "B", "y"), intType, intType);
-
- List<Statement> statements =
- getStatementsInTopLevelFunction(unit2, "test1");
-
- assertAssignmentStatementTypes(statements[0], intType, stringType);
- assertAssignmentStatementTypes(statements[1], intType, stringType);
- }
-
- // Test inference across units (cyclic)
- void test_perform_inference_cross_unit_cyclic() {
- AnalysisTarget firstSource = newSource(
- '/a.dart',
- '''
- import 'test.dart';
- var x = 2;
- class A { static var x = 2; }
-''');
- AnalysisTarget secondSource = newSource(
- '/test.dart',
- '''
- import 'a.dart';
- var y = x;
- class B { static var y = A.x; }
-
- test1() {
- int t = 3;
- t = x;
- t = y;
- t = A.x;
- t = B.y;
- }
-''');
- computeResult(
- new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT8);
- CompilationUnit unit1 = outputs[RESOLVED_UNIT8];
- computeResult(
- new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT8);
- CompilationUnit unit2 = outputs[RESOLVED_UNIT8];
-
- InterfaceType intType = context.typeProvider.intType;
- InterfaceType stringType = context.typeProvider.stringType;
-
- assertVariableDeclarationTypes(
- getTopLevelVariable(unit1, "x"), intType, intType);
- assertVariableDeclarationTypes(
- getFieldInClass(unit1, "A", "x"), intType, intType);
-
- assertVariableDeclarationTypes(
- getTopLevelVariable(unit2, "y"), intType, intType);
- assertVariableDeclarationTypes(
- getFieldInClass(unit2, "B", "y"), intType, intType);
-
- List<Statement> statements =
- getStatementsInTopLevelFunction(unit2, "test1");
-
- assertAssignmentStatementTypes(statements[1], intType, intType);
- assertAssignmentStatementTypes(statements[2], intType, intType);
- assertAssignmentStatementTypes(statements[3], intType, intType);
- assertAssignmentStatementTypes(statements[4], intType, intType);
- }
-
- // Test inference of instance fields across units
- // TODO(leafp): Fix this
- // https://github.com/dart-lang/dev_compiler/issues/354
- void fail_perform_inference_cross_unit_instance() {
- List<Source> sources = newSources({
- '/a7.dart': '''
- import 'b7.dart';
- class A {
- final a2 = new B().b2;
- }
- ''',
- '/b7.dart': '''
- class B {
- final b2 = 1;
- }
- ''',
- '/main7.dart': '''
- import "a7.dart";
-
- test1() {
- int x = 0;
- x = new A().a2;
- }
- '''
- });
- List<dynamic> units =
- computeLibraryResults(sources, RESOLVED_UNIT8).toList();
- CompilationUnit unit0 = units[0];
- CompilationUnit unit1 = units[1];
- CompilationUnit unit2 = units[2];
-
- InterfaceType intType = context.typeProvider.intType;
-
- assertVariableDeclarationTypes(
- getFieldInClass(unit0, "A", "a2"), intType, intType);
-
- assertVariableDeclarationTypes(
- getFieldInClass(unit1, "B", "b2"), intType, intType);
-
- List<Statement> statements =
- getStatementsInTopLevelFunction(unit2, "test1");
-
- assertAssignmentStatementTypes(statements[1], intType, intType);
- }
-
- // Test inference between static and instance fields
- // TODO(leafp): Fix this
- // https://github.com/dart-lang/dev_compiler/issues/354
- void fail_perform_inference_cross_unit_static_instance() {
- List<Source> sources = newSources({
- '/a.dart': '''
- import 'b.dart';
- class A {
- static final a1 = B.b1;
- final a2 = new B().b2;
- }
- ''',
- '/b.dart': '''
- class B {
- static final b1 = 1;
- final b2 = 1;
- }
- ''',
- '/main.dart': '''
- import "a.dart";
-
- test1() {
- int x = 0;
- // inference in A now works.
- x = A.a1;
- x = new A().a2;
- }
- '''
- });
- List<dynamic> units =
- computeLibraryResults(sources, RESOLVED_UNIT8).toList();
- CompilationUnit unit0 = units[0];
- CompilationUnit unit1 = units[1];
- CompilationUnit unit2 = units[2];
-
- InterfaceType intType = context.typeProvider.intType;
-
- assertVariableDeclarationTypes(
- getFieldInClass(unit0, "A", "a1"), intType, intType);
- assertVariableDeclarationTypes(
- getFieldInClass(unit0, "A", "a2"), intType, intType);
-
- assertVariableDeclarationTypes(
- getFieldInClass(unit1, "B", "b1"), intType, intType);
- assertVariableDeclarationTypes(
- getFieldInClass(unit1, "B", "b2"), intType, intType);
-
- List<Statement> statements =
- getStatementsInTopLevelFunction(unit2, "test1");
-
- assertAssignmentStatementTypes(statements[1], intType, intType);
- assertAssignmentStatementTypes(statements[2], intType, intType);
- }
-}
-
-@reflectiveTest
class ResolveLibraryTypeNamesTaskTest extends _AbstractDartTaskTest {
test_perform() {
Source sourceLib = newSource(
@@ -3338,6 +2933,469 @@
}
@reflectiveTest
+class StrongModeInferenceTest extends _AbstractDartTaskTest {
+ void assertAssignmentStatementTypes(
+ Statement stmt, DartType leftType, DartType rightType) {
+ AssignmentExpression assgn = (stmt as ExpressionStatement).expression;
+ expect(assgn.leftHandSide.staticType, leftType);
+ expect(assgn.rightHandSide.staticType, rightType);
+ }
+
+ // Check that even within a static variable cycle, inferred
+ // types get propagated to the members of the cycle.
+ void assertVariableDeclarationStatementTypes(
+ Statement stmt, DartType varType, DartType initializerType) {
+ VariableDeclaration decl =
+ (stmt as VariableDeclarationStatement).variables.variables[0];
+ assertVariableDeclarationTypes(decl, varType, initializerType);
+ }
+
+ void assertVariableDeclarationTypes(
+ VariableDeclaration decl, DartType varType, DartType initializerType) {
+ expect(decl.element.type, varType);
+ expect(decl.initializer.staticType, initializerType);
+ }
+
+ void fail_perform_inference_cross_unit_instance() {
+ List<Source> sources = newSources({
+ '/a7.dart': '''
+ import 'b7.dart';
+ class A {
+ final a2 = new B().b2;
+ }
+ ''',
+ '/b7.dart': '''
+ class B {
+ final b2 = 1;
+ }
+ ''',
+ '/main7.dart': '''
+ import "a7.dart";
+
+ test1() {
+ int x = 0;
+ x = new A().a2;
+ }
+ '''
+ });
+ List<dynamic> units =
+ computeLibraryResults(sources, RESOLVED_UNIT8).toList();
+ CompilationUnit unit0 = units[0];
+ CompilationUnit unit1 = units[1];
+ CompilationUnit unit2 = units[2];
+
+ InterfaceType intType = context.typeProvider.intType;
+
+ assertVariableDeclarationTypes(
+ getFieldInClass(unit0, "A", "a2"), intType, intType);
+
+ assertVariableDeclarationTypes(
+ getFieldInClass(unit1, "B", "b2"), intType, intType);
+
+ List<Statement> statements =
+ getStatementsInTopLevelFunction(unit2, "test1");
+
+ assertAssignmentStatementTypes(statements[1], intType, intType);
+ }
+
+ void fail_perform_inference_cross_unit_static_instance() {
+ List<Source> sources = newSources({
+ '/a.dart': '''
+ import 'b.dart';
+ class A {
+ static final a1 = B.b1;
+ final a2 = new B().b2;
+ }
+ ''',
+ '/b.dart': '''
+ class B {
+ static final b1 = 1;
+ final b2 = 1;
+ }
+ ''',
+ '/main.dart': '''
+ import "a.dart";
+
+ test1() {
+ int x = 0;
+ // inference in A now works.
+ x = A.a1;
+ x = new A().a2;
+ }
+ '''
+ });
+ List<dynamic> units =
+ computeLibraryResults(sources, RESOLVED_UNIT8).toList();
+ CompilationUnit unit0 = units[0];
+ CompilationUnit unit1 = units[1];
+ CompilationUnit unit2 = units[2];
+
+ InterfaceType intType = context.typeProvider.intType;
+
+ assertVariableDeclarationTypes(
+ getFieldInClass(unit0, "A", "a1"), intType, intType);
+ assertVariableDeclarationTypes(
+ getFieldInClass(unit0, "A", "a2"), intType, intType);
+
+ assertVariableDeclarationTypes(
+ getFieldInClass(unit1, "B", "b1"), intType, intType);
+ assertVariableDeclarationTypes(
+ getFieldInClass(unit1, "B", "b2"), intType, intType);
+
+ List<Statement> statements =
+ getStatementsInTopLevelFunction(unit2, "test1");
+
+ assertAssignmentStatementTypes(statements[1], intType, intType);
+ assertAssignmentStatementTypes(statements[2], intType, intType);
+ }
+
+ @override
+ void setUp() {
+ super.setUp();
+ enableStrongMode();
+ }
+
+ // Test that local variables in method bodies are inferred appropriately
+ void test_perform_cycle() {
+ AnalysisTarget source = newSource(
+ '/test.dart',
+ '''
+var piFirst = true;
+var pi = piFirst ? 3.14 : tau / 2;
+var tau = piFirst ? pi * 2 : 6.28;
+''');
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
+ CompilationUnit unit = outputs[RESOLVED_UNIT8];
+ VariableElement piFirst =
+ getTopLevelVariable(unit, 'piFirst').name.staticElement;
+ VariableElement pi = getTopLevelVariable(unit, 'pi').name.staticElement;
+ VariableElement tau = getTopLevelVariable(unit, 'tau').name.staticElement;
+ Expression piFirstUse = (getTopLevelVariable(unit, 'tau').initializer
+ as ConditionalExpression).condition;
+
+ expect(piFirstUse.staticType, context.typeProvider.boolType);
+ expect(piFirst.type, context.typeProvider.boolType);
+ expect(pi.type.isDynamic, isTrue);
+ expect(tau.type.isDynamic, isTrue);
+ }
+
+ // Test inference interactions between local variables and fields
+ void test_perform_inference_cross_unit_cyclic() {
+ AnalysisTarget firstSource = newSource(
+ '/a.dart',
+ '''
+ import 'test.dart';
+ var x = 2;
+ class A { static var x = 2; }
+''');
+ AnalysisTarget secondSource = newSource(
+ '/test.dart',
+ '''
+ import 'a.dart';
+ var y = x;
+ class B { static var y = A.x; }
+
+ test1() {
+ int t = 3;
+ t = x;
+ t = y;
+ t = A.x;
+ t = B.y;
+ }
+''');
+ computeResult(
+ new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT8);
+ CompilationUnit unit1 = outputs[RESOLVED_UNIT8];
+ computeResult(
+ new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT8);
+ CompilationUnit unit2 = outputs[RESOLVED_UNIT8];
+
+ InterfaceType intType = context.typeProvider.intType;
+
+ assertVariableDeclarationTypes(
+ getTopLevelVariable(unit1, "x"), intType, intType);
+ assertVariableDeclarationTypes(
+ getFieldInClass(unit1, "A", "x"), intType, intType);
+
+ assertVariableDeclarationTypes(
+ getTopLevelVariable(unit2, "y"), intType, intType);
+ assertVariableDeclarationTypes(
+ getFieldInClass(unit2, "B", "y"), intType, intType);
+
+ List<Statement> statements =
+ getStatementsInTopLevelFunction(unit2, "test1");
+
+ assertAssignmentStatementTypes(statements[1], intType, intType);
+ assertAssignmentStatementTypes(statements[2], intType, intType);
+ assertAssignmentStatementTypes(statements[3], intType, intType);
+ assertAssignmentStatementTypes(statements[4], intType, intType);
+ }
+
+ // Test inference interactions between local variables and top level
+ // variables
+ void test_perform_inference_cross_unit_non_cyclic() {
+ AnalysisTarget firstSource = newSource(
+ '/a.dart',
+ '''
+ var x = 2;
+ class A { static var x = 2; }
+''');
+ AnalysisTarget secondSource = newSource(
+ '/test.dart',
+ '''
+ import 'a.dart';
+ var y = x;
+ class B { static var y = A.x; }
+
+ test1() {
+ x = /*severe:StaticTypeError*/"hi";
+ y = /*severe:StaticTypeError*/"hi";
+ A.x = /*severe:StaticTypeError*/"hi";
+ B.y = /*severe:StaticTypeError*/"hi";
+ }
+''');
+ computeResult(
+ new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT8);
+ CompilationUnit unit1 = outputs[RESOLVED_UNIT8];
+ computeResult(
+ new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT8);
+ CompilationUnit unit2 = outputs[RESOLVED_UNIT8];
+
+ InterfaceType intType = context.typeProvider.intType;
+ InterfaceType stringType = context.typeProvider.stringType;
+
+ assertVariableDeclarationTypes(
+ getTopLevelVariable(unit1, "x"), intType, intType);
+ assertVariableDeclarationTypes(
+ getFieldInClass(unit1, "A", "x"), intType, intType);
+
+ assertVariableDeclarationTypes(
+ getTopLevelVariable(unit2, "y"), intType, intType);
+ assertVariableDeclarationTypes(
+ getFieldInClass(unit2, "B", "y"), intType, intType);
+
+ List<Statement> statements =
+ getStatementsInTopLevelFunction(unit2, "test1");
+
+ assertAssignmentStatementTypes(statements[0], intType, stringType);
+ assertAssignmentStatementTypes(statements[1], intType, stringType);
+ }
+
+ // Test that inference does not propagate from null
+ void test_perform_inference_local_variables() {
+ AnalysisTarget source = newSource(
+ '/test.dart',
+ '''
+ test() {
+ int x = 3;
+ x = "hi";
+ var y = 3;
+ y = "hi";
+ }
+''');
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
+ CompilationUnit unit = outputs[RESOLVED_UNIT8];
+
+ InterfaceType intType = context.typeProvider.intType;
+ InterfaceType stringType = context.typeProvider.stringType;
+
+ List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
+
+ assertVariableDeclarationStatementTypes(statements[0], intType, intType);
+ assertAssignmentStatementTypes(statements[1], intType, stringType);
+ assertVariableDeclarationStatementTypes(statements[2], intType, intType);
+ assertAssignmentStatementTypes(statements[3], intType, stringType);
+ }
+
+ // Test inference across units (non-cyclic)
+ void test_perform_inference_local_variables_fields() {
+ AnalysisTarget source = newSource(
+ '/test.dart',
+ '''
+ class A {
+ int x = 0;
+
+ test1() {
+ var a = x;
+ a = "hi";
+ a = 3;
+ var b = y;
+ b = "hi";
+ b = 4;
+ var c = z;
+ c = "hi";
+ c = 4;
+ }
+
+ int y; // field def after use
+ final z = 42; // should infer `int`
+ }
+''');
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
+ CompilationUnit unit = outputs[RESOLVED_UNIT8];
+
+ InterfaceType intType = context.typeProvider.intType;
+ InterfaceType stringType = context.typeProvider.stringType;
+
+ List<Statement> statements = getStatementsInMethod(unit, "A", "test1");
+
+ assertVariableDeclarationStatementTypes(statements[0], intType, intType);
+ assertAssignmentStatementTypes(statements[1], intType, stringType);
+ assertAssignmentStatementTypes(statements[2], intType, intType);
+
+ assertVariableDeclarationStatementTypes(statements[3], intType, intType);
+ assertAssignmentStatementTypes(statements[4], intType, stringType);
+ assertAssignmentStatementTypes(statements[5], intType, intType);
+
+ assertVariableDeclarationStatementTypes(statements[6], intType, intType);
+ assertAssignmentStatementTypes(statements[7], intType, stringType);
+ assertAssignmentStatementTypes(statements[8], intType, intType);
+
+ assertVariableDeclarationTypes(
+ getFieldInClass(unit, "A", "x"), intType, intType);
+ assertVariableDeclarationTypes(
+ getFieldInClass(unit, "A", "z"), intType, intType);
+ }
+
+ // Test inference across units (cyclic)
+ void test_perform_inference_local_variables_topLevel() {
+ AnalysisTarget source = newSource(
+ '/test.dart',
+ '''
+ int x = 0;
+
+ test1() {
+ var a = x;
+ a = /*severe:StaticTypeError*/"hi";
+ a = 3;
+ var b = y;
+ b = /*severe:StaticTypeError*/"hi";
+ b = 4;
+ var c = z;
+ c = /*severe:StaticTypeError*/"hi";
+ c = 4;
+ }
+
+ int y = 0; // field def after use
+ final z = 42; // should infer `int`
+''');
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
+ CompilationUnit unit = outputs[RESOLVED_UNIT8];
+
+ InterfaceType intType = context.typeProvider.intType;
+ InterfaceType stringType = context.typeProvider.stringType;
+
+ List<Statement> statements = getStatementsInTopLevelFunction(unit, "test1");
+
+ assertVariableDeclarationStatementTypes(statements[0], intType, intType);
+ assertAssignmentStatementTypes(statements[1], intType, stringType);
+ assertAssignmentStatementTypes(statements[2], intType, intType);
+
+ assertVariableDeclarationStatementTypes(statements[3], intType, intType);
+ assertAssignmentStatementTypes(statements[4], intType, stringType);
+ assertAssignmentStatementTypes(statements[5], intType, intType);
+
+ assertVariableDeclarationStatementTypes(statements[6], intType, intType);
+ assertAssignmentStatementTypes(statements[7], intType, stringType);
+ assertAssignmentStatementTypes(statements[8], intType, intType);
+
+ assertVariableDeclarationTypes(
+ getTopLevelVariable(unit, "x"), intType, intType);
+ assertVariableDeclarationTypes(
+ getTopLevelVariable(unit, "y"), intType, intType);
+ assertVariableDeclarationTypes(
+ getTopLevelVariable(unit, "z"), intType, intType);
+ }
+
+ // Test inference of instance fields across units
+ // TODO(leafp): Fix this
+ // https://github.com/dart-lang/dev_compiler/issues/354
+ void test_perform_inference_null() {
+ AnalysisTarget source = newSource(
+ '/test.dart',
+ '''
+ var x = null;
+ var y = 3;
+ class A {
+ static var x = null;
+ static var y = 3;
+
+ var x2 = null;
+ var y2 = 3;
+ }
+
+ test() {
+ x = "hi";
+ y = /*severe:StaticTypeError*/"hi";
+ A.x = "hi";
+ A.y = /*severe:StaticTypeError*/"hi";
+ new A().x2 = "hi";
+ new A().y2 = /*severe:StaticTypeError*/"hi";
+ }
+''');
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
+ CompilationUnit unit = outputs[RESOLVED_UNIT8];
+
+ InterfaceType intType = context.typeProvider.intType;
+ InterfaceType stringType = context.typeProvider.stringType;
+ DartType bottomType = context.typeProvider.bottomType;
+ DartType dynamicType = context.typeProvider.dynamicType;
+
+ assertVariableDeclarationTypes(
+ getTopLevelVariable(unit, "x"), dynamicType, bottomType);
+ assertVariableDeclarationTypes(
+ getTopLevelVariable(unit, "y"), intType, intType);
+ assertVariableDeclarationTypes(
+ getFieldInClass(unit, "A", "x"), dynamicType, bottomType);
+ assertVariableDeclarationTypes(
+ getFieldInClass(unit, "A", "y"), intType, intType);
+ assertVariableDeclarationTypes(
+ getFieldInClass(unit, "A", "x2"), dynamicType, bottomType);
+ assertVariableDeclarationTypes(
+ getFieldInClass(unit, "A", "y2"), intType, intType);
+
+ List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
+
+ assertAssignmentStatementTypes(statements[0], dynamicType, stringType);
+ assertAssignmentStatementTypes(statements[1], intType, stringType);
+ assertAssignmentStatementTypes(statements[2], dynamicType, stringType);
+ assertAssignmentStatementTypes(statements[3], intType, stringType);
+ assertAssignmentStatementTypes(statements[4], dynamicType, stringType);
+ assertAssignmentStatementTypes(statements[5], intType, stringType);
+ }
+
+ // Test inference between static and instance fields
+ // TODO(leafp): Fix this
+ // https://github.com/dart-lang/dev_compiler/issues/354
+ void test_perform_local_explicit_disabled() {
+ AnalysisTarget source = newSource(
+ '/test.dart',
+ '''
+ test() {
+ int x = 3;
+ x = "hi";
+ }
+''');
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
+ CompilationUnit unit = outputs[RESOLVED_UNIT8];
+
+ InterfaceType intType = context.typeProvider.intType;
+ InterfaceType stringType = context.typeProvider.stringType;
+
+ List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
+ VariableDeclaration decl =
+ (statements[0] as VariableDeclarationStatement).variables.variables[0];
+ expect(decl.element.type, intType);
+ expect(decl.initializer.staticType, intType);
+
+ ExpressionStatement statement = statements[1];
+ AssignmentExpression assgn = statement.expression;
+ expect(assgn.leftHandSide.staticType, intType);
+ expect(assgn.rightHandSide.staticType, stringType);
+ }
+}
+
+@reflectiveTest
class VerifyUnitTaskTest extends _AbstractDartTaskTest {
test_perform_constantError() {
Source source = newSource(
@@ -3370,6 +3428,23 @@
<ErrorCode>[CompileTimeErrorCode.URI_DOES_NOT_EXIST]);
}
+ void test_perform_reresolution() {
+ enableStrongMode();
+ AnalysisTarget source = newSource(
+ '/test.dart',
+ '''
+const topLevel = 3;
+class C {
+ String field = topLevel;
+}
+''');
+ computeResult(new LibrarySpecificUnit(source, source), VERIFY_ERRORS);
+ // validate
+ _fillErrorListener(VERIFY_ERRORS);
+ errorListener.assertErrorsWithCodes(
+ <ErrorCode>[StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+ }
+
test_perform_verifyError() {
Source source = newSource(
'/test.dart',
@@ -3387,23 +3462,6 @@
errorListener.assertErrorsWithCodes(
<ErrorCode>[StaticTypeWarningCode.NON_BOOL_CONDITION]);
}
-
- void test_perform_reresolution() {
- enableStrongMode();
- AnalysisTarget source = newSource(
- '/test.dart',
- '''
-const topLevel = 3;
-class C {
- String field = topLevel;
-}
-''');
- computeResult(new LibrarySpecificUnit(source, source), VERIFY_ERRORS);
- // validate
- _fillErrorListener(VERIFY_ERRORS);
- errorListener.assertErrorsWithCodes(
- <ErrorCode>[StaticTypeWarningCode.INVALID_ASSIGNMENT]);
- }
}
class _AbstractDartTaskTest extends AbstractContextTest {
@@ -3540,6 +3598,23 @@
}
/**
+ * Return the declaration of the top-level function with the given
+ * [functionName] in the given compilation [unit].
+ */
+ FunctionDeclaration getTopLevelFunction(
+ CompilationUnit unit, String functionName) {
+ NodeList<CompilationUnitMember> unitMembers = unit.declarations;
+ for (CompilationUnitMember unitMember in unitMembers) {
+ if (unitMember is FunctionDeclaration) {
+ if (unitMember.name.name == functionName) {
+ return unitMember;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
* Return the declaration of the top-level variable with the given
* [variableName] in the given compilation [unit].
*/
@@ -3560,23 +3635,6 @@
return null;
}
- /**
- * Return the declaration of the top-level function with the given
- * [functionName] in the given compilation [unit].
- */
- FunctionDeclaration getTopLevelFunction(
- CompilationUnit unit, String functionName) {
- NodeList<CompilationUnitMember> unitMembers = unit.declarations;
- for (CompilationUnitMember unitMember in unitMembers) {
- if (unitMember is FunctionDeclaration) {
- if (unitMember.name.name == functionName) {
- return unitMember;
- }
- }
- }
- return null;
- }
-
void setUp() {
super.setUp();
emptySource = newSource('/test.dart');
diff --git a/pkg/analyzer/test/src/task/inputs_test.dart b/pkg/analyzer/test/src/task/inputs_test.dart
index 35e4660..3943a99 100644
--- a/pkg/analyzer/test/src/task/inputs_test.dart
+++ b/pkg/analyzer/test/src/task/inputs_test.dart
@@ -15,6 +15,8 @@
main() {
initializeTestEnvironment();
+ runReflectiveTests(ConstantTaskInputBuilderTest);
+ runReflectiveTests(ConstantTaskInputTest);
runReflectiveTests(ListTaskInputImplTest);
runReflectiveTests(ListToListTaskInputTest);
runReflectiveTests(ListToListTaskInputBuilderTest);
@@ -28,6 +30,96 @@
}
@reflectiveTest
+class ConstantTaskInputBuilderTest extends EngineTestCase {
+ static final int value = 7;
+ static final ConstantTaskInput<int> input = new ConstantTaskInput<int>(value);
+
+ ConstantTaskInputBuilder builder;
+
+ void setUp() {
+ builder = new ConstantTaskInputBuilder(input);
+ }
+
+ test_create() {
+ expect(builder, isNotNull);
+ expect(builder.input, input);
+ }
+
+ test_currentResult_afterOneMoveNext() {
+ builder.moveNext();
+ expect(builder.currentResult, null);
+ }
+
+ test_currentResult_beforeMoveNext() {
+ expect(builder.currentResult, null);
+ }
+
+ test_currentTarget_afterOneMoveNext() {
+ builder.moveNext();
+ expect(builder.currentTarget, null);
+ }
+
+ test_currentTarget_beforeMoveNext() {
+ expect(builder.currentTarget, null);
+ }
+
+ test_currentValue_afterOneMoveNext() {
+ builder.moveNext();
+ expect(() {
+ builder.currentValue = 'value';
+ }, throwsStateError);
+ }
+
+ test_currentValue_beforeMoveNext() {
+ expect(() {
+ builder.currentValue = 'value';
+ }, throwsStateError);
+ }
+
+ test_currentValueNotAvailable_afterOneMoveNext() {
+ builder.moveNext();
+ expect(() {
+ builder.currentValueNotAvailable();
+ }, throwsStateError);
+ }
+
+ test_currentValueNotAvailable_beforeMoveNext() {
+ expect(() {
+ builder.currentValueNotAvailable();
+ }, throwsStateError);
+ }
+
+ test_inputValue_afterOneMoveNext() {
+ builder.moveNext();
+ expect(builder.inputValue, value);
+ }
+
+ test_inputValue_beforeMoveNext() {
+ expect(builder.inputValue, value);
+ }
+
+ test_moveNext() {
+ expect(builder.moveNext(), false);
+ expect(builder.moveNext(), false);
+ }
+}
+
+@reflectiveTest
+class ConstantTaskInputTest extends EngineTestCase {
+ test_create() {
+ int value = 3;
+ ConstantTaskInput<int> input = new ConstantTaskInput<int>(value);
+ expect(input, isNotNull);
+ expect(input.value, value);
+ }
+
+ test_createBuilder() {
+ ConstantTaskInput<int> input = new ConstantTaskInput<int>(5);
+ expect(input.createBuilder(), new isInstanceOf<ConstantTaskInputBuilder>());
+ }
+}
+
+@reflectiveTest
class ListTaskInputImplTest extends EngineTestCase {
static final AnalysisTarget target = new TestSource();
static final result1 =
@@ -800,6 +892,21 @@
expect(builder.currentResult, result1);
}
+ test_currentResult_afterTwoMoveNext_withConstantInput() {
+ ConstantTaskInput<int> constantInput = new ConstantTaskInput<int>(11);
+ Map<String, TaskInput> inputDescriptors = {
+ 'one': input1,
+ 'constant': constantInput,
+ 'two': input2
+ };
+ TopLevelTaskInputBuilder builder =
+ new TopLevelTaskInputBuilder(inputDescriptors);
+ builder.moveNext();
+ builder.currentValue = 'value1';
+ builder.moveNext();
+ expect(builder.currentResult, result2);
+ }
+
test_currentResult_beforeMoveNext() {
Map<String, TaskInput> inputDescriptors = {};
TopLevelTaskInputBuilder builder =
@@ -835,6 +942,21 @@
expect(builder.currentTarget, target);
}
+ test_currentTarget_afterTwoMoveNext_withConstantInput() {
+ ConstantTaskInput<int> constantInput = new ConstantTaskInput<int>(11);
+ Map<String, TaskInput> inputDescriptors = {
+ 'one': input1,
+ 'constant': constantInput,
+ 'two': input2
+ };
+ TopLevelTaskInputBuilder builder =
+ new TopLevelTaskInputBuilder(inputDescriptors);
+ builder.moveNext();
+ builder.currentValue = 'value1';
+ builder.moveNext();
+ expect(builder.currentTarget, target);
+ }
+
test_currentTarget_beforeMoveNext() {
Map<String, TaskInput> inputDescriptors = {};
TopLevelTaskInputBuilder builder =
diff --git a/pkg/analyzer/test/src/task/strong_mode_test.dart b/pkg/analyzer/test/src/task/strong_mode_test.dart
index fbbbae6..ff87d92 100644
--- a/pkg/analyzer/test/src/task/strong_mode_test.dart
+++ b/pkg/analyzer/test/src/task/strong_mode_test.dart
@@ -252,9 +252,6 @@
final $fieldName = 0;
}
''');
- ClassElement classA = unit.getType('A');
- FieldElement fieldA = classA.getField(fieldName);
- PropertyAccessorElement getterA = classA.getGetter(fieldName);
ClassElement classB = unit.getType('B');
FieldElement fieldB = classB.getField(fieldName);
PropertyAccessorElement getterB = classB.getGetter(fieldName);
@@ -564,7 +561,6 @@
}
''');
ClassElement classA = unit.getType('A');
- FieldElement fieldA = classA.getField(getterName);
PropertyAccessorElement setterA = classA.getSetter(getterName);
ClassElement classB = unit.getType('B');
FieldElement fieldB = classB.getField(getterName);
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart
index 7f5ce65..e515631 100644
--- a/pkg/compiler/lib/src/apiimpl.dart
+++ b/pkg/compiler/lib/src/apiimpl.dart
@@ -24,7 +24,8 @@
GenericTask;
import 'compiler.dart' as leg;
import 'diagnostics/diagnostic_listener.dart' show
- DiagnosticMessage;
+ DiagnosticMessage,
+ DiagnosticOptions;
import 'diagnostics/messages.dart';
import 'diagnostics/source_span.dart' show
SourceSpan;
@@ -90,8 +91,6 @@
analyzeSignaturesOnly:
hasOption(options, Flags.analyzeSignaturesOnly),
strips: extractCsvOption(options, '--force-strip='),
- enableConcreteTypeInference:
- hasOption(options, Flags.enableConcreteTypeInference),
disableTypeInferenceFlag:
hasOption(options, Flags.disableTypeInference),
preserveComments: hasOption(options, Flags.preserveComments),
@@ -99,22 +98,24 @@
verbose: hasOption(options, Flags.verbose),
sourceMapUri: extractUriOption(options, '--source-map='),
outputUri: extractUriOption(options, '--out='),
- terseDiagnostics: hasOption(options, Flags.terse),
deferredMapUri: extractUriOption(options, '--deferred-map='),
dumpInfo: hasOption(options, Flags.dumpInfo),
buildId: extractStringOption(
options, '--build-id=',
"build number could not be determined"),
- showPackageWarnings:
- hasOption(options, Flags.showPackageWarnings),
useContentSecurityPolicy:
hasOption(options, Flags.useContentSecurityPolicy),
useStartupEmitter: hasOption(options, Flags.fastStartup),
hasIncrementalSupport:
forceIncrementalSupport ||
hasOption(options, Flags.incrementalSupport),
- suppressWarnings: hasOption(options, Flags.suppressWarnings),
- fatalWarnings: hasOption(options, Flags.fatalWarnings),
+ diagnosticOptions: new DiagnosticOptions(
+ suppressWarnings: hasOption(options, Flags.suppressWarnings),
+ fatalWarnings: hasOption(options, Flags.fatalWarnings),
+ suppressHints: hasOption(options, Flags.suppressHints),
+ terseDiagnostics: hasOption(options, Flags.terse),
+ showPackageWarnings:
+ hasOption(options, Flags.showPackageWarnings)),
enableExperimentalMirrors:
hasOption(options, Flags.enableExperimentalMirrors),
enableAssertMessage:
@@ -237,7 +238,7 @@
Future<Script> readScript(Spannable node, Uri readableUri) {
if (!readableUri.isAbsolute) {
if (node == null) node = NO_LOCATION_SPANNABLE;
- internalError(node,
+ reporter.internalError(node,
'Relative uri $readableUri provided to readScript(Uri).');
}
@@ -247,13 +248,13 @@
elements.Element element = currentElement;
void reportReadError(exception) {
if (element == null || node == null) {
- reportErrorMessage(
+ reporter.reportErrorMessage(
new SourceSpan(readableUri, 0, 0),
MessageKind.READ_SELF_ERROR,
{'uri': readableUri, 'exception': exception});
} else {
- withCurrentElement(element, () {
- reportErrorMessage(
+ reporter.withCurrentElement(element, () {
+ reporter.reportErrorMessage(
node,
MessageKind.READ_SCRIPT_ERROR,
{'uri': readableUri, 'exception': exception});
@@ -265,8 +266,8 @@
if (resourceUri == null) return synthesizeScript(node, readableUri);
if (resourceUri.scheme == 'dart-ext') {
if (!allowNativeExtensions) {
- withCurrentElement(element, () {
- reportErrorMessage(
+ reporter.withCurrentElement(element, () {
+ reporter.reportErrorMessage(
node, MessageKind.DART_EXT_NOT_SUPPORTED);
});
}
@@ -337,13 +338,13 @@
}
if (!allowInternalLibraryAccess) {
if (importingLibrary != null) {
- reportErrorMessage(
+ reporter.reportErrorMessage(
spannable,
MessageKind.INTERNAL_LIBRARY_FROM,
{'resolvedUri': resolvedUri,
'importingUri': importingLibrary.canonicalUri});
} else {
- reportErrorMessage(
+ reporter.reportErrorMessage(
spannable,
MessageKind.INTERNAL_LIBRARY,
{'resolvedUri': resolvedUri});
@@ -352,12 +353,12 @@
}
if (path == null) {
if (libraryInfo == null) {
- reportErrorMessage(
+ reporter.reportErrorMessage(
spannable,
MessageKind.LIBRARY_NOT_FOUND,
{'resolvedUri': resolvedUri});
} else {
- reportErrorMessage(
+ reporter.reportErrorMessage(
spannable,
MessageKind.LIBRARY_NOT_SUPPORTED,
{'resolvedUri': resolvedUri});
@@ -385,7 +386,7 @@
try {
checkValidPackageUri(uri);
} on ArgumentError catch (e) {
- reportErrorMessage(
+ reporter.reportErrorMessage(
node,
MessageKind.INVALID_PACKAGE_URI,
{'uri': uri, 'exception': e.message});
@@ -393,7 +394,7 @@
}
return packages.resolve(uri,
notFound: (Uri notFound) {
- reportErrorMessage(
+ reporter.reportErrorMessage(
node,
MessageKind.LIBRARY_NOT_FOUND,
{'resolvedUri': uri});
@@ -431,7 +432,7 @@
packages =
new MapPackages(pkgs.parse(packageConfigContents, packageConfig));
}).catchError((error) {
- reportErrorMessage(
+ reporter.reportErrorMessage(
NO_LOCATION_SPANNABLE,
MessageKind.INVALID_PACKAGE_CONFIG,
{'uri': packageConfig, 'exception': error});
@@ -479,9 +480,11 @@
void reportDiagnostic(DiagnosticMessage message,
List<DiagnosticMessage> infos,
api.Diagnostic kind) {
+ // TODO(johnniwinther): Move this to the [DiagnosticReporter]?
if (kind == api.Diagnostic.ERROR ||
kind == api.Diagnostic.CRASH ||
- (fatalWarnings && kind == api.Diagnostic.WARNING)) {
+ (reporter.options.fatalWarnings &&
+ kind == api.Diagnostic.WARNING)) {
compilationFailed = true;
}
_reportDiagnosticMessage(message, kind);
@@ -541,11 +544,6 @@
}
}
- void diagnoseCrashInUserCode(String message, exception, stackTrace) {
- hasCrashed = true;
- print('$message: ${tryToString(exception)}');
- print(tryToString(stackTrace));
- }
fromEnvironment(String name) => environment[name];
diff --git a/pkg/compiler/lib/src/closure.dart b/pkg/compiler/lib/src/closure.dart
index 0f8f218..b0fff43 100644
--- a/pkg/compiler/lib/src/closure.dart
+++ b/pkg/compiler/lib/src/closure.dart
@@ -6,6 +6,9 @@
import 'common/names.dart' show
Identifiers;
+import 'common/resolution.dart' show
+ Parsing,
+ Resolution;
import 'common/tasks.dart' show
CompilerTask;
import 'compiler.dart' show
@@ -75,7 +78,7 @@
return measure(() {
ClosureClassMap nestedClosureData = closureMappingCache[node];
if (nestedClosureData == null) {
- compiler.internalError(node, "No closure cache.");
+ reporter.internalError(node, "No closure cache.");
}
return nestedClosureData;
});
@@ -140,7 +143,7 @@
bool get isInstanceMember => true;
bool get isAssignable => false;
- DartType computeType(Compiler compiler) => type;
+ DartType computeType(Resolution resolution) => type;
DartType get type {
if (local is LocalElement) {
@@ -197,7 +200,7 @@
ClassElement superclass = methodElement.isInstanceMember
? backend.boundClosureClass
: backend.closureClass;
- superclass.ensureResolved(compiler);
+ superclass.ensureResolved(compiler.resolution);
supertype = superclass.thisType;
interfaces = const Link<DartType>();
thisType = rawType = new InterfaceType(this);
@@ -208,7 +211,7 @@
Iterable<ClosureFieldElement> get closureFields => _closureFields;
- void addField(ClosureFieldElement field, DiagnosticListener listener) {
+ void addField(ClosureFieldElement field, DiagnosticReporter listener) {
_closureFields.add(field);
addMember(field, listener);
}
@@ -219,7 +222,7 @@
Token get position => node.getBeginToken();
- Node parseNode(DiagnosticListener listener) => node;
+ Node parseNode(Parsing parsing) => node;
// A [ClosureClassElement] is nested inside a function or initializer in terms
// of [enclosingElement], but still has to be treated as a top-level
@@ -252,7 +255,7 @@
: this.box = box,
super(name, ElementKind.FIELD, box.executableContext);
- DartType computeType(Compiler compiler) => type;
+ DartType computeType(Resolution resolution) => type;
DartType get type => variableElement.type;
@@ -315,7 +318,7 @@
: expression = other,
super(name, other.kind, other.modifiers, enclosing) {
asyncMarker = other.asyncMarker;
- functionSignatureCache = other.functionSignature;
+ functionSignature = other.functionSignature;
}
/// Use [closureClass] instead.
@@ -332,7 +335,7 @@
FunctionExpression get node => expression.node;
- FunctionExpression parseNode(DiagnosticListener listener) => node;
+ FunctionExpression parseNode(Parsing parsing) => node;
ResolvedAst get resolvedAst {
return new ResolvedAst(this, node, treeElements);
@@ -507,6 +510,8 @@
this.elements,
this.closureMappingCache);
+ DiagnosticReporter get reporter => compiler.reporter;
+
/// Generate a unique name for the [id]th closure field, with proposed name
/// [name].
///
@@ -539,7 +544,7 @@
void addCapturedVariable(Node node, Local variable) {
if (_capturedVariableMapping[variable] != null) {
- compiler.internalError(node, 'In closure analyzer.');
+ reporter.internalError(node, 'In closure analyzer.');
}
_capturedVariableMapping[variable] = null;
}
@@ -609,7 +614,7 @@
void addClosureField(Local local, String name) {
ClosureFieldElement closureField =
new ClosureFieldElement(name, local, closureClass);
- closureClass.addField(closureField, compiler);
+ closureClass.addField(closureField, reporter);
data.freeVariableMap[local] = closureField;
}
@@ -999,7 +1004,7 @@
globalizedElement, callElement, element);
MemberElement enclosing = element.memberContext;
enclosing.nestedClosures.add(callElement);
- globalizedElement.addMember(callElement, compiler);
+ globalizedElement.addMember(callElement, reporter);
globalizedElement.computeAllClassMembers(compiler);
// The nested function's 'this' is the same as the one for the outer
// function. It could be [null] if we are inside a static method.
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 204bb2a..668cb28 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -19,8 +19,6 @@
static const String dumpInfo = '--dump-info';
static const String enableAssertMessage = '--assert-message';
static const String enableCheckedMode = '--enable-checked-mode';
- static const String enableConcreteTypeInference =
- '--enable-concrete-type-inference';
static const String enableDiagnosticColors = '--enable-diagnostic-colors';
static const String enableExperimentalMirrors =
'--enable-experimental-mirrors';
diff --git a/pkg/compiler/lib/src/common/backend_api.dart b/pkg/compiler/lib/src/common/backend_api.dart
index 487f01d..948fdba 100644
--- a/pkg/compiler/lib/src/common/backend_api.dart
+++ b/pkg/compiler/lib/src/common/backend_api.dart
@@ -11,6 +11,8 @@
import '../compile_time_constants.dart' show
BackendConstantEnvironment,
ConstantCompilerTask;
+import '../constants/expressions.dart' show
+ ConstantExpression;
import '../constants/constant_system.dart' show
ConstantSystem;
import '../constants/values.dart' show
@@ -48,6 +50,11 @@
checkNativeAnnotation;
import '../resolution/tree_elements.dart' show
TreeElements;
+import '../tree/tree.dart' show
+ Node,
+ Send;
+import '../universe/call_structure.dart' show
+ CallStructure;
import 'codegen.dart' show
CodegenWorkItem;
@@ -220,7 +227,7 @@
/// Call this method to enable support for isolates.
void enableIsolateSupport(Enqueuer enqueuer) {}
- void registerRequiredType(DartType type, Element enclosingElement) {}
+ void registerRequiredType(DartType type) {}
void registerConstSymbol(String name, Registry registry) {}
void registerNewSymbol(Registry registry) {}
@@ -375,5 +382,23 @@
void registerAsyncMarker(FunctionElement element,
Enqueuer enqueuer,
Registry registry) {}
+
+ /// Called when resolving a call to a foreign function.
+ void registerForeignCall(Send node,
+ Element element,
+ CallStructure callStructure,
+ ForeignResolver resolver) {}
}
+/// Interface for resolving calls to foreign functions.
+abstract class ForeignResolver {
+ /// Returns the constant expression of [node], or `null` if [node] is not
+ /// a constant expression.
+ ConstantExpression getConstant(Node node);
+
+ /// Registers [type] as instantiated.
+ void registerInstantiatedType(InterfaceType type);
+
+ /// Resolves [typeName] to a type in the context of [node].
+ DartType resolveTypeFromString(Node node, String typeName);
+}
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index e220aab..e5554c9 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -191,7 +191,7 @@
// generation could spuriously be adding dependencies on things we know we
// don't need.
assert(invariant(element,
- compiler.enqueuer.resolution.hasBeenResolved(element),
+ compiler.enqueuer.resolution.hasBeenProcessed(element),
message: "$element has not been resolved."));
assert(invariant(element, element.resolvedAst.elements != null,
message: 'Resolution tree is null for $element in codegen work item'));
diff --git a/pkg/compiler/lib/src/common/resolution.dart b/pkg/compiler/lib/src/common/resolution.dart
index 86a21bd..474b10e 100644
--- a/pkg/compiler/lib/src/common/resolution.dart
+++ b/pkg/compiler/lib/src/common/resolution.dart
@@ -1,3 +1,4 @@
+
// Copyright (c) 2012, 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.
@@ -6,18 +7,36 @@
import '../compiler.dart' show
Compiler;
+import '../core_types.dart' show
+ CoreTypes;
import '../dart_types.dart' show
- DartType;
+ DartType,
+ InterfaceType;
+import '../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import '../elements/elements.dart' show
AstElement,
+ ClassElement,
+ Element,
ErroneousElement,
+ FunctionElement,
+ FunctionSignature,
+ LocalFunctionElement,
+ MetadataAnnotation,
+ MethodElement,
+ TypedefElement,
TypeVariableElement;
import '../enqueue.dart' show
ResolutionEnqueuer,
WorldImpact;
import '../tree/tree.dart' show
AsyncForIn,
- Send;
+ Send,
+ TypeAnnotation;
+import '../universe/universe.dart' show
+ UniverseSelector;
+import '../util/util.dart' show
+ Setlet;
import 'registry.dart' show
Registry;
import 'work.dart' show
@@ -34,6 +53,7 @@
WorldImpact run(Compiler compiler, ResolutionEnqueuer world) {
WorldImpact impact = compiler.analyze(this, world);
+ impact = compiler.backend.resolutionCallbacks.transformImpact(impact);
_isAnalyzed = true;
return impact;
}
@@ -41,8 +61,13 @@
bool get isAnalyzed => _isAnalyzed;
}
+// TODO(johnniwinther): Rename this to something like `BackendResolutionApi`
+// and clean up the interface.
/// Backend callbacks function specific to the resolution phase.
class ResolutionCallbacks {
+ ///
+ WorldImpact transformImpact(ResolutionWorldImpact worldImpact) => worldImpact;
+
/// Register that an assert has been seen.
void onAssert(bool hasMessage, Registry registry) {}
@@ -120,3 +145,279 @@
/// Called when resolving a prefix or postfix expression.
void onIncDecOperation(Registry registry) {}
}
+
+class ResolutionWorldImpact extends WorldImpact {
+ const ResolutionWorldImpact();
+
+ // TODO(johnniwinther): Remove this.
+ void registerDependency(Element element) {}
+
+ Iterable<Feature> get features => const <Feature>[];
+ Iterable<DartType> get requiredTypes => const <DartType>[];
+ Iterable<MapLiteralUse> get mapLiterals => const <MapLiteralUse>[];
+ Iterable<ListLiteralUse> get listLiterals => const <ListLiteralUse>[];
+ Iterable<DartType> get typeLiterals => const <DartType>[];
+ Iterable<String> get constSymbolNames => const <String>[];
+}
+
+/// A language feature seen during resolution.
+// TODO(johnniwinther): Should mirror usage be part of this?
+enum Feature {
+ /// Invocation of a generative construction on an abstract class.
+ ABSTRACT_CLASS_INSTANTIATION,
+ /// An assert statement with no message.
+ ASSERT,
+ /// An assert statement with a message.
+ ASSERT_WITH_MESSAGE,
+ /// A method with an `async` body modifier.
+ ASYNC,
+ /// An asynchronous for in statement like `await for (var e in i) {}`.
+ ASYNC_FOR_IN,
+ /// A method with an `async*` body modifier.
+ ASYNC_STAR,
+ /// A catch statement.
+ CATCH_STATEMENT,
+ /// A compile time error.
+ COMPILE_TIME_ERROR,
+ /// A fall through in a switch case.
+ FALL_THROUGH_ERROR,
+ /// A ++/-- operation.
+ INC_DEC_OPERATION,
+ /// A field whose initialization is not a constant.
+ LAZY_FIELD,
+ /// A call to `new Symbol`.
+ NEW_SYMBOL,
+ /// A catch clause with a variable for the stack trace.
+ STACK_TRACE_IN_CATCH,
+ /// String interpolation.
+ STRING_INTERPOLATION,
+ /// An implicit call to `super.noSuchMethod`, like calling an unresolved
+ /// super method.
+ SUPER_NO_SUCH_METHOD,
+ /// A redirection to the `Symbol` constructor.
+ SYMBOL_CONSTRUCTOR,
+ /// An synchronous for in statement, like `for (var e in i) {}`.
+ SYNC_FOR_IN,
+ /// A method with a `sync*` body modifier.
+ SYNC_STAR,
+ /// A throw expression.
+ THROW_EXPRESSION,
+ /// An implicit throw of a `NoSuchMethodError`, like calling an unresolved
+ /// static method.
+ THROW_NO_SUCH_METHOD,
+ /// An implicit throw of a runtime error, like
+ THROW_RUNTIME_ERROR,
+ /// The need for a type variable bound check, like instantiation of a generic
+ /// type whose type variable have non-trivial bounds.
+ TYPE_VARIABLE_BOUNDS_CHECK,
+}
+
+/// A use of a map literal seen during resolution.
+class MapLiteralUse {
+ final InterfaceType type;
+ final bool isConstant;
+ final bool isEmpty;
+
+ MapLiteralUse(this.type, {this.isConstant: false, this.isEmpty: false});
+
+ int get hashCode {
+ return
+ type.hashCode * 13 +
+ isConstant.hashCode * 17 +
+ isEmpty.hashCode * 19;
+ }
+
+ bool operator ==(other) {
+ if (identical(this, other)) return true;
+ if (other is! MapLiteralUse) return false;
+ return
+ type == other.type &&
+ isConstant == other.isConstant &&
+ isEmpty == other.isEmpty;
+ }
+}
+
+/// A use of a list literal seen during resolution.
+class ListLiteralUse {
+ final InterfaceType type;
+ final bool isConstant;
+ final bool isEmpty;
+
+ ListLiteralUse(this.type, {this.isConstant: false, this.isEmpty: false});
+
+ int get hashCode {
+ return
+ type.hashCode * 13 +
+ isConstant.hashCode * 17 +
+ isEmpty.hashCode * 19;
+ }
+
+ bool operator ==(other) {
+ if (identical(this, other)) return true;
+ if (other is! ListLiteralUse) return false;
+ return
+ type == other.type &&
+ isConstant == other.isConstant &&
+ isEmpty == other.isEmpty;
+ }
+}
+
+/// Mutable implementation of [WorldImpact] used to transform
+/// [ResolutionWorldImpact] to [WorldImpact].
+// TODO(johnniwinther): Remove [Registry] when dependency is tracked directly
+// on [WorldImpact].
+class TransformedWorldImpact implements WorldImpact, Registry {
+ final ResolutionWorldImpact worldImpact;
+
+ Setlet<Element> _staticUses;
+ Setlet<InterfaceType> _instantiatedTypes;
+ Setlet<UniverseSelector> _dynamicGetters;
+ Setlet<UniverseSelector> _dynamicInvocations;
+ Setlet<UniverseSelector> _dynamicSetters;
+
+ TransformedWorldImpact(this.worldImpact);
+
+ @override
+ Iterable<DartType> get asCasts => worldImpact.asCasts;
+
+ @override
+ Iterable<DartType> get checkedModeChecks => worldImpact.checkedModeChecks;
+
+ @override
+ Iterable<MethodElement> get closurizedFunctions {
+ return worldImpact.closurizedFunctions;
+ }
+
+ @override
+ Iterable<UniverseSelector> get dynamicGetters {
+ return _dynamicGetters != null
+ ? _dynamicGetters : worldImpact.dynamicGetters;
+ }
+
+ @override
+ Iterable<UniverseSelector> get dynamicInvocations {
+ return _dynamicInvocations != null
+ ? _dynamicInvocations : worldImpact.dynamicInvocations;
+ }
+
+ @override
+ Iterable<UniverseSelector> get dynamicSetters {
+ return _dynamicSetters != null
+ ? _dynamicSetters : worldImpact.dynamicSetters;
+ }
+
+ @override
+ Iterable<DartType> get isChecks => worldImpact.isChecks;
+
+ @override
+ Iterable<Element> get staticUses {
+ if (_staticUses == null) {
+ return worldImpact.staticUses;
+ }
+ return _staticUses;
+ }
+
+ @override
+ bool get isForResolution => true;
+
+ _unsupported(String message) => throw new UnsupportedError(message);
+
+ @override
+ Iterable<Element> get otherDependencies => _unsupported('otherDependencies');
+
+ // TODO(johnniwinther): Remove this.
+ @override
+ void registerAssert(bool hasMessage) => _unsupported('registerAssert');
+
+ @override
+ void registerDependency(Element element) {
+ worldImpact.registerDependency(element);
+ }
+
+ @override
+ void registerDynamicGetter(UniverseSelector selector) {
+ if (_dynamicGetters == null) {
+ _dynamicGetters = new Setlet<UniverseSelector>();
+ _dynamicGetters.addAll(worldImpact.dynamicGetters);
+ }
+ _dynamicGetters.add(selector);
+ }
+
+ @override
+ void registerDynamicInvocation(UniverseSelector selector) {
+ if (_dynamicInvocations == null) {
+ _dynamicInvocations = new Setlet<UniverseSelector>();
+ _dynamicInvocations.addAll(worldImpact.dynamicInvocations);
+ }
+ _dynamicInvocations.add(selector);
+ }
+
+ @override
+ void registerDynamicSetter(UniverseSelector selector) {
+ if (_dynamicSetters == null) {
+ _dynamicSetters = new Setlet<UniverseSelector>();
+ _dynamicSetters.addAll(worldImpact.dynamicSetters);
+ }
+ _dynamicSetters.add(selector);
+ }
+
+ @override
+ void registerGetOfStaticFunction(FunctionElement element) {
+ _unsupported('registerGetOfStaticFunction($element)');
+ }
+
+ @override
+ void registerInstantiation(InterfaceType type) {
+ // TODO(johnniwinther): Remove this when dependency tracking is done on
+ // the world impact itself.
+ registerDependency(type.element);
+ if (_instantiatedTypes == null) {
+ _instantiatedTypes = new Setlet<InterfaceType>();
+ }
+ _instantiatedTypes.add(type);
+ }
+
+ @override
+ Iterable<InterfaceType> get instantiatedTypes {
+ return _instantiatedTypes != null
+ ? _instantiatedTypes : const <InterfaceType>[];
+ }
+
+ @override
+ void registerStaticInvocation(Element element) {
+ // TODO(johnniwinther): Remove this when dependency tracking is done on
+ // the world impact itself.
+ registerDependency(element);
+ if (_staticUses == null) {
+ _staticUses = new Setlet<Element>();
+ }
+ _staticUses.add(element);
+ }
+
+ @override
+ Iterable<LocalFunctionElement> get closures => worldImpact.closures;
+}
+
+// TODO(johnniwinther): Rename to `Resolver` or `ResolverContext`.
+abstract class Resolution {
+ Parsing get parsing;
+ DiagnosticReporter get reporter;
+ CoreTypes get coreTypes;
+
+ void resolveTypedef(TypedefElement typdef);
+ void resolveClass(ClassElement cls);
+ void registerClass(ClassElement cls);
+ void resolveMetadataAnnotation(MetadataAnnotation metadataAnnotation);
+ FunctionSignature resolveSignature(FunctionElement function);
+ DartType resolveTypeAnnotation(Element element, TypeAnnotation node);
+
+ bool hasBeenResolved(Element element);
+ ResolutionWorldImpact analyzeElement(Element element);
+}
+
+// TODO(johnniwinther): Rename to `Parser` or `ParsingContext`.
+abstract class Parsing {
+ DiagnosticReporter get reporter;
+ void parsePatchClass(ClassElement cls);
+ measure(f());
+}
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/common/tasks.dart b/pkg/compiler/lib/src/common/tasks.dart
index 32966df..56253db 100644
--- a/pkg/compiler/lib/src/common/tasks.dart
+++ b/pkg/compiler/lib/src/common/tasks.dart
@@ -8,6 +8,8 @@
UserTag;
import '../compiler.dart' show
Compiler;
+import '../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import '../elements/elements.dart' show
Element;
@@ -30,6 +32,8 @@
: this.compiler = compiler,
watch = (compiler.verbose) ? new Stopwatch() : null;
+ DiagnosticReporter get reporter => compiler.reporter;
+
String get name => "Unknown task '${this.runtimeType}'";
int get timing {
@@ -66,7 +70,7 @@
}
measureElement(Element element, action()) {
- compiler.withCurrentElement(element, () => measure(action));
+ reporter.withCurrentElement(element, () => measure(action));
}
/// Measure the time spent in [action] (if in verbose mode) and accumulate it
diff --git a/pkg/compiler/lib/src/compile_time_constants.dart b/pkg/compiler/lib/src/compile_time_constants.dart
index dba9976..59166a0 100644
--- a/pkg/compiler/lib/src/compile_time_constants.dart
+++ b/pkg/compiler/lib/src/compile_time_constants.dart
@@ -4,6 +4,8 @@
library dart2js.compile_time_constant_evaluator;
+import 'common/resolution.dart' show
+ Resolution;
import 'common/tasks.dart' show
CompilerTask;
import 'compiler.dart' show
@@ -14,6 +16,8 @@
import 'constants/expressions.dart';
import 'constants/values.dart';
import 'dart_types.dart';
+import 'diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import 'diagnostics/invariant.dart' show
invariant;
import 'diagnostics/messages.dart' show
@@ -161,6 +165,8 @@
ConstantCompilerBase(this.compiler, this.constantSystem);
+ DiagnosticReporter get reporter => compiler.reporter;
+
@override
ConstantValue getConstantValueForVariable(VariableElement element) {
return getConstantValue(initialVariableValues[element.declaration]);
@@ -198,7 +204,7 @@
return result;
}
AstElement currentElement = element.analyzableElement;
- return compiler.withCurrentElement(currentElement, () {
+ return reporter.withCurrentElement(currentElement, () {
// TODO(johnniwinther): Avoid this eager analysis.
_analyzeElementEagerly(compiler, currentElement);
@@ -221,7 +227,7 @@
Node node = element.node;
if (pendingVariables.contains(element)) {
if (isConst) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS);
ConstantExpression expression = new ErroneousConstantExpression();
constantValueMap[expression] = constantSystem.createNull();
@@ -249,7 +255,7 @@
if (elementType.isMalformed && !value.isNull) {
if (isConst) {
ErroneousElement element = elementType.element;
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, element.messageKind, element.messageArguments);
} else {
// We need to throw an exception at runtime.
@@ -260,7 +266,7 @@
if (!constantSystem.isSubtype(
compiler.types, constantType, elementType)) {
if (isConst) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node,
MessageKind.NOT_ASSIGNABLE,
{'fromType': constantType,
@@ -366,6 +372,9 @@
: this.isEvaluatingConstant = isConst;
ConstantSystem get constantSystem => handler.constantSystem;
+ Resolution get resolution => compiler.resolution;
+
+ DiagnosticReporter get reporter => compiler.reporter;
AstConstant evaluate(Node node) {
// TODO(johnniwinther): should there be a visitErrorNode?
@@ -448,7 +457,7 @@
if (!map.containsKey(key.value)) {
keyValues.add(key.value);
} else {
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY);
}
keyExpressions.add(key.expression);
@@ -573,7 +582,7 @@
AstConstant result;
if (Elements.isStaticOrTopLevelFunction(element)) {
FunctionElementX function = element;
- function.computeType(compiler);
+ function.computeType(resolution);
result = new AstConstant(context, send,
new FunctionConstantExpression(function),
new FunctionConstantValue(function));
@@ -623,7 +632,7 @@
}
if (isDeferredUse(send)) {
if (isEvaluatingConstant) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
send, MessageKind.DEFERRED_COMPILE_TIME_CONSTANT);
}
PrefixElement prefix =
@@ -660,7 +669,7 @@
UnaryOperator operator = UnaryOperator.parse(node.source);
UnaryOperation operation = constantSystem.lookupUnary(operator);
if (operation == null) {
- compiler.internalError(send.selector, "Unexpected operator.");
+ reporter.internalError(send.selector, "Unexpected operator.");
}
ConstantValue folded = operation.fold(receiverConstant.value);
if (folded == null) {
@@ -723,7 +732,7 @@
} else if (!condition.value.isBool) {
DartType conditionType = condition.value.getType(compiler.coreTypes);
if (isEvaluatingConstant) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node.condition,
MessageKind.NOT_ASSIGNABLE,
{'fromType': conditionType,
@@ -766,13 +775,13 @@
return new AstConstant.fromDefaultValue(
element, constant, handler.getConstantValue(constant));
}
- target.computeType(compiler);
+ target.computeType(resolution);
FunctionSignature signature = target.functionSignature;
if (!callStructure.signatureApplies(signature)) {
String name = Elements.constructorNameForDiagnostics(
target.enclosingClass.name, target.name);
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS,
{'constructorName': name});
@@ -876,14 +885,14 @@
ConstantValue defaultValue = normalizedArguments[1].value;
if (firstArgument.isNull) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
normalizedArguments[0].node, MessageKind.NULL_NOT_ALLOWED);
return null;
}
if (!firstArgument.isString) {
DartType type = defaultValue.getType(compiler.coreTypes);
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
normalizedArguments[0].node,
MessageKind.NOT_ASSIGNABLE,
{'fromType': type,
@@ -894,7 +903,7 @@
if (constructor == compiler.intEnvironment &&
!(defaultValue.isNull || defaultValue.isInt)) {
DartType type = defaultValue.getType(compiler.coreTypes);
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
normalizedArguments[1].node,
MessageKind.NOT_ASSIGNABLE,
{'fromType': type,
@@ -905,7 +914,7 @@
if (constructor == compiler.boolEnvironment &&
!(defaultValue.isNull || defaultValue.isBool)) {
DartType type = defaultValue.getType(compiler.coreTypes);
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
normalizedArguments[1].node,
MessageKind.NOT_ASSIGNABLE,
{'fromType': type,
@@ -916,7 +925,7 @@
if (constructor == compiler.stringEnvironment &&
!(defaultValue.isNull || defaultValue.isString)) {
DartType type = defaultValue.getType(compiler.coreTypes);
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
normalizedArguments[1].node,
MessageKind.NOT_ASSIGNABLE,
{'fromType': type,
@@ -1010,7 +1019,7 @@
AstConstant signalNotCompileTimeConstant(Node node,
{MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) {
if (isEvaluatingConstant) {
- compiler.reportErrorMessage(node, message);
+ reporter.reportErrorMessage(node, message);
return new AstConstant(context, node, new ErroneousConstantExpression(),
new NullConstantValue());
@@ -1050,7 +1059,7 @@
if (Elements.isLocal(element)) {
AstConstant constant = definitions[element];
if (constant == null) {
- compiler.internalError(send, "Local variable without value.");
+ reporter.internalError(send, "Local variable without value.");
}
return constant;
}
@@ -1063,8 +1072,8 @@
DartType constantType = constant.value.getType(compiler.coreTypes);
if (!constantSystem.isSubtype(
compiler.types, constantType, elementType)) {
- compiler.withCurrentElement(constant.element, () {
- compiler.reportErrorMessage(
+ reporter.withCurrentElement(constant.element, () {
+ reporter.reportErrorMessage(
constant.node,
MessageKind.NOT_ASSIGNABLE,
{'fromType': constantType,
@@ -1190,7 +1199,7 @@
*/
void evaluateConstructorFieldValues(List<AstConstant> arguments) {
if (constructor.isErroneous) return;
- compiler.withCurrentElement(constructor, () {
+ reporter.withCurrentElement(constructor, () {
assignArgumentsToParameters(arguments);
evaluateConstructorInitializers();
});
@@ -1256,10 +1265,9 @@
new ErroneousConstantExpression(), new NullConstantValue());
}
-// TODO(johnniwinther): Avoid the need for this hack.
+// TODO(johnniwinther): Clean this up.
TreeElements _analyzeElementEagerly(Compiler compiler, AstElement element) {
- WorldImpact worldImpact = compiler.analyzeElement(element.declaration);
- compiler.enqueuer.resolution.applyImpact(element.declaration, worldImpact);
+ compiler.resolution.analyzeElement(element.declaration);
return element.resolvedAst.elements;
}
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 86a87f3..e3105d7 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -24,7 +24,10 @@
import 'common/registry.dart' show
Registry;
import 'common/resolution.dart' show
- ResolutionWorkItem;
+ Parsing,
+ Resolution,
+ ResolutionWorkItem,
+ ResolutionWorldImpact;
import 'common/tasks.dart' show
CompilerTask,
GenericTask;
@@ -42,7 +45,10 @@
Types;
import 'deferred_load.dart' show DeferredLoadTask, OutputUnit;
import 'diagnostics/code_location.dart';
-import 'diagnostics/diagnostic_listener.dart';
+import 'diagnostics/diagnostic_listener.dart' show
+ DiagnosticMessage,
+ DiagnosticOptions,
+ DiagnosticReporter;
import 'diagnostics/invariant.dart' show
invariant,
REPORT_EXCESS_RESOLUTION;
@@ -120,7 +126,8 @@
import 'tokens/token_map.dart' show
TokenMap;
import 'tree/tree.dart' show
- Node;
+ Node,
+ TypeAnnotation;
import 'typechecker.dart' show
TypeCheckerTask;
import 'types/types.dart' as ti;
@@ -136,13 +143,16 @@
import 'world.dart' show
World;
-abstract class Compiler extends DiagnosticListener {
+abstract class Compiler {
final Stopwatch totalCompileTime = new Stopwatch();
int nextFreeClassId = 0;
World world;
Types types;
_CompilerCoreTypes _coreTypes;
+ _CompilerDiagnosticReporter _reporter;
+ _CompilerResolution _resolution;
+ _CompilerParsing _parsing;
final CacheStrategy cacheStrategy;
@@ -181,7 +191,6 @@
final bool enableUserAssertions;
final bool trustTypeAnnotations;
final bool trustPrimitives;
- final bool enableConcreteTypeInference;
final bool disableTypeInferenceFlag;
final Uri deferredMapUri;
final bool dumpInfo;
@@ -238,23 +247,6 @@
*/
final Uri outputUri;
- /// Emit terse diagnostics without howToFix.
- final bool terseDiagnostics;
-
- /// If `true`, warnings and hints not from user code are reported.
- final bool showPackageWarnings;
-
- /// `true` if the last diagnostic was filtered, in which case the
- /// accompanying info message should be filtered as well.
- bool lastDiagnosticWasFiltered = false;
-
- /// Map containing information about the warnings and hints that have been
- /// suppressed for each library.
- Map<Uri, SuppressionInfo> suppressedWarnings = <Uri, SuppressionInfo>{};
-
- final bool suppressWarnings;
- final bool fatalWarnings;
-
/// If `true`, some values are cached for reuse in incremental compilation.
/// Incremental compilation is basically calling [run] more than once.
final bool hasIncrementalSupport;
@@ -283,7 +275,6 @@
Tracer tracer;
CompilerTask measuredTask;
- Element _currentElement;
LibraryElement coreLibrary;
LibraryElement asyncLibrary;
@@ -314,7 +305,10 @@
ClassElement get iterableClass => _coreTypes.iterableClass;
ClassElement get streamClass => _coreTypes.streamClass;
+ DiagnosticReporter get reporter => _reporter;
CoreTypes get coreTypes => _coreTypes;
+ Resolution get resolution => _resolution;
+ Parsing get parsing => _parsing;
ClassElement typedDataClass;
@@ -372,49 +366,7 @@
fromEnvironment(String name) => null;
- Element get currentElement => _currentElement;
-
- String tryToString(object) {
- try {
- return object.toString();
- } catch (_) {
- return '<exception in toString()>';
- }
- }
-
- /**
- * Perform an operation, [f], returning the return value from [f]. If an
- * error occurs then report it as having occurred during compilation of
- * [element]. Can be nested.
- */
- withCurrentElement(Element element, f()) {
- Element old = currentElement;
- _currentElement = element;
- try {
- return f();
- } on SpannableAssertionFailure catch (ex) {
- if (!hasCrashed) {
- reportAssertionFailure(ex);
- pleaseReportCrash();
- }
- hasCrashed = true;
- rethrow;
- } on StackOverflowError {
- // We cannot report anything useful in this case, because we
- // do not have enough stack space.
- rethrow;
- } catch (ex) {
- if (hasCrashed) rethrow;
- try {
- unhandledExceptionOnElement(element);
- } catch (doubleFault) {
- // Ignoring exceptions in exception handling.
- }
- rethrow;
- } finally {
- _currentElement = old;
- }
- }
+ Element get currentElement => _reporter.currentElement;
List<CompilerTask> tasks;
ScannerTask scanner;
@@ -458,6 +410,8 @@
bool enabledInvokeOn = false;
bool hasIsolateSupport = false;
+ bool get hasCrashed => _reporter.hasCrashed;
+
Stopwatch progress;
bool get shouldPrintProgress {
@@ -481,8 +435,6 @@
compilationFailedInternal = value;
}
- bool hasCrashed = false;
-
/// Set by the backend if real reflection is detected in use of dart:mirrors.
bool disableTypeInferenceForMirrors = false;
@@ -490,7 +442,6 @@
this.enableUserAssertions: false,
this.trustTypeAnnotations: false,
this.trustPrimitives: false,
- this.enableConcreteTypeInference: false,
bool disableTypeInferenceFlag: false,
this.maxConcreteTypeSize: 5,
this.enableMinification: false,
@@ -510,20 +461,17 @@
this.sourceMapUri: null,
this.outputUri: null,
this.buildId: UNDETERMINED_BUILD_ID,
- this.terseDiagnostics: false,
this.deferredMapUri: null,
this.dumpInfo: false,
- this.showPackageWarnings: false,
bool useStartupEmitter: false,
this.useContentSecurityPolicy: false,
- this.suppressWarnings: false,
- this.fatalWarnings: false,
bool hasIncrementalSupport: false,
this.enableExperimentalMirrors: false,
this.enableAssertMessage: false,
this.allowNativeExtensions: false,
this.generateCodeWithCompileTimeErrors: false,
this.testMode: false,
+ DiagnosticOptions diagnosticOptions,
api.CompilerOutput outputProvider,
List<String> strips: const []})
: this.disableTypeInferenceFlag =
@@ -544,7 +492,10 @@
world = new World(this);
// TODO(johnniwinther): Initialize core types in [initializeCoreClasses] and
// make its field final.
- _coreTypes = new _CompilerCoreTypes(this);
+ _reporter = new _CompilerDiagnosticReporter(this, diagnosticOptions);
+ _parsing = new _CompilerParsing(this);
+ _resolution = new _CompilerResolution(this);
+ _coreTypes = new _CompilerCoreTypes(_resolution);
types = new Types(this);
tracer = new Tracer(this, this.outputProvider);
@@ -609,118 +560,15 @@
int getNextFreeClassId() => nextFreeClassId++;
void unimplemented(Spannable spannable, String methodName) {
- internalError(spannable, "$methodName not implemented.");
- }
-
- internalError(Spannable node, reason) {
- String message = tryToString(reason);
- reportDiagnosticInternal(
- createMessage(node, MessageKind.GENERIC, {'text': message}),
- const <DiagnosticMessage>[],
- api.Diagnostic.CRASH);
- throw 'Internal Error: $message';
- }
-
- void unhandledExceptionOnElement(Element element) {
- if (hasCrashed) return;
- hasCrashed = true;
- reportDiagnostic(
- createMessage(element, MessageKind.COMPILER_CRASHED),
- const <DiagnosticMessage>[],
- api.Diagnostic.CRASH);
- pleaseReportCrash();
- }
-
- void pleaseReportCrash() {
- print(
- MessageTemplate.TEMPLATES[MessageKind.PLEASE_REPORT_THE_CRASH]
- .message({'buildId': buildId}));
- }
-
- SourceSpan spanFromSpannable(Spannable node) {
- // TODO(johnniwinther): Disallow `node == null` ?
- if (node == null) return null;
- if (node == CURRENT_ELEMENT_SPANNABLE) {
- node = currentElement;
- } else if (node == NO_LOCATION_SPANNABLE) {
- if (currentElement == null) return null;
- node = currentElement;
- }
- if (node is SourceSpan) {
- return node;
- } else if (node is Node) {
- return spanFromNode(node);
- } else if (node is TokenPair) {
- return spanFromTokens(node.begin, node.end);
- } else if (node is Token) {
- return spanFromTokens(node, node);
- } else if (node is HInstruction) {
- return spanFromHInstruction(node);
- } else if (node is Element) {
- return spanFromElement(node);
- } else if (node is MetadataAnnotation) {
- Uri uri = node.annotatedElement.compilationUnit.script.resourceUri;
- return spanFromTokens(node.beginToken, node.endToken, uri);
- } else if (node is Local) {
- Local local = node;
- return spanFromElement(local.executableContext);
- } else {
- throw 'No error location.';
- }
- }
-
- Element _elementFromHInstruction(HInstruction instruction) {
- return instruction.sourceElement is Element
- ? instruction.sourceElement : null;
- }
-
- /// Finds the approximate [Element] for [node]. [currentElement] is used as
- /// the default value.
- Element elementFromSpannable(Spannable node) {
- Element element;
- if (node is Element) {
- element = node;
- } else if (node is HInstruction) {
- element = _elementFromHInstruction(node);
- } else if (node is MetadataAnnotation) {
- element = node.annotatedElement;
- }
- return element != null ? element : currentElement;
- }
-
- void log(message) {
- Message msg = MessageTemplate.TEMPLATES[MessageKind.GENERIC]
- .message({'text': '$message'});
- reportDiagnostic(
- new DiagnosticMessage(null, null, msg),
- const <DiagnosticMessage>[],
- api.Diagnostic.VERBOSE_INFO);
+ reporter.internalError(spannable, "$methodName not implemented.");
}
Future<bool> run(Uri uri) {
totalCompileTime.start();
- return new Future.sync(() => runCompiler(uri)).catchError((error) {
- try {
- if (!hasCrashed) {
- hasCrashed = true;
- if (error is SpannableAssertionFailure) {
- reportAssertionFailure(error);
- } else {
- reportDiagnostic(
- createMessage(
- new SourceSpan(uri, 0, 0),
- MessageKind.COMPILER_CRASHED),
- const <DiagnosticMessage>[],
- api.Diagnostic.CRASH);
- }
- pleaseReportCrash();
- }
- } catch (doubleFault) {
- // Ignoring exceptions in exception handling.
- }
- throw error;
- }).whenComplete(() {
+ return new Future.sync(() => runCompiler(uri))
+ .catchError((error) => _reporter.onError(uri, error))
+ .whenComplete(() {
tracer.close();
totalCompileTime.stop();
}).then((_) {
@@ -859,7 +707,7 @@
if (loadedLibraries.containsLibrary(uri)) {
Set<String> importChains =
computeImportChainsFor(loadedLibraries, Uri.parse('dart:io'));
- reportInfo(NO_LOCATION_SPANNABLE,
+ reporter.reportInfo(NO_LOCATION_SPANNABLE,
MessageKind.DISALLOWED_LIBRARY_IMPORT,
{'uri': uri,
'importChain': importChains.join(
@@ -871,24 +719,27 @@
return null;
}
- if (!enableExperimentalMirrors &&
- loadedLibraries.containsLibrary(Uris.dart_mirrors)) {
+ bool importsMirrorsLibrary =
+ loadedLibraries.containsLibrary(Uris.dart_mirrors);
+ if (importsMirrorsLibrary && !backend.supportsReflection) {
Set<String> importChains =
computeImportChainsFor(loadedLibraries, Uris.dart_mirrors);
- if (!backend.supportsReflection) {
- reportErrorMessage(
- NO_LOCATION_SPANNABLE,
- MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND);
- } else {
- reportWarningMessage(
- NO_LOCATION_SPANNABLE,
- MessageKind.IMPORT_EXPERIMENTAL_MIRRORS,
- {'importChain': importChains.join(
- MessageTemplate.IMPORT_EXPERIMENTAL_MIRRORS_PADDING)});
- }
+ reporter.reportErrorMessage(
+ NO_LOCATION_SPANNABLE,
+ MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND,
+ {'importChain': importChains.join(
+ MessageTemplate.MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING)});
+ } else if (importsMirrorsLibrary && !enableExperimentalMirrors) {
+ Set<String> importChains =
+ computeImportChainsFor(loadedLibraries, Uris.dart_mirrors);
+ reporter.reportWarningMessage(
+ NO_LOCATION_SPANNABLE,
+ MessageKind.IMPORT_EXPERIMENTAL_MIRRORS,
+ {'importChain': importChains.join(
+ MessageTemplate.IMPORT_EXPERIMENTAL_MIRRORS_PADDING)});
}
- functionClass.ensureResolved(this);
+ functionClass.ensureResolved(resolution);
functionApplyMethod = functionClass.lookupLocalMember('apply');
if (preserveComments) {
@@ -903,7 +754,7 @@
bool isProxyConstant(ConstantValue value) {
FieldElement field = coreLibrary.find('proxy');
if (field == null) return false;
- if (!enqueuer.resolution.hasBeenResolved(field)) return false;
+ if (!resolution.hasBeenResolved(field)) return false;
if (proxyConstant == null) {
proxyConstant =
constants.getConstantValue(
@@ -915,10 +766,10 @@
Element findRequiredElement(LibraryElement library, String name) {
var element = library.find(name);
if (element == null) {
- internalError(library,
+ reporter.internalError(library,
"The library '${library.canonicalUri}' does not contain required "
"element: '$name'.");
- }
+ }
return element;
}
@@ -973,7 +824,7 @@
_coreTypes.iterableClass = lookupCoreClass('Iterable');
_coreTypes.symbolClass = lookupCoreClass('Symbol');
if (!missingCoreClasses.isEmpty) {
- internalError(
+ reporter.internalError(
coreLibrary,
'dart:core library does not contain required classes: '
'$missingCoreClasses');
@@ -1010,16 +861,16 @@
return new Future.sync(() {
if (librariesToAnalyzeWhenRun != null) {
return Future.forEach(librariesToAnalyzeWhenRun, (libraryUri) {
- log('Analyzing $libraryUri ($buildId)');
+ reporter.log('Analyzing $libraryUri ($buildId)');
return libraryLoader.loadLibrary(libraryUri);
});
}
}).then((_) {
if (uri != null) {
if (analyzeOnly) {
- log('Analyzing $uri ($buildId)');
+ reporter.log('Analyzing $uri ($buildId)');
} else {
- log('Compiling $uri ($buildId)');
+ reporter.log('Compiling $uri ($buildId)');
}
return libraryLoader.loadLibrary(uri).then((LibraryElement library) {
mainApp = library;
@@ -1053,7 +904,7 @@
if (main is ErroneousElement) {
errorElement = main;
} else {
- internalError(main, 'Problem with ${Identifiers.main}.');
+ reporter.internalError(main, 'Problem with ${Identifiers.main}.');
}
mainFunction = backend.helperForBadMain();
} else if (!main.isFunction) {
@@ -1063,7 +914,7 @@
mainFunction = backend.helperForBadMain();
} else {
mainFunction = main;
- mainFunction.computeType(this);
+ mainFunction.computeType(resolution);
FunctionSignature parameters = mainFunction.functionSignature;
if (parameters.requiredParameterCount > 2) {
int index = 0;
@@ -1081,7 +932,7 @@
}
if (mainFunction == null) {
if (errorElement == null && !analyzeOnly && !analyzeAll) {
- internalError(mainApp, "Problem with '${Identifiers.main}'.");
+ reporter.internalError(mainApp, "Problem with '${Identifiers.main}'.");
} else {
mainFunction = errorElement;
}
@@ -1089,7 +940,7 @@
if (errorElement != null &&
errorElement.isSynthesized &&
!mainApp.isSynthesized) {
- reportWarningMessage(
+ reporter.reportWarningMessage(
errorElement, errorElement.messageKind,
errorElement.messageArguments);
}
@@ -1106,7 +957,7 @@
Uri libraryUri,
{bool skipLibraryWithPartOfTag: true}) {
assert(analyzeMain);
- log('Analyzing $libraryUri ($buildId)');
+ reporter.log('Analyzing $libraryUri ($buildId)');
return libraryLoader.loadLibrary(libraryUri).then((LibraryElement library) {
var compilationUnit = library.compilationUnit;
if (skipLibraryWithPartOfTag && compilationUnit.partTag != null) {
@@ -1114,7 +965,7 @@
}
fullyEnqueueLibrary(library, enqueuer.resolution);
emptyQueue(enqueuer.resolution);
- enqueuer.resolution.logSummary(log);
+ enqueuer.resolution.logSummary(reporter.log);
return library;
});
}
@@ -1134,7 +985,7 @@
phase = PHASE_RESOLVING;
if (analyzeAll) {
libraryLoader.libraries.forEach((LibraryElement library) {
- log('Enqueuing ${library.canonicalUri}');
+ reporter.log('Enqueuing ${library.canonicalUri}');
fullyEnqueueLibrary(library, enqueuer.resolution);
});
} else if (analyzeMain && mainApp != null) {
@@ -1144,30 +995,11 @@
// that are not pulled in by a particular element.
backend.enqueueHelpers(enqueuer.resolution, globalDependencies);
resolveLibraryMetadata();
- log('Resolving...');
+ reporter.log('Resolving...');
processQueue(enqueuer.resolution, mainFunction);
- enqueuer.resolution.logSummary(log);
+ enqueuer.resolution.logSummary(reporter.log);
- if (!showPackageWarnings && !suppressWarnings) {
- suppressedWarnings.forEach((Uri uri, SuppressionInfo info) {
- MessageKind kind = MessageKind.HIDDEN_WARNINGS_HINTS;
- if (info.warnings == 0) {
- kind = MessageKind.HIDDEN_HINTS;
- } else if (info.hints == 0) {
- kind = MessageKind.HIDDEN_WARNINGS;
- }
- MessageTemplate template = MessageTemplate.TEMPLATES[kind];
- Message message = template.message(
- {'warnings': info.warnings,
- 'hints': info.hints,
- 'uri': uri},
- terseDiagnostics);
- reportDiagnostic(
- new DiagnosticMessage(null, null, message),
- const <DiagnosticMessage>[],
- api.Diagnostic.HINT);
- });
- }
+ _reporter.reportSuppressedMessagesSummary();
if (compilationFailed){
if (!generateCodeWithCompileTimeErrors) return;
@@ -1198,14 +1030,14 @@
deferredLoadTask.onResolutionComplete(mainFunction);
- log('Inferring types...');
+ reporter.log('Inferring types...');
typesTask.onResolutionComplete(mainFunction);
if (stopAfterTypeInference) return;
backend.onTypeInferenceComplete();
- log('Compiling...');
+ reporter.log('Compiling...');
phase = PHASE_COMPILING;
backend.onCodegenStart();
// TODO(johnniwinther): Move these to [CodegenEnqueuer].
@@ -1218,7 +1050,7 @@
});
}
processQueue(enqueuer.codegen, mainFunction);
- enqueuer.codegen.logSummary(log);
+ enqueuer.codegen.logSummary(reporter.log);
int programSize = backend.assembleProgram();
@@ -1240,7 +1072,7 @@
void fullyEnqueueTopLevelElement(Element element, Enqueuer world) {
if (element.isClass) {
ClassElement cls = element;
- cls.ensureResolved(this);
+ cls.ensureResolved(resolution);
cls.forEachLocalMember(enqueuer.resolution.addToWorkList);
backend.registerInstantiatedType(
cls.rawType, world, globalDependencies);
@@ -1256,7 +1088,7 @@
for (LibraryElement library in libraryLoader.libraries) {
if (library.metadata != null) {
for (MetadataAnnotation metadata in library.metadata) {
- metadata.ensureResolved(this);
+ metadata.ensureResolved(resolution);
}
}
}
@@ -1267,7 +1099,7 @@
*/
void emptyQueue(Enqueuer world) {
world.forEach((WorkItem work) {
- withCurrentElement(work.element, () {
+ reporter.withCurrentElement(work.element, () {
world.applyImpact(work.element, work.run(this, world));
});
});
@@ -1277,13 +1109,13 @@
world.nativeEnqueuer.processNativeClasses(libraryLoader.libraries);
if (main != null && !main.isErroneous) {
FunctionElement mainMethod = main;
- mainMethod.computeType(this);
+ mainMethod.computeType(resolution);
if (mainMethod.functionSignature.parameterCount != 0) {
// The first argument could be a list of strings.
- backend.listImplementation.ensureResolved(this);
+ backend.listImplementation.ensureResolved(resolution);
backend.registerInstantiatedType(
backend.listImplementation.rawType, world, globalDependencies);
- backend.stringImplementation.ensureResolved(this);
+ backend.stringImplementation.ensureResolved(resolution);
backend.registerInstantiatedType(
backend.stringImplementation.rawType, world, globalDependencies);
@@ -1309,11 +1141,11 @@
checkQueues() {
for (Enqueuer world in [enqueuer.resolution, enqueuer.codegen]) {
world.forEach((WorkItem work) {
- internalError(work.element, "Work list is not empty.");
+ reporter.internalError(work.element, "Work list is not empty.");
});
}
if (!REPORT_EXCESS_RESOLUTION) return;
- var resolved = new Set.from(enqueuer.resolution.resolvedElements);
+ var resolved = new Set.from(enqueuer.resolution.processedElements);
for (Element e in enqueuer.codegen.generatedCode.keys) {
resolved.remove(e);
}
@@ -1332,15 +1164,15 @@
resolved.remove(e);
}
}
- log('Excess resolution work: ${resolved.length}.');
+ reporter.log('Excess resolution work: ${resolved.length}.');
for (Element e in resolved) {
- reportWarningMessage(e,
+ reporter.reportWarningMessage(e,
MessageKind.GENERIC,
{'text': 'Warning: $e resolved but not compiled.'});
}
}
- WorldImpact analyzeElement(Element element) {
+ ResolutionWorldImpact analyzeElement(Element element) {
assert(invariant(element,
element.impliesType ||
element.isField ||
@@ -1352,23 +1184,11 @@
assert(invariant(element, element is AnalyzableElement,
message: 'Element $element is not analyzable.'));
assert(invariant(element, element.isDeclaration));
- ResolutionEnqueuer world = enqueuer.resolution;
- if (world.hasBeenResolved(element)) {
- return const WorldImpact();
- }
- assert(parser != null);
- Node tree = parser.parse(element);
- assert(invariant(element, !element.isSynthesized || tree == null));
- WorldImpact worldImpact = resolver.resolve(element);
- if (tree != null && !analyzeSignaturesOnly && !suppressWarnings) {
- // Only analyze nodes with a corresponding [TreeElements].
- checker.check(element);
- }
- world.registerResolvedElement(element);
- return worldImpact;
+ return resolution.analyzeElement(element);
}
- WorldImpact analyze(ResolutionWorkItem work, ResolutionEnqueuer world) {
+ ResolutionWorldImpact analyze(ResolutionWorkItem work,
+ ResolutionEnqueuer world) {
assert(invariant(work.element, identical(world, enqueuer.resolution)));
assert(invariant(work.element, !work.isAnalyzed,
message: 'Element ${work.element} has already been analyzed'));
@@ -1376,17 +1196,19 @@
// TODO(ahe): Add structured diagnostics to the compiler API and
// use it to separate this from the --verbose option.
if (phase == PHASE_RESOLVING) {
- log('Resolved ${enqueuer.resolution.resolvedElements.length} '
+ reporter.log(
+ 'Resolved ${enqueuer.resolution.processedElements.length} '
'elements.');
progress.reset();
}
}
AstElement element = work.element;
- if (world.hasBeenResolved(element)) {
- return const WorldImpact();
+ if (world.hasBeenProcessed(element)) {
+ return const ResolutionWorldImpact();
}
- WorldImpact worldImpact = analyzeElement(element);
+ ResolutionWorldImpact worldImpact = analyzeElement(element);
backend.onElementResolved(element, element.resolvedAst.elements);
+ world.registerProcessedElement(element);
return worldImpact;
}
@@ -1395,153 +1217,19 @@
if (shouldPrintProgress) {
// TODO(ahe): Add structured diagnostics to the compiler API and
// use it to separate this from the --verbose option.
- log('Compiled ${enqueuer.codegen.generatedCode.length} methods.');
+ reporter.log(
+ 'Compiled ${enqueuer.codegen.generatedCode.length} methods.');
progress.reset();
}
return backend.codegen(work);
}
- DiagnosticMessage createMessage(
- Spannable spannable,
- MessageKind messageKind,
- [Map arguments = const {}]) {
- SourceSpan span = spanFromSpannable(spannable);
- MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
- Message message = template.message(arguments, terseDiagnostics);
- return new DiagnosticMessage(span, spannable, message);
- }
-
- void reportError(
- DiagnosticMessage message,
- [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
- reportDiagnosticInternal(message, infos, api.Diagnostic.ERROR);
- }
-
- void reportWarning(
- DiagnosticMessage message,
- [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
- reportDiagnosticInternal(message, infos, api.Diagnostic.WARNING);
- }
-
- void reportHint(
- DiagnosticMessage message,
- [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
- reportDiagnosticInternal(message, infos, api.Diagnostic.HINT);
- }
-
- @deprecated
- void reportInfo(Spannable node, MessageKind messageKind,
- [Map arguments = const {}]) {
- reportDiagnosticInternal(
- createMessage(node, messageKind, arguments),
- const <DiagnosticMessage>[],
- api.Diagnostic.INFO);
- }
-
- void reportDiagnosticInternal(DiagnosticMessage message,
- List<DiagnosticMessage> infos,
- api.Diagnostic kind) {
- if (!showPackageWarnings && message.spannable != NO_LOCATION_SPANNABLE) {
- switch (kind) {
- case api.Diagnostic.WARNING:
- case api.Diagnostic.HINT:
- Element element = elementFromSpannable(message.spannable);
- if (!inUserCode(element, assumeInUserCode: true)) {
- Uri uri = getCanonicalUri(element);
- SuppressionInfo info =
- suppressedWarnings.putIfAbsent(uri, () => new SuppressionInfo());
- if (kind == api.Diagnostic.WARNING) {
- info.warnings++;
- } else {
- info.hints++;
- }
- lastDiagnosticWasFiltered = true;
- return;
- }
- break;
- case api.Diagnostic.INFO:
- if (lastDiagnosticWasFiltered) {
- return;
- }
- break;
- }
- }
- lastDiagnosticWasFiltered = false;
- reportDiagnostic(message, infos, kind);
- }
-
void reportDiagnostic(DiagnosticMessage message,
List<DiagnosticMessage> infos,
api.Diagnostic kind);
- void reportAssertionFailure(SpannableAssertionFailure ex) {
- String message = (ex.message != null) ? tryToString(ex.message)
- : tryToString(ex);
- reportDiagnosticInternal(
- createMessage(ex.node, MessageKind.GENERIC, {'text': message}),
- const <DiagnosticMessage>[],
- api.Diagnostic.CRASH);
- }
-
- SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) {
- if (begin == null || end == null) {
- // TODO(ahe): We can almost always do better. Often it is only
- // end that is null. Otherwise, we probably know the current
- // URI.
- throw 'Cannot find tokens to produce error message.';
- }
- if (uri == null && currentElement != null) {
- uri = currentElement.compilationUnit.script.resourceUri;
- }
- return new SourceSpan.fromTokens(uri, begin, end);
- }
-
- SourceSpan spanFromNode(Node node) {
- return spanFromTokens(node.getBeginToken(), node.getEndToken());
- }
-
- SourceSpan spanFromElement(Element element) {
- if (element != null && element.sourcePosition != null) {
- return element.sourcePosition;
- }
- while (element != null && element.isSynthesized) {
- element = element.enclosingElement;
- }
- if (element != null &&
- element.sourcePosition == null &&
- !element.isLibrary &&
- !element.isCompilationUnit) {
- // Sometimes, the backend fakes up elements that have no
- // position. So we use the enclosing element instead. It is
- // not a good error location, but cancel really is "internal
- // error" or "not implemented yet", so the vicinity is good
- // enough for now.
- element = element.enclosingElement;
- // TODO(ahe): I plan to overhaul this infrastructure anyways.
- }
- if (element == null) {
- element = currentElement;
- }
- if (element == null) {
- return null;
- }
-
- if (element.sourcePosition != null) {
- return element.sourcePosition;
- }
- Token position = element.position;
- Uri uri = element.compilationUnit.script.resourceUri;
- return (position == null)
- ? new SourceSpan(uri, 0, 0)
- : spanFromTokens(position, position, uri);
- }
-
- SourceSpan spanFromHInstruction(HInstruction instruction) {
- Element element = _elementFromHInstruction(instruction);
- if (element == null) element = currentElement;
- SourceInformation position = instruction.sourceInformation;
- if (position == null) return spanFromElement(element);
- return position.sourceSpan;
+ void reportCrashInUserCode(String message, exception, stackTrace) {
+ _reporter.onCrashInUserCode(message, exception, stackTrace);
}
/**
@@ -1616,20 +1304,20 @@
void checkLive(member) {
if (member.isErroneous) return;
if (member.isFunction) {
- if (!enqueuer.resolution.hasBeenResolved(member)) {
- reportHintMessage(
+ if (!enqueuer.resolution.hasBeenProcessed(member)) {
+ reporter.reportHintMessage(
member, MessageKind.UNUSED_METHOD, {'name': member.name});
}
} else if (member.isClass) {
if (!member.isResolved) {
- reportHintMessage(
+ reporter.reportHintMessage(
member, MessageKind.UNUSED_CLASS, {'name': member.name});
} else {
member.forEachLocalMember(checkLive);
}
} else if (member.isTypedef) {
if (!member.isResolved) {
- reportHintMessage(
+ reporter.reportHintMessage(
member, MessageKind.UNUSED_TYPEDEF, {'name': member.name});
}
}
@@ -1753,7 +1441,7 @@
}
class _CompilerCoreTypes implements CoreTypes {
- final Compiler compiler;
+ final Resolution resolution;
ClassElement objectClass;
ClassElement boolClass;
@@ -1773,31 +1461,50 @@
ClassElement streamClass;
ClassElement resourceClass;
- _CompilerCoreTypes(this.compiler);
+ _CompilerCoreTypes(this.resolution);
@override
- InterfaceType get objectType => objectClass.computeType(compiler);
+ InterfaceType get objectType {
+ objectClass.ensureResolved(resolution);
+ return objectClass.rawType;
+ }
@override
- InterfaceType get boolType => boolClass.computeType(compiler);
+ InterfaceType get boolType {
+ boolClass.ensureResolved(resolution);
+ return boolClass.rawType;
+ }
@override
- InterfaceType get doubleType => doubleClass.computeType(compiler);
+ InterfaceType get doubleType {
+ doubleClass.ensureResolved(resolution);
+ return doubleClass.rawType;
+ }
@override
- InterfaceType get functionType => functionClass.computeType(compiler);
+ InterfaceType get functionType {
+ functionClass.ensureResolved(resolution);
+ return functionClass.rawType;
+ }
@override
- InterfaceType get intType => intClass.computeType(compiler);
+ InterfaceType get intType {
+ intClass.ensureResolved(resolution);
+ return intClass.rawType;
+ }
@override
- InterfaceType get resourceType => resourceClass.computeType(compiler);
+ InterfaceType get resourceType {
+ resourceClass.ensureResolved(resolution);
+ return resourceClass.rawType;
+ }
@override
InterfaceType listType([DartType elementType]) {
- InterfaceType type = listClass.computeType(compiler);
+ listClass.ensureResolved(resolution);
+ InterfaceType type = listClass.rawType;
if (elementType == null) {
- return listClass.rawType;
+ return type;
}
return type.createInstantiation([elementType]);
}
@@ -1805,9 +1512,10 @@
@override
InterfaceType mapType([DartType keyType,
DartType valueType]) {
- InterfaceType type = mapClass.computeType(compiler);
+ mapClass.ensureResolved(resolution);
+ InterfaceType type = mapClass.rawType;
if (keyType == null && valueType == null) {
- return mapClass.rawType;
+ return type;
} else if (keyType == null) {
keyType = const DynamicType();
} else if (valueType == null) {
@@ -1817,44 +1525,498 @@
}
@override
- InterfaceType get nullType => nullClass.computeType(compiler);
+ InterfaceType get nullType {
+ nullClass.ensureResolved(resolution);
+ return nullClass.rawType;
+ }
@override
- InterfaceType get numType => numClass.computeType(compiler);
+ InterfaceType get numType {
+ numClass.ensureResolved(resolution);
+ return numClass.rawType;
+ }
@override
- InterfaceType get stringType => stringClass.computeType(compiler);
+ InterfaceType get stringType {
+ stringClass.ensureResolved(resolution);
+ return stringClass.rawType;
+ }
@override
- InterfaceType get symbolType => symbolClass.computeType(compiler);
+ InterfaceType get symbolType {
+ symbolClass.ensureResolved(resolution);
+ return symbolClass.rawType;
+ }
@override
- InterfaceType get typeType => typeClass.computeType(compiler);
+ InterfaceType get typeType {
+ typeClass.ensureResolved(resolution);
+ return typeClass.rawType;
+ }
@override
InterfaceType iterableType([DartType elementType]) {
- InterfaceType type = iterableClass.computeType(compiler);
+ iterableClass.ensureResolved(resolution);
+ InterfaceType type = iterableClass.rawType;
if (elementType == null) {
- return iterableClass.rawType;
+ return type;
}
return type.createInstantiation([elementType]);
}
@override
InterfaceType futureType([DartType elementType]) {
- InterfaceType type = futureClass.computeType(compiler);
+ futureClass.ensureResolved(resolution);
+ InterfaceType type = futureClass.rawType;
if (elementType == null) {
- return futureClass.rawType;
+ return type;
}
return type.createInstantiation([elementType]);
}
@override
InterfaceType streamType([DartType elementType]) {
- InterfaceType type = streamClass.computeType(compiler);
+ streamClass.ensureResolved(resolution);
+ InterfaceType type = streamClass.rawType;
if (elementType == null) {
- return streamClass.rawType;
+ return type;
}
return type.createInstantiation([elementType]);
}
}
+
+class _CompilerDiagnosticReporter extends DiagnosticReporter {
+ final Compiler compiler;
+ final DiagnosticOptions options;
+
+ Element _currentElement;
+ bool hasCrashed = false;
+
+ /// `true` if the last diagnostic was filtered, in which case the
+ /// accompanying info message should be filtered as well.
+ bool lastDiagnosticWasFiltered = false;
+
+ /// Map containing information about the warnings and hints that have been
+ /// suppressed for each library.
+ Map<Uri, SuppressionInfo> suppressedWarnings = <Uri, SuppressionInfo>{};
+
+ _CompilerDiagnosticReporter(this.compiler, this.options);
+
+ Element get currentElement => _currentElement;
+
+ DiagnosticMessage createMessage(
+ Spannable spannable,
+ MessageKind messageKind,
+ [Map arguments = const {}]) {
+ SourceSpan span = spanFromSpannable(spannable);
+ MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
+ Message message = template.message(arguments, options.terseDiagnostics);
+ return new DiagnosticMessage(span, spannable, message);
+ }
+
+ void reportError(
+ DiagnosticMessage message,
+ [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
+ reportDiagnosticInternal(message, infos, api.Diagnostic.ERROR);
+ }
+
+ void reportWarning(
+ DiagnosticMessage message,
+ [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
+ reportDiagnosticInternal(message, infos, api.Diagnostic.WARNING);
+ }
+
+ void reportHint(
+ DiagnosticMessage message,
+ [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
+ reportDiagnosticInternal(message, infos, api.Diagnostic.HINT);
+ }
+
+ @deprecated
+ void reportInfo(Spannable node, MessageKind messageKind,
+ [Map arguments = const {}]) {
+ reportDiagnosticInternal(
+ createMessage(node, messageKind, arguments),
+ const <DiagnosticMessage>[],
+ api.Diagnostic.INFO);
+ }
+
+ void reportDiagnosticInternal(DiagnosticMessage message,
+ List<DiagnosticMessage> infos,
+ api.Diagnostic kind) {
+ if (!options.showPackageWarnings &&
+ message.spannable != NO_LOCATION_SPANNABLE) {
+ switch (kind) {
+ case api.Diagnostic.WARNING:
+ case api.Diagnostic.HINT:
+ Element element = elementFromSpannable(message.spannable);
+ if (!compiler.inUserCode(element, assumeInUserCode: true)) {
+ Uri uri = compiler.getCanonicalUri(element);
+ SuppressionInfo info =
+ suppressedWarnings.putIfAbsent(uri, () => new SuppressionInfo());
+ if (kind == api.Diagnostic.WARNING) {
+ info.warnings++;
+ } else {
+ info.hints++;
+ }
+ lastDiagnosticWasFiltered = true;
+ return;
+ }
+ break;
+ case api.Diagnostic.INFO:
+ if (lastDiagnosticWasFiltered) {
+ return;
+ }
+ break;
+ }
+ }
+ lastDiagnosticWasFiltered = false;
+ reportDiagnostic(message, infos, kind);
+ }
+
+ void reportDiagnostic(DiagnosticMessage message,
+ List<DiagnosticMessage> infos,
+ api.Diagnostic kind) {
+ compiler.reportDiagnostic(message, infos, kind);
+ }
+
+ /**
+ * Perform an operation, [f], returning the return value from [f]. If an
+ * error occurs then report it as having occurred during compilation of
+ * [element]. Can be nested.
+ */
+ withCurrentElement(Element element, f()) {
+ Element old = currentElement;
+ _currentElement = element;
+ try {
+ return f();
+ } on SpannableAssertionFailure catch (ex) {
+ if (!hasCrashed) {
+ reportAssertionFailure(ex);
+ pleaseReportCrash();
+ }
+ hasCrashed = true;
+ rethrow;
+ } on StackOverflowError {
+ // We cannot report anything useful in this case, because we
+ // do not have enough stack space.
+ rethrow;
+ } catch (ex) {
+ if (hasCrashed) rethrow;
+ try {
+ unhandledExceptionOnElement(element);
+ } catch (doubleFault) {
+ // Ignoring exceptions in exception handling.
+ }
+ rethrow;
+ } finally {
+ _currentElement = old;
+ }
+ }
+
+ void reportAssertionFailure(SpannableAssertionFailure ex) {
+ String message = (ex.message != null) ? tryToString(ex.message)
+ : tryToString(ex);
+ reportDiagnosticInternal(
+ createMessage(ex.node, MessageKind.GENERIC, {'text': message}),
+ const <DiagnosticMessage>[],
+ api.Diagnostic.CRASH);
+ }
+
+ SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) {
+ if (begin == null || end == null) {
+ // TODO(ahe): We can almost always do better. Often it is only
+ // end that is null. Otherwise, we probably know the current
+ // URI.
+ throw 'Cannot find tokens to produce error message.';
+ }
+ if (uri == null && currentElement != null) {
+ uri = currentElement.compilationUnit.script.resourceUri;
+ }
+ return new SourceSpan.fromTokens(uri, begin, end);
+ }
+
+ SourceSpan spanFromNode(Node node) {
+ return spanFromTokens(node.getBeginToken(), node.getEndToken());
+ }
+
+ SourceSpan spanFromElement(Element element) {
+ if (element != null && element.sourcePosition != null) {
+ return element.sourcePosition;
+ }
+ while (element != null && element.isSynthesized) {
+ element = element.enclosingElement;
+ }
+ if (element != null &&
+ element.sourcePosition == null &&
+ !element.isLibrary &&
+ !element.isCompilationUnit) {
+ // Sometimes, the backend fakes up elements that have no
+ // position. So we use the enclosing element instead. It is
+ // not a good error location, but cancel really is "internal
+ // error" or "not implemented yet", so the vicinity is good
+ // enough for now.
+ element = element.enclosingElement;
+ // TODO(ahe): I plan to overhaul this infrastructure anyways.
+ }
+ if (element == null) {
+ element = currentElement;
+ }
+ if (element == null) {
+ return null;
+ }
+
+ if (element.sourcePosition != null) {
+ return element.sourcePosition;
+ }
+ Token position = element.position;
+ Uri uri = element.compilationUnit.script.resourceUri;
+ return (position == null)
+ ? new SourceSpan(uri, 0, 0)
+ : spanFromTokens(position, position, uri);
+ }
+
+ SourceSpan spanFromHInstruction(HInstruction instruction) {
+ Element element = _elementFromHInstruction(instruction);
+ if (element == null) element = currentElement;
+ SourceInformation position = instruction.sourceInformation;
+ if (position == null) return spanFromElement(element);
+ return position.sourceSpan;
+ }
+
+ SourceSpan spanFromSpannable(Spannable node) {
+ // TODO(johnniwinther): Disallow `node == null` ?
+ if (node == null) return null;
+ if (node == CURRENT_ELEMENT_SPANNABLE) {
+ node = currentElement;
+ } else if (node == NO_LOCATION_SPANNABLE) {
+ if (currentElement == null) return null;
+ node = currentElement;
+ }
+ if (node is SourceSpan) {
+ return node;
+ } else if (node is Node) {
+ return spanFromNode(node);
+ } else if (node is TokenPair) {
+ return spanFromTokens(node.begin, node.end);
+ } else if (node is Token) {
+ return spanFromTokens(node, node);
+ } else if (node is HInstruction) {
+ return spanFromHInstruction(node);
+ } else if (node is Element) {
+ return spanFromElement(node);
+ } else if (node is MetadataAnnotation) {
+ Uri uri = node.annotatedElement.compilationUnit.script.resourceUri;
+ return spanFromTokens(node.beginToken, node.endToken, uri);
+ } else if (node is Local) {
+ Local local = node;
+ return spanFromElement(local.executableContext);
+ } else {
+ throw 'No error location.';
+ }
+ }
+
+ Element _elementFromHInstruction(HInstruction instruction) {
+ return instruction.sourceElement is Element
+ ? instruction.sourceElement : null;
+ }
+
+ internalError(Spannable node, reason) {
+ String message = tryToString(reason);
+ reportDiagnosticInternal(
+ createMessage(node, MessageKind.GENERIC, {'text': message}),
+ const <DiagnosticMessage>[],
+ api.Diagnostic.CRASH);
+ throw 'Internal Error: $message';
+ }
+
+ void unhandledExceptionOnElement(Element element) {
+ if (hasCrashed) return;
+ hasCrashed = true;
+ reportDiagnostic(
+ createMessage(element, MessageKind.COMPILER_CRASHED),
+ const <DiagnosticMessage>[],
+ api.Diagnostic.CRASH);
+ pleaseReportCrash();
+ }
+
+ void pleaseReportCrash() {
+ print(
+ MessageTemplate.TEMPLATES[MessageKind.PLEASE_REPORT_THE_CRASH]
+ .message({'buildId': compiler.buildId}));
+ }
+
+ /// Finds the approximate [Element] for [node]. [currentElement] is used as
+ /// the default value.
+ Element elementFromSpannable(Spannable node) {
+ Element element;
+ if (node is Element) {
+ element = node;
+ } else if (node is HInstruction) {
+ element = _elementFromHInstruction(node);
+ } else if (node is MetadataAnnotation) {
+ element = node.annotatedElement;
+ }
+ return element != null ? element : currentElement;
+ }
+
+ void log(message) {
+ Message msg = MessageTemplate.TEMPLATES[MessageKind.GENERIC]
+ .message({'text': '$message'});
+ reportDiagnostic(
+ new DiagnosticMessage(null, null, msg),
+ const <DiagnosticMessage>[],
+ api.Diagnostic.VERBOSE_INFO);
+ }
+
+ String tryToString(object) {
+ try {
+ return object.toString();
+ } catch (_) {
+ return '<exception in toString()>';
+ }
+ }
+
+ onError(Uri uri, error) {
+ try {
+ if (!hasCrashed) {
+ hasCrashed = true;
+ if (error is SpannableAssertionFailure) {
+ reportAssertionFailure(error);
+ } else {
+ reportDiagnostic(
+ createMessage(
+ new SourceSpan(uri, 0, 0),
+ MessageKind.COMPILER_CRASHED),
+ const <DiagnosticMessage>[],
+ api.Diagnostic.CRASH);
+ }
+ pleaseReportCrash();
+ }
+ } catch (doubleFault) {
+ // Ignoring exceptions in exception handling.
+ }
+ throw error;
+ }
+
+ void onCrashInUserCode(String message, exception, stackTrace) {
+ hasCrashed = true;
+ print('$message: ${tryToString(exception)}');
+ print(tryToString(stackTrace));
+ }
+
+ void reportSuppressedMessagesSummary() {
+ if (!options.showPackageWarnings && !options.suppressWarnings) {
+ suppressedWarnings.forEach((Uri uri, SuppressionInfo info) {
+ MessageKind kind = MessageKind.HIDDEN_WARNINGS_HINTS;
+ if (info.warnings == 0) {
+ kind = MessageKind.HIDDEN_HINTS;
+ } else if (info.hints == 0) {
+ kind = MessageKind.HIDDEN_WARNINGS;
+ }
+ MessageTemplate template = MessageTemplate.TEMPLATES[kind];
+ Message message = template.message(
+ {'warnings': info.warnings,
+ 'hints': info.hints,
+ 'uri': uri},
+ options.terseDiagnostics);
+ reportDiagnostic(
+ new DiagnosticMessage(null, null, message),
+ const <DiagnosticMessage>[],
+ api.Diagnostic.HINT);
+ });
+ }
+ }
+}
+
+// TODO(johnniwinther): Move [ResolverTask] here.
+class _CompilerResolution implements Resolution {
+ final Compiler compiler;
+ final Map<Element, ResolutionWorldImpact> _worldImpactCache =
+ <Element, ResolutionWorldImpact>{};
+
+ _CompilerResolution(this.compiler);
+
+ @override
+ DiagnosticReporter get reporter => compiler.reporter;
+
+ @override
+ Parsing get parsing => compiler.parsing;
+
+ @override
+ CoreTypes get coreTypes => compiler.coreTypes;
+
+ @override
+ void registerClass(ClassElement cls) {
+ compiler.world.registerClass(cls);
+ }
+
+ @override
+ void resolveClass(ClassElement cls) {
+ compiler.resolver.resolveClass(cls);
+ }
+
+ @override
+ void resolveTypedef(TypedefElement typdef) {
+ compiler.resolver.resolve(typdef);
+ }
+
+ @override
+ void resolveMetadataAnnotation(MetadataAnnotation metadataAnnotation) {
+ compiler.resolver.resolveMetadataAnnotation(metadataAnnotation);
+ }
+
+ @override
+ FunctionSignature resolveSignature(FunctionElement function) {
+ return compiler.resolver.resolveSignature(function);
+ }
+
+ @override
+ DartType resolveTypeAnnotation(Element element, TypeAnnotation node) {
+ return compiler.resolver.resolveTypeAnnotation(element, node);
+ }
+
+ ResolutionWorldImpact analyzeElement(Element element) {
+ return _worldImpactCache.putIfAbsent(element, () {
+ assert(compiler.parser != null);
+ Node tree = compiler.parser.parse(element);
+ assert(invariant(element, !element.isSynthesized || tree == null));
+ ResolutionWorldImpact worldImpact = compiler.resolver.resolve(element);
+ if (tree != null &&
+ !compiler.analyzeSignaturesOnly &&
+ !reporter.options.suppressWarnings) {
+ // Only analyze nodes with a corresponding [TreeElements].
+ compiler.checker.check(element);
+ }
+ return worldImpact;
+ });
+ }
+
+ @override
+ bool hasBeenResolved(Element element) {
+ return _worldImpactCache.containsKey(element);
+ }
+}
+
+// TODO(johnniwinther): Move [ParserTask], [PatchParserTask], [DietParserTask]
+// and [ScannerTask] here.
+class _CompilerParsing implements Parsing {
+ final Compiler compiler;
+
+ _CompilerParsing(this.compiler);
+
+ @override
+ DiagnosticReporter get reporter => compiler.reporter;
+
+ @override
+ measure(f()) => compiler.parser.measure(f);
+
+ @override
+ void parsePatchClass(ClassElement cls) {
+ compiler.patchParser.measure(() {
+ if (cls.isPatch) {
+ compiler.patchParser.parsePatchClassNode(cls);
+ }
+ });
+ }
+}
diff --git a/pkg/compiler/lib/src/constant_system_dart.dart b/pkg/compiler/lib/src/constant_system_dart.dart
index 940e764..4a15ac9 100644
--- a/pkg/compiler/lib/src/constant_system_dart.dart
+++ b/pkg/compiler/lib/src/constant_system_dart.dart
@@ -434,7 +434,7 @@
// `compiler.coreTypes.typeType` and check the backend specific value in
// [checkConstMapKeysDontOverrideEquals] in 'members.dart'.
return new TypeConstantValue(type,
- compiler.backend.typeImplementation.computeType(compiler));
+ compiler.backend.typeImplementation.computeType(compiler.resolution));
}
bool isInt(ConstantValue constant) => constant.isInt;
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
index 09c6b0d..3d168d3 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
@@ -15,6 +15,8 @@
Compiler;
import '../constants/expressions.dart';
import '../dart_types.dart';
+import '../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import '../diagnostics/invariant.dart' show
invariant;
import '../elements/elements.dart';
@@ -83,7 +85,7 @@
TreeElements elementsMapping = element.resolvedAst.elements;
element = element.implementation;
- return compiler.withCurrentElement(element, () {
+ return reporter.withCurrentElement(element, () {
SourceInformationBuilder sourceInformationBuilder =
sourceInformationStrategy.createBuilderForContext(element);
@@ -160,6 +162,8 @@
this.compiler,
this.sourceInformationBuilder);
+ DiagnosticReporter get reporter => compiler.reporter;
+
String bailoutMessage = null;
@override
@@ -235,14 +239,14 @@
ir.Primitive visitBreakStatement(ast.BreakStatement node) {
if (!irBuilder.buildBreak(elements.getTargetOf(node))) {
- compiler.internalError(node, "'break' target not found");
+ reporter.internalError(node, "'break' target not found");
}
return null;
}
ir.Primitive visitContinueStatement(ast.ContinueStatement node) {
if (!irBuilder.buildContinue(elements.getTargetOf(node))) {
- compiler.internalError(node, "'continue' target not found");
+ reporter.internalError(node, "'continue' target not found");
}
return null;
}
@@ -2065,8 +2069,7 @@
}
@override
- ir.Primitive bulkHandleError(ast.Send node, ErroneousElement error, _) {
- assert(compiler.compilationFailed);
+ ir.Primitive bulkHandleError(ast.Node node, ErroneousElement error, _) {
return irBuilder.buildNullConstant();
}
@@ -2259,7 +2262,7 @@
}
internalError(ast.Node node, String message) {
- compiler.internalError(node, message);
+ reporter.internalError(node, message);
}
@override
@@ -2496,7 +2499,7 @@
ClassElement get nullClass => _compiler.nullClass;
- DartType unaliasType(DartType type) => type.unalias(_compiler);
+ DartType unaliasType(DartType type) => type.unalias(_compiler.resolution);
TypeMask getTypeMaskForForeign(NativeBehavior behavior) {
if (behavior == null) {
@@ -2647,7 +2650,7 @@
break;
default:
- compiler.internalError(element, "Unexpected element type $element");
+ reporter.internalError(element, "Unexpected element type $element");
}
return root;
});
@@ -2906,7 +2909,7 @@
fieldValues);
hasConstructorCall = true;
} else {
- compiler.internalError(initializer,
+ reporter.internalError(initializer,
"Unexpected initializer type $initializer");
}
}
@@ -2916,7 +2919,7 @@
ClassElement superClass = enclosingClass.superclass;
FunctionElement target = superClass.lookupDefaultConstructor();
if (target == null) {
- compiler.internalError(superClass, "No default constructor available.");
+ reporter.internalError(superClass, "No default constructor available.");
}
target = target.implementation;
evaluateConstructorCallFromInitializer(
@@ -3372,7 +3375,7 @@
CallStructure callStructure) {
Element element = backend.isolateHelperLibrary.find(helperName);
if (element == null) {
- compiler.internalError(node,
+ reporter.internalError(node,
'Isolate library and compiler mismatch.');
}
List<ir.Primitive> arguments = translateStaticArguments(argumentList,
diff --git a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
index b9b6b09..4de0cab 100644
--- a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
+++ b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
@@ -43,7 +43,7 @@
final World _classWorld;
ScalarReplacer(dart2js.Compiler compiler)
- : _internalError = compiler.internalError,
+ : _internalError = compiler.reporter.internalError,
_classWorld = compiler.world;
@override
diff --git a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
index 893113f..a84d28d 100644
--- a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
@@ -133,10 +133,7 @@
if (!mask.isValue) return null;
if (mask.isNullable) return null; // e.g. 'true or null'.
ValueTypeMask valueMask = mask;
- var value = valueMask.value;
- // TODO(sra): Why is ValueTypeMask.value not a ConstantValue?
- if (value == false) return new FalseConstantValue();
- if (value == true) return new TrueConstantValue();
+ if (valueMask.value.isBool) return valueMask.value;
// TODO(sra): Consider other values. Be careful with large strings.
return null;
}
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index 383b39f..ecf555d 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -355,7 +355,7 @@
TypeMaskSystem typeSystem,
this._functionCompiler)
: _compiler = compiler,
- _internalError = compiler.internalError,
+ _internalError = compiler.reporter.internalError,
_typeSystem = typeSystem,
_lattice = new ConstantPropagationLattice(
typeSystem,
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index c250be1..bc511e4 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -329,9 +329,6 @@
(_) => diagnosticHandler.enableColors = true),
new OptionHandler('--enable[_-]checked[_-]mode|--checked',
(_) => setCheckedMode(Flags.enableCheckedMode)),
- new OptionHandler(Flags.enableConcreteTypeInference,
- (_) => implyCompilation(
- Flags.enableConcreteTypeInference)),
new OptionHandler(Flags.trustTypeAnnotations,
(_) => setTrustTypeAnnotations(
Flags.trustTypeAnnotations)),
diff --git a/pkg/compiler/lib/src/dart_backend/backend.dart b/pkg/compiler/lib/src/dart_backend/backend.dart
index c29ae0e..85427b1 100644
--- a/pkg/compiler/lib/src/dart_backend/backend.dart
+++ b/pkg/compiler/lib/src/dart_backend/backend.dart
@@ -52,7 +52,7 @@
new Set<ClassElement>();
bool enableCodegenWithErrorsIfSupported(Spannable node) {
- compiler.reportHintMessage(
+ reporter.reportHintMessage(
node,
MessageKind.GENERIC,
{'text': "Generation of code with compile time errors is not "
@@ -108,7 +108,7 @@
stripAsserts = strips.indexOf('asserts') != -1,
constantCompilerTask = new DartConstantTask(compiler),
outputter = new DartOutputter(
- compiler, compiler.outputProvider,
+ compiler.reporter, compiler.outputProvider,
forceStripTypes: strips.indexOf('types') != -1,
multiFile: multiFile,
enableMinification: compiler.enableMinification),
@@ -116,6 +116,11 @@
resolutionCallbacks = new DartResolutionCallbacks(this);
}
+
+ DiagnosticReporter get reporter => compiler.reporter;
+
+ Resolution get resolution => compiler.resolution;
+
bool classNeedsRti(ClassElement cls) => false;
bool methodNeedsRti(FunctionElement function) => false;
@@ -128,7 +133,7 @@
final coreLibrary = compiler.coreLibrary;
for (final name in LITERAL_TYPE_NAMES) {
ClassElement classElement = coreLibrary.findLocal(name);
- classElement.ensureResolved(compiler);
+ classElement.ensureResolved(resolution);
}
// Enqueue the methods that the VM might invoke on user objects because
// we don't trust the resolution to always get these included.
@@ -167,7 +172,7 @@
newTypedefElementCallback,
newClassElementCallback) {
ReferencedElementCollector collector =
- new ReferencedElementCollector(compiler,
+ new ReferencedElementCollector(reporter,
element,
elementAst,
newTypedefElementCallback,
@@ -178,7 +183,7 @@
int totalSize = outputter.assembleProgram(
libraries: compiler.libraryLoader.libraries,
instantiatedClasses: compiler.resolverWorld.directlyInstantiatedClasses,
- resolvedElements: compiler.enqueuer.resolution.resolvedElements,
+ resolvedElements: compiler.enqueuer.resolution.processedElements,
usedTypeLiterals: usedTypeLiterals,
postProcessElementAst: postProcessElementAst,
computeElementAst: computeElementAst,
@@ -214,7 +219,7 @@
'Output total size: $totalOutputSize bytes (${percentage}%)');
}
- log(String message) => compiler.log('[DartBackend] $message');
+ log(String message) => reporter.log('[DartBackend] $message');
@override
Future onLibrariesLoaded(LoadedLibraries loadedLibraries) {
@@ -225,7 +230,7 @@
library.forEachLocalMember((Element element) {
if (element.isClass) {
ClassElement classElement = element;
- classElement.ensureResolved(compiler);
+ classElement.ensureResolved(resolution);
}
});
}
@@ -306,7 +311,7 @@
if (element.isConstructor || element.isStatic) return;
FunctionElement function = element.asFunctionElement();
- element.computeType(compiler);
+ element.computeType(resolution);
Selector selector = new Selector.fromElement(element);
if (selector.isGetter) {
registry.registerDynamicGetter(
@@ -330,7 +335,7 @@
@override
bool enableDeferredLoadingIfSupported(Spannable node, Registry registry) {
// TODO(sigurdm): Implement deferred loading for dart2dart.
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
node, MessageKind.DEFERRED_LIBRARY_DART_2_DART);
return false;
}
@@ -341,6 +346,24 @@
DartResolutionCallbacks(this.backend);
+ @override
+ WorldImpact transformImpact(ResolutionWorldImpact worldImpact) {
+ TransformedWorldImpact transformed =
+ new TransformedWorldImpact(worldImpact);
+ for (DartType typeLiteral in worldImpact.typeLiterals) {
+ onTypeLiteral(typeLiteral, transformed);
+ }
+ for (InterfaceType instantiatedType in worldImpact.instantiatedTypes) {
+ // TODO(johnniwinther): Remove this when dependency tracking is done on
+ // the world impact itself.
+ transformed.registerInstantiation(instantiatedType);
+ backend.registerInstantiatedType(
+ instantiatedType, backend.compiler.enqueuer.resolution, transformed);
+ }
+ return transformed;
+ }
+
+ @override
void onTypeLiteral(DartType type, Registry registry) {
if (type.isInterfaceType) {
backend.usedTypeLiterals.add(type.element);
@@ -385,13 +408,13 @@
* (just to name a few). Retraverse AST to pick those up.
*/
class ReferencedElementCollector extends Visitor {
- final Compiler compiler;
+ final DiagnosticReporter reporter;
final Element element;
final ElementAst elementAst;
final newTypedefElementCallback;
final newClassElementCallback;
- ReferencedElementCollector(this.compiler,
+ ReferencedElementCollector(this.reporter,
this.element,
this.elementAst,
this.newTypedefElementCallback,
@@ -412,7 +435,7 @@
}
void collect() {
- compiler.withCurrentElement(element, () {
+ reporter.withCurrentElement(element, () {
elementAst.ast.accept(this);
});
}
diff --git a/pkg/compiler/lib/src/dart_backend/dart_backend.dart b/pkg/compiler/lib/src/dart_backend/dart_backend.dart
index 9c42e1d..fcfc0c8 100644
--- a/pkg/compiler/lib/src/dart_backend/dart_backend.dart
+++ b/pkg/compiler/lib/src/dart_backend/dart_backend.dart
@@ -19,7 +19,10 @@
import '../common/registry.dart' show
Registry;
import '../common/resolution.dart' show
- ResolutionCallbacks;
+ Resolution,
+ ResolutionCallbacks,
+ ResolutionWorldImpact,
+ TransformedWorldImpact;
import '../common/tasks.dart' show
CompilerTask;
import '../compiler.dart' show
diff --git a/pkg/compiler/lib/src/dart_backend/outputter.dart b/pkg/compiler/lib/src/dart_backend/outputter.dart
index a8240ad..3e6f564 100644
--- a/pkg/compiler/lib/src/dart_backend/outputter.dart
+++ b/pkg/compiler/lib/src/dart_backend/outputter.dart
@@ -18,7 +18,7 @@
/// Output engine for dart2dart that is shared between the dart2js and the
/// analyzer implementations of dart2dart.
class DartOutputter {
- final DiagnosticListener listener;
+ final DiagnosticReporter reporter;
final CompilerOutputProvider outputProvider;
final bool forceStripTypes;
@@ -37,7 +37,7 @@
ElementInfo elementInfo;
// TODO(johnniwinther): Support recompilation.
- DartOutputter(this.listener, this.outputProvider,
+ DartOutputter(this.reporter, this.outputProvider,
{bool this.forceStripTypes: false,
bool this.enableMinification: false,
bool this.multiFile: false});
@@ -97,7 +97,7 @@
}
libraryInfo = LibraryInfo.processLibraries(
- listener, libraries, resolvedElements);
+ reporter, libraries, resolvedElements);
elementInfo = ElementInfoProcessor.createElementInfo(
instantiatedClasses,
@@ -109,7 +109,7 @@
sortElements: sortElements);
PlaceholderCollector collector = collectPlaceholders(
- listener,
+ reporter,
mirrorRenamer,
mainFunction,
libraryInfo,
@@ -124,7 +124,7 @@
isSafeToRemoveTypeDeclarations: isSafeToRemoveTypeDeclarations);
if (outputAst) {
- String code = astOutput(listener, elementInfo);
+ String code = astOutput(reporter, elementInfo);
outputProvider("", "dart")
..add(code)
..close();
@@ -147,14 +147,14 @@
}
static PlaceholderCollector collectPlaceholders(
- DiagnosticListener listener,
+ DiagnosticReporter reporter,
MirrorRenamer mirrorRenamer,
FunctionElement mainFunction,
LibraryInfo libraryInfo,
ElementInfo elementInfo) {
// Create all necessary placeholders.
PlaceholderCollector collector = new PlaceholderCollector(
- listener,
+ reporter,
mirrorRenamer,
libraryInfo.fixedDynamicNames,
elementInfo.elementAsts,
@@ -194,13 +194,13 @@
return placeholderRenamer;
}
- static String astOutput(DiagnosticListener listener,
+ static String astOutput(DiagnosticReporter reporter,
ElementInfo elementInfo) {
// TODO(antonm): Ideally XML should be a separate backend.
// TODO(antonm): obey renames and minification, at least as an option.
StringBuffer sb = new StringBuffer();
outputElement(element) {
- sb.write(element.parseNode(listener).toDebugString());
+ sb.write(element.parseNode(reporter).toDebugString());
}
// Emit XML for AST instead of the program.
@@ -229,7 +229,7 @@
this.userLibraries);
static LibraryInfo processLibraries(
- DiagnosticListener listener,
+ DiagnosticReporter reporter,
Iterable<LibraryElement> libraries,
Iterable<AstElement> resolvedElements) {
Set<String> fixedStaticNames = new Set<String>();
@@ -299,14 +299,14 @@
ClassElement existingEnumClass =
enumClassMap.putIfAbsent(cls.name, () => cls);
if (existingEnumClass != cls) {
- listener.reportError(
- listener.createMessage(
+ reporter.reportError(
+ reporter.createMessage(
cls,
MessageKind.GENERIC,
{'text': "Duplicate enum names are not supported "
"in dart2dart."}),
<DiagnosticMessage>[
- listener.createMessage(
+ reporter.createMessage(
existingEnumClass,
MessageKind.GENERIC,
{'text': "This is the other declaration of '${cls.name}'."}),
diff --git a/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart b/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart
index b15e76a..42c15f9 100644
--- a/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart
+++ b/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart
@@ -170,7 +170,7 @@
}
class PlaceholderCollector extends Visitor {
- final DiagnosticListener listener;
+ final DiagnosticReporter reporter;
final MirrorRenamer mirrorRenamer;
final FunctionElement mainFunction;
final Set<String> fixedMemberNames; // member names which cannot be renamed.
@@ -196,7 +196,7 @@
get currentFunctionScope => functionScopes.putIfAbsent(
topmostEnclosingFunction, () => new FunctionScope());
- PlaceholderCollector(this.listener, this.mirrorRenamer,
+ PlaceholderCollector(this.reporter, this.mirrorRenamer,
this.fixedMemberNames, this.elementAsts,
this.mainFunction);
@@ -258,7 +258,7 @@
currentLocalPlaceholders = new Map<String, LocalPlaceholder>();
if (!(element is ConstructorElement && element.isRedirectingFactory)) {
// Do not visit the body of redirecting factories.
- listener.withCurrentElement(element, () {
+ reporter.withCurrentElement(element, () {
elementNode.accept(this);
});
}
@@ -475,7 +475,7 @@
}
void internalError(String reason, {Node node}) {
- listener.internalError(node, reason);
+ reporter.internalError(node, reason);
}
visit(Node node) => (node == null) ? null : node.accept(this);
diff --git a/pkg/compiler/lib/src/dart_types.dart b/pkg/compiler/lib/src/dart_types.dart
index 1686c5a..353c00a 100644
--- a/pkg/compiler/lib/src/dart_types.dart
+++ b/pkg/compiler/lib/src/dart_types.dart
@@ -6,9 +6,13 @@
import 'dart:math' show min;
-import 'core_types.dart';
+import 'common/resolution.dart' show
+ Resolution;
import 'compiler.dart' show
Compiler;
+import 'core_types.dart';
+import 'diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import 'diagnostics/invariant.dart' show
invariant;
import 'diagnostics/spannable.dart' show
@@ -82,7 +86,7 @@
* function type [: (B) -> A :] and the unaliased type of
* [: Func<int,String> :] is the function type [: (String) -> int :].
*/
- DartType unalias(Compiler compiler);
+ DartType unalias(Resolution resolution);
/**
* If this type is malformed or a generic type created with the wrong number
@@ -215,7 +219,7 @@
return this;
}
- DartType unalias(Compiler compiler) => this;
+ DartType unalias(Resolution resolution) => this;
TypeVariableType get typeVariableOccurrence => this;
@@ -249,7 +253,7 @@
DartType subst(List<DartType> arguments, List<DartType> parameters) => this;
- DartType unalias(Compiler compiler) => this;
+ DartType unalias(Resolution resolution) => this;
accept(DartTypeVisitor visitor, var argument) {
return visitor.visitStatementType(this, argument);
@@ -270,7 +274,7 @@
return this;
}
- DartType unalias(Compiler compiler) => this;
+ DartType unalias(Resolution resolution) => this;
accept(DartTypeVisitor visitor, var argument) {
return visitor.visitVoidType(this, argument);
@@ -320,7 +324,7 @@
// Malformed types are treated as dynamic.
bool get treatAsDynamic => true;
- DartType unalias(Compiler compiler) => this;
+ DartType unalias(Resolution resolution) => this;
accept(DartTypeVisitor visitor, var argument) {
return visitor.visitMalformedType(this, argument);
@@ -487,7 +491,7 @@
return null;
}
- DartType unalias(Compiler compiler) => this;
+ DartType unalias(Resolution resolution) => this;
MemberSignature lookupInterfaceMember(Name name) {
MemberSignature member = element.lookupInterfaceMember(name);
@@ -613,8 +617,6 @@
assert(namedParameters.length == namedParameterTypes.length);
}
-
-
TypeKind get kind => TypeKind.FUNCTION;
DartType getNamedParameterType(String name) {
@@ -658,7 +660,7 @@
return this;
}
- DartType unalias(Compiler compiler) => this;
+ DartType unalias(Resolution resolution) => this;
TypeVariableType get typeVariableOccurrence {
TypeVariableType typeVariableType = returnType.typeVariableOccurrence;
@@ -783,10 +785,10 @@
return new TypedefType(element, newTypeArguments);
}
- DartType unalias(Compiler compiler) {
- element.ensureResolved(compiler);
- element.checkCyclicReference(compiler);
- DartType definition = element.alias.unalias(compiler);
+ DartType unalias(Resolution resolution) {
+ element.ensureResolved(resolution);
+ element.checkCyclicReference(resolution);
+ DartType definition = element.alias.unalias(resolution);
return definition.substByContext(this);
}
@@ -811,7 +813,7 @@
message: 'Alias must be non-null on $element.'));
}
- FunctionType unalias(Compiler compiler) => alias;
+ FunctionType unalias(Resolution resolution) => alias;
}
/**
@@ -828,7 +830,7 @@
TypeKind get kind => TypeKind.DYNAMIC;
- DartType unalias(Compiler compiler) => this;
+ DartType unalias(Resolution resolution) => this;
DartType subst(List<DartType> arguments, List<DartType> parameters) => this;
@@ -949,6 +951,7 @@
extends BaseDartTypeVisitor<bool, DartType> {
final Compiler compiler;
CoreTypes get coreTypes => compiler.coreTypes;
+ Resolution get resolution => compiler.resolution;
AbstractTypeRelation(this.compiler);
@@ -977,7 +980,7 @@
// TODO(johnniwinther): Currently needed since literal types like int,
// double, bool etc. might not have been resolved yet.
- t.element.ensureResolved(compiler);
+ t.element.ensureResolved(resolution);
bool checkTypeArguments(InterfaceType instance, InterfaceType other) {
List<DartType> tTypeArgs = instance.typeArguments;
@@ -1142,8 +1145,8 @@
if (s == coreTypes.objectType) {
return true;
}
- t = t.unalias(compiler);
- s = s.unalias(compiler);
+ t = t.unalias(resolution);
+ s = s.unalias(resolution);
return t.accept(this, s);
}
@@ -1242,6 +1245,10 @@
CoreTypes get coreTypes => compiler.coreTypes;
+ DiagnosticReporter get reporter => compiler.reporter;
+
+ Resolution get resolution => compiler.resolution;
+
Types(Compiler compiler)
: this.compiler = compiler,
this.moreSpecificVisitor = new MoreSpecificVisitor(compiler),
@@ -1541,7 +1548,7 @@
}
}
- compiler.internalError(CURRENT_ELEMENT_SPANNABLE,
+ reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
'No least upper bound computed for $a and $b.');
return null;
}
@@ -1642,8 +1649,8 @@
return computeLeastUpperBoundTypeVariableTypes(a, b);
}
- a = a.unalias(compiler);
- b = b.unalias(compiler);
+ a = a.unalias(resolution);
+ b = b.unalias(resolution);
if (a.treatAsDynamic || b.treatAsDynamic) return const DynamicType();
if (a.isVoid || b.isVoid) return const VoidType();
@@ -1704,7 +1711,7 @@
if (type.isMalformed) {
return const DynamicType();
}
- return type.unalias(compiler);
+ return type.unalias(compiler.resolution);
}
/// Computes the interface type of [type], which is the type that defines
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index 9615406..d0f3120 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -6,6 +6,8 @@
import 'common/backend_api.dart' show
Backend;
+import 'common/resolution.dart' show
+ Resolution;
import 'common/tasks.dart' show
CompilerTask;
import 'compiler.dart' show
@@ -201,7 +203,7 @@
String name =
_importDeferName[new _DeclaredDeferredImport(prefix.deferredImport)];
if (name == null) {
- compiler.internalError(node, "No deferred name for $prefix.");
+ reporter.internalError(node, "No deferred name for $prefix.");
}
return name;
}
@@ -283,7 +285,7 @@
collectTypeDependencies(type.returnType);
} else if (type is TypedefType) {
elements.add(type.element);
- collectTypeDependencies(type.unalias(compiler));
+ collectTypeDependencies(type.unalias(compiler.resolution));
} else if (type is InterfaceType) {
elements.add(type.element);
}
@@ -302,7 +304,7 @@
// TODO(sigurdm): We want to be more specific about this - need a better
// way to query "liveness".
if (astElement is! TypedefElement &&
- !compiler.enqueuer.resolution.hasBeenResolved(astElement)) {
+ !compiler.enqueuer.resolution.hasBeenProcessed(astElement)) {
return;
}
@@ -354,7 +356,7 @@
// to. Static members are not relevant, unless we are processing
// extra dependencies due to mirrors.
void addLiveInstanceMember(Element element) {
- if (!compiler.enqueuer.resolution.hasBeenResolved(element)) return;
+ if (!compiler.enqueuer.resolution.hasBeenProcessed(element)) return;
if (!isMirrorUsage && !element.isInstanceMember) return;
collectDependencies(element.implementation);
}
@@ -714,7 +716,7 @@
Map<String, ImportElement> prefixDeferredImport =
new Map<String, ImportElement>();
for (LibraryElement library in compiler.libraryLoader.libraries) {
- compiler.withCurrentElement(library, () {
+ reporter.withCurrentElement(library, () {
prefixDeferredImport.clear();
usedPrefixes.clear();
// TODO(sigurdm): Make helper getLibraryImportTags when tags is a List
@@ -724,12 +726,12 @@
List<MetadataAnnotation> metadataList = import.metadata;
if (metadataList != null) {
for (MetadataAnnotation metadata in metadataList) {
- metadata.ensureResolved(compiler);
+ metadata.ensureResolved(compiler.resolution);
ConstantValue value =
compiler.constants.getConstantValue(metadata.constant);
Element element = value.getType(compiler.coreTypes).element;
if (element == deferredLibraryClass) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
import, MessageKind.DEFERRED_OLD_SYNTAX);
}
}
@@ -746,7 +748,7 @@
_allDeferredImports[key] = importedLibrary;
if (prefix == null) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
import,
MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX);
} else {
@@ -763,7 +765,7 @@
ImportElement failingImport = (previousDeferredImport != null)
? previousDeferredImport
: import;
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
failingImport.prefix,
MessageKind.DEFERRED_LIBRARY_DUPLICATE_PREFIX);
}
@@ -922,7 +924,7 @@
List<MetadataAnnotation> metadatas = declaration.metadata;
assert(metadatas != null);
for (MetadataAnnotation metadata in metadatas) {
- metadata.ensureResolved(compiler);
+ metadata.ensureResolved(compiler.resolution);
ConstantValue value =
compiler.constants.getConstantValue(metadata.constant);
Element element = value.getType(compiler.coreTypes).element;
diff --git a/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart b/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart
index e2e4d1a..7d624b2 100644
--- a/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart
+++ b/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart
@@ -12,8 +12,35 @@
Element;
import 'messages.dart';
+class DiagnosticOptions {
+
+ /// Emit terse diagnostics without howToFix.
+ final bool terseDiagnostics;
+
+ /// If `true`, warnings and hints not from user code are reported.
+ final bool showPackageWarnings;
+
+ /// If `true`, warnings are not reported.
+ final bool suppressWarnings;
+
+ /// If `true`, warnings cause the compilation to fail.
+ final bool fatalWarnings;
+
+ /// If `true`, hints are not reported.
+ final bool suppressHints;
+
+ const DiagnosticOptions({
+ this.suppressWarnings: false,
+ this.fatalWarnings: false,
+ this.suppressHints: false,
+ this.terseDiagnostics: false,
+ this.showPackageWarnings: false});
+}
+
// TODO(johnniwinther): Rename and cleanup this interface. Add severity enum.
-abstract class DiagnosticListener {
+abstract class DiagnosticReporter {
+ DiagnosticOptions get options => const DiagnosticOptions();
+
// TODO(karlklose): rename log to something like reportInfo.
void log(message);
diff --git a/pkg/compiler/lib/src/diagnostics/messages.dart b/pkg/compiler/lib/src/diagnostics/messages.dart
index 33a6ba3..347b25b 100644
--- a/pkg/compiler/lib/src/diagnostics/messages.dart
+++ b/pkg/compiler/lib/src/diagnostics/messages.dart
@@ -3352,7 +3352,11 @@
MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND:
const MessageTemplate(
MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND,
- "dart:mirrors library is not supported when using this backend."),
+ """
+dart:mirrors library is not supported when using this backend.
+
+Your app imports dart:mirrors via:""""""
+$MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING#{importChain}"""),
MessageKind.CALL_NOT_SUPPORTED_ON_NATIVE_CLASS:
const MessageTemplate(MessageKind.CALL_NOT_SUPPORTED_ON_NATIVE_CLASS,
@@ -3393,6 +3397,10 @@
static const String IMPORT_EXPERIMENTAL_MIRRORS_PADDING = '\n* ';
/// Padding used before and between import chains in the message for
+ /// [MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND].
+ static const String MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING = '\n ';
+
+ /// Padding used before and between import chains in the message for
/// [MessageKind.DISALLOWED_LIBRARY_IMPORT].
static const String DISALLOWED_LIBRARY_IMPORT_PADDING = '\n ';
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 88d1be1..e9d7c05 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -31,6 +31,7 @@
import 'js/js.dart' as jsAst;
import 'universe/universe.dart' show
UniverseSelector;
+import 'info/send_info.dart' show collectSendMeasurements;
class ElementInfoCollector extends BaseElementVisitor<Info, dynamic> {
final Compiler compiler;
@@ -226,6 +227,8 @@
FunctionInfo visitFunctionElement(FunctionElement element, _) {
int size = compiler.dumpInfoTask.sizeOf(element);
+ // TODO(sigmund): consider adding a small info to represent unreachable
+ // code here.
if (size == 0 && !shouldKeep(element)) return null;
String name = element.name;
@@ -317,6 +320,9 @@
}
info.closures = nestedClosures;
result.functions.add(info);
+ if (const bool.fromEnvironment('send_stats')) {
+ info.measurements = collectSendMeasurements(element, compiler);
+ }
return info;
}
@@ -486,16 +492,9 @@
return sb.toString();
}
- void collectInfo() {
- infoCollector = new ElementInfoCollector(compiler)..run();
- }
-
void dumpInfo() {
measure(() {
- if (infoCollector == null) {
- collectInfo();
- }
-
+ infoCollector = new ElementInfoCollector(compiler)..run();
StringBuffer jsonBuffer = new StringBuffer();
dumpInfoJson(jsonBuffer);
compiler.outputProvider('', 'info.json')
@@ -561,7 +560,7 @@
ChunkedConversionSink<Object> sink = encoder.startChunkedConversion(
new StringConversionSink.fromStringSink(buffer));
sink.add(result.toJson());
- compiler.reportInfo(NO_LOCATION_SPANNABLE, MessageKind.GENERIC, {
+ reporter.reportInfo(NO_LOCATION_SPANNABLE, MessageKind.GENERIC, {
'text': "View the dumped .info.json file at "
"https://dart-lang.github.io/dump-info-visualizer"
});
diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart
index d3e5d5d..d10bf45 100644
--- a/pkg/compiler/lib/src/elements/elements.dart
+++ b/pkg/compiler/lib/src/elements/elements.dart
@@ -4,6 +4,8 @@
library elements;
+import '../common/resolution.dart' show
+ Resolution;
import '../compiler.dart' show
Compiler;
import '../constants/constructors.dart';
@@ -425,7 +427,7 @@
/// Unwraps [element] reporting any warnings attached to it, if any.
static Element unwrap(Element element,
- DiagnosticListener listener,
+ DiagnosticReporter listener,
Spannable spannable) {
if (element != null && element.isWarnOnUse) {
WarnOnUseElement wrappedElement = element;
@@ -804,7 +806,7 @@
/// Reports the attached warning and returns the wrapped element.
/// [usageSpannable] is used to report messages on the reference of
/// [wrappedElement].
- Element unwrap(DiagnosticListener listener, Spannable usageSpannable);
+ Element unwrap(DiagnosticReporter listener, Spannable usageSpannable);
}
/// An ambiguous element represents multiple elements accessible by the same
@@ -821,7 +823,7 @@
/// Compute the info messages associated with an error/warning on [context].
List<DiagnosticMessage> computeInfos(
- Element context, DiagnosticListener listener);
+ Element context, DiagnosticReporter listener);
}
// TODO(kasperl): This probably shouldn't be called an element. It's
@@ -967,7 +969,7 @@
/// For instance `(int)->void` for `typedef void F(int)`.
DartType get alias;
- void checkCyclicReference(Compiler compiler);
+ void checkCyclicReference(Resolution resolution);
}
/// An executable element is an element that can hold code.
@@ -1315,7 +1317,7 @@
/// error and calling [computeType] covers that error.
/// This method will go away!
@deprecated
- GenericType computeType(Compiler compiler);
+ GenericType computeType(Resolution resolution);
/**
* The `this type` for this type declaration.
@@ -1355,7 +1357,7 @@
bool get isResolved;
- void ensureResolved(Compiler compiler);
+ void ensureResolved(Resolution resolution);
}
abstract class ClassElement extends TypeDeclarationElement
@@ -1570,7 +1572,7 @@
bool get hasNode;
Node get node;
- MetadataAnnotation ensureResolved(Compiler compiler);
+ MetadataAnnotation ensureResolved(Resolution resolution);
}
/// An [Element] that has a type.
@@ -1582,7 +1584,7 @@
/// error and calling [computeType] covers that error.
/// This method will go away!
@deprecated
- DartType computeType(Compiler compiler);
+ DartType computeType(Resolution resolution);
DartType get type;
}
diff --git a/pkg/compiler/lib/src/elements/modelx.dart b/pkg/compiler/lib/src/elements/modelx.dart
index c576f8d..488c7e1 100644
--- a/pkg/compiler/lib/src/elements/modelx.dart
+++ b/pkg/compiler/lib/src/elements/modelx.dart
@@ -4,6 +4,9 @@
library elements.modelx;
+import '../common/resolution.dart' show
+ Resolution,
+ Parsing;
import '../compiler.dart' show
Compiler;
import '../constants/constant_constructors.dart';
@@ -67,8 +70,8 @@
Modifiers get modifiers => Modifiers.EMPTY;
- Node parseNode(DiagnosticListener listener) {
- listener.internalError(this,
+ Node parseNode(Parsing parsing) {
+ parsing.reporter.internalError(this,
'parseNode not implemented on $this.');
return null;
}
@@ -312,8 +315,7 @@
bool get isRedirectingGenerative => unsupported();
bool get isRedirectingFactory => unsupported();
- computeSignature(compiler) => unsupported();
- computeType(compiler) => unsupported();
+ computeType(Resolution resolution) => unsupported();
bool get hasFunctionSignature => false;
@@ -393,6 +395,10 @@
throw new UnsupportedError("effectiveTargetType=");
}
+ void _computeSignature(Resolution resolution) {
+ throw new UnsupportedError("_computeSignature");
+ }
+
get typeCache {
throw new UnsupportedError("typeCache");
}
@@ -409,14 +415,18 @@
throw new UnsupportedError("immediateRedirectionTarget=");
}
- get functionSignatureCache {
+ get _functionSignatureCache {
throw new UnsupportedError("functionSignatureCache");
}
- set functionSignatureCache(_) {
+ set _functionSignatureCache(_) {
throw new UnsupportedError("functionSignatureCache=");
}
+ set functionSignature(_) {
+ throw new UnsupportedError("functionSignature=");
+ }
+
get nestedClosures {
throw new UnsupportedError("nestedClosures");
}
@@ -468,24 +478,24 @@
: this.wrappedElement = wrappedElement,
super(wrappedElement.name, ElementKind.WARN_ON_USE, enclosingElement);
- Element unwrap(DiagnosticListener listener, Spannable usageSpannable) {
+ Element unwrap(DiagnosticReporter reporter, Spannable usageSpannable) {
var unwrapped = wrappedElement;
if (warning != null) {
Spannable spannable = warning.spannable;
if (spannable == null) spannable = usageSpannable;
- DiagnosticMessage warningMessage = listener.createMessage(
+ DiagnosticMessage warningMessage = reporter.createMessage(
spannable, warning.messageKind, warning.messageArguments);
List<DiagnosticMessage> infos = <DiagnosticMessage>[];
if (info != null) {
Spannable spannable = info.spannable;
if (spannable == null) spannable = usageSpannable;
- infos.add(listener.createMessage(
+ infos.add(reporter.createMessage(
spannable, info.messageKind, info.messageArguments));
}
- listener.reportWarning(warningMessage, infos);
+ reporter.reportWarning(warningMessage, infos);
}
if (unwrapped.isWarnOnUse) {
- unwrapped = unwrapped.unwrap(listener, usageSpannable);
+ unwrapped = unwrapped.unwrap(reporter, usageSpannable);
}
return unwrapped;
}
@@ -535,7 +545,7 @@
}
List<DiagnosticMessage> computeInfos(Element context,
- DiagnosticListener listener) {
+ DiagnosticReporter reporter) {
return const <DiagnosticMessage>[];
}
@@ -559,7 +569,7 @@
List<DiagnosticMessage> computeInfos(
Element context,
- DiagnosticListener listener) {
+ DiagnosticReporter reporter) {
List<DiagnosticMessage> infos = <DiagnosticMessage>[];
Setlet ambiguousElements = flatten();
MessageKind code = (ambiguousElements.length == 1)
@@ -567,10 +577,10 @@
LibraryElementX importer = context.library;
for (Element element in ambiguousElements) {
Map arguments = {'name': element.name};
- infos.add(listener.createMessage(element, code, arguments));
- listener.withCurrentElement(importer, () {
+ infos.add(reporter.createMessage(element, code, arguments));
+ reporter.withCurrentElement(importer, () {
for (ImportElement import in importer.importers.getImports(element)) {
- infos.add(listener.createMessage(
+ infos.add(reporter.createMessage(
import, MessageKind.IMPORTED_HERE, arguments));
}
});
@@ -601,20 +611,20 @@
return contents[name];
}
- void add(Element element, DiagnosticListener listener) {
+ void add(Element element, DiagnosticReporter reporter) {
String name = element.name;
if (element.isAccessor) {
- addAccessor(element, contents[name], listener);
+ addAccessor(element, contents[name], reporter);
} else {
Element existing = contents.putIfAbsent(name, () => element);
if (!identical(existing, element)) {
- listener.reportError(
- listener.createMessage(
+ reporter.reportError(
+ reporter.createMessage(
element,
MessageKind.DUPLICATE_DEFINITION,
{'name': name}),
<DiagnosticMessage>[
- listener.createMessage(
+ reporter.createMessage(
existing,
MessageKind.EXISTING_DEFINITION,
{'name': name}),
@@ -638,15 +648,15 @@
*/
void addAccessor(AccessorElementX accessor,
Element existing,
- DiagnosticListener listener) {
+ DiagnosticReporter reporter) {
void reportError(Element other) {
- listener.reportError(
- listener.createMessage(
+ reporter.reportError(
+ reporter.createMessage(
accessor,
MessageKind.DUPLICATE_DEFINITION,
{'name': accessor.name}),
<DiagnosticMessage>[
- listener.createMessage(
+ reporter.createMessage(
other,
MessageKind.EXISTING_DEFINITION,
{'name': accessor.name}),
@@ -689,7 +699,7 @@
} else {
field.setter = accessor;
}
- add(field, listener);
+ add(field, reporter);
}
}
}
@@ -729,32 +739,32 @@
localMembers.forEach(f);
}
- void addMember(Element element, DiagnosticListener listener) {
+ void addMember(Element element, DiagnosticReporter reporter) {
// Keep a list of top level members.
localMembers = localMembers.prepend(element);
// Provide the member to the library to build scope.
if (enclosingElement.isPatch) {
- implementationLibrary.addMember(element, listener);
+ implementationLibrary.addMember(element, reporter);
} else {
- library.addMember(element, listener);
+ library.addMember(element, reporter);
}
}
- void setPartOf(PartOf tag, DiagnosticListener listener) {
+ void setPartOf(PartOf tag, DiagnosticReporter reporter) {
LibraryElementX library = enclosingElement;
if (library.entryCompilationUnit == this) {
partTag = tag;
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
tag, MessageKind.IMPORT_PART_OF);
return;
}
if (!localMembers.isEmpty) {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
tag, MessageKind.BEFORE_TOP_LEVEL);
return;
}
if (partTag != null) {
- listener.reportWarningMessage(tag, MessageKind.DUPLICATED_PART_OF);
+ reporter.reportWarningMessage(tag, MessageKind.DUPLICATED_PART_OF);
return;
}
partTag = tag;
@@ -763,19 +773,19 @@
if (libraryTag != null) {
String expectedName = libraryTag.name.toString();
if (expectedName != actualName) {
- listener.reportWarningMessage(
+ reporter.reportWarningMessage(
tag.name,
MessageKind.LIBRARY_NAME_MISMATCH,
{'libraryName': expectedName});
}
} else {
- listener.reportWarning(
- listener.createMessage(
+ reporter.reportWarning(
+ reporter.createMessage(
library,
MessageKind.MISSING_LIBRARY_NAME,
{'libraryName': actualName}),
<DiagnosticMessage>[
- listener.createMessage(
+ reporter.createMessage(
tag.name,
MessageKind.THIS_IS_THE_PART_OF_TAG),
]);
@@ -834,7 +844,7 @@
void addImport(Element enclosingElement,
Element element,
ImportElement import,
- DiagnosticListener listener) {
+ DiagnosticReporter reporter) {
LibraryElementX library = enclosingElement.library;
Importers importers = library.importers;
@@ -860,7 +870,7 @@
messageKind,
{'name': name, 'hiddenUri': hiddenUri, 'hidingUri': hidingUri}),
new WrappedMessage(
- listener.spanFromSpannable(import),
+ reporter.spanFromSpannable(import),
MessageKind.IMPORTED_HERE,
{'name': name}),
enclosingElement, hidingElement);
@@ -1062,9 +1072,9 @@
compilationUnits = compilationUnits.prepend(element);
}
- void addTag(LibraryTag tag, DiagnosticListener listener) {
+ void addTag(LibraryTag tag, DiagnosticReporter reporter) {
if (tagsCache != null) {
- listener.internalError(tag,
+ reporter.internalError(tag,
"Library tags for $this have already been computed.");
}
tagsBuilder.addLast(tag);
@@ -1099,17 +1109,17 @@
*/
void addImport(Element element,
ImportElement import,
- DiagnosticListener listener) {
- importScope.addImport(this, element, import, listener);
+ DiagnosticReporter reporter) {
+ importScope.addImport(this, element, import, reporter);
}
- void addMember(Element element, DiagnosticListener listener) {
+ void addMember(Element element, DiagnosticReporter reporter) {
localMembers = localMembers.prepend(element);
- addToScope(element, listener);
+ addToScope(element, reporter);
}
- void addToScope(Element element, DiagnosticListener listener) {
- localScope.add(element, listener);
+ void addToScope(Element element, DiagnosticReporter reporter) {
+ localScope.add(element, reporter);
}
Element localLookup(String elementName) {
@@ -1281,14 +1291,14 @@
Element lookupLocalMember(String memberName) => importScope[memberName];
- DartType computeType(Compiler compiler) => const DynamicType();
+ DartType computeType(Resolution resolution) => const DynamicType();
Token get position => firstPosition;
void addImport(Element element,
ImportElement import,
- DiagnosticListener listener) {
- importScope.addImport(this, element, import, listener);
+ DiagnosticReporter reporter) {
+ importScope.addImport(this, element, import, reporter);
}
accept(ElementVisitor visitor, arg) {
@@ -1336,17 +1346,17 @@
*/
FunctionSignature functionSignature;
- TypedefType computeType(Compiler compiler) {
+ TypedefType computeType(Resolution resolution) {
if (thisTypeCache != null) return thisTypeCache;
- Typedef node = parseNode(compiler);
- setThisAndRawTypes(compiler, createTypeVariables(node.typeParameters));
- ensureResolved(compiler);
+ Typedef node = parseNode(resolution.parsing);
+ setThisAndRawTypes(createTypeVariables(node.typeParameters));
+ ensureResolved(resolution);
return thisTypeCache;
}
- void ensureResolved(Compiler compiler) {
+ void ensureResolved(Resolution resolution) {
if (resolutionState == STATE_NOT_STARTED) {
- compiler.resolver.resolve(this);
+ resolution.resolveTypedef(this);
}
}
@@ -1358,10 +1368,11 @@
return new TypeDeclarationScope(enclosingElement.buildScope(), this);
}
- void checkCyclicReference(Compiler compiler) {
+ void checkCyclicReference(Resolution resolution) {
if (hasBeenCheckedForCycles) return;
- var visitor = new TypedefCyclicVisitor(compiler, this);
- computeType(compiler).accept(visitor, null);
+ TypedefCyclicVisitor visitor =
+ new TypedefCyclicVisitor(resolution.reporter, this);
+ computeType(resolution).accept(visitor, null);
hasBeenCheckedForCycles = true;
}
@@ -1409,11 +1420,11 @@
metadataInternal = metadata;
}
- VariableDefinitions parseNode(Element element, DiagnosticListener listener) {
+ VariableDefinitions parseNode(Element element, Parsing parsing) {
return definitions;
}
- DartType computeType(Element element, Compiler compiler) => type;
+ DartType computeType(Element element, Resolution resolution) => type;
}
abstract class ConstantVariableMixin implements VariableElement {
@@ -1492,10 +1503,10 @@
return initializerCache;
}
- Node parseNode(DiagnosticListener listener) {
+ Node parseNode(Parsing parsing) {
if (definitionsCache != null) return definitionsCache;
- VariableDefinitions definitions = variables.parseNode(this, listener);
+ VariableDefinitions definitions = variables.parseNode(this, parsing);
createDefinitions(definitions);
return definitionsCache;
}
@@ -1535,14 +1546,12 @@
}
}
- DartType computeType(Compiler compiler) {
+ DartType computeType(Resolution resolution) {
if (variables.type != null) return variables.type;
// Call [parseNode] to ensure that [definitionsCache] and [initializerCache]
// are set as a consequence of calling [computeType].
- return compiler.withCurrentElement(this, () {
- parseNode(compiler);
- return variables.computeType(this, compiler);
- });
+ parseNode(resolution.parsing);
+ return variables.computeType(this, resolution);
}
DartType get type {
@@ -1683,7 +1692,7 @@
throw new UnsupportedError("copyWithEnclosing");
}
- DartType computeType(Compiler compiler) => type;
+ DartType computeType(Resolution resolution) => type;
}
/// [Element] for a parameter-like element.
@@ -1699,7 +1708,7 @@
* kept to provide full information about parameter names through the mirror
* system.
*/
- FunctionSignature functionSignatureCache;
+ FunctionSignature _functionSignatureCache;
FormalElementX(ElementKind elementKind,
FunctionTypedElement enclosingElement,
@@ -1714,9 +1723,9 @@
Token get position => identifier.getBeginToken();
- Node parseNode(DiagnosticListener listener) => definitions;
+ Node parseNode(Parsing parsing) => definitions;
- DartType computeType(Compiler compiler) {
+ DartType computeType(Resolution resolution) {
assert(invariant(this, type != null,
message: "Parameter type has not been set for $this."));
return type;
@@ -1729,9 +1738,16 @@
}
FunctionSignature get functionSignature {
- assert(invariant(this, typeCache != null,
- message: "Parameter signature has not been set for $this."));
- return functionSignatureCache;
+ assert(invariant(this, _functionSignatureCache != null,
+ message: "Parameter signature has not been computed for $this."));
+ return _functionSignatureCache;
+ }
+
+ void set functionSignature(FunctionSignature value) {
+ assert(invariant(this, _functionSignatureCache == null,
+ message: "Parameter signature has already been computed for $this."));
+ _functionSignatureCache = value;
+ typeCache = _functionSignatureCache.type;
}
bool get hasNode => true;
@@ -1869,7 +1885,7 @@
throw "internal error: AbstractFieldElement has no type";
}
- Node parseNode(DiagnosticListener listener) {
+ Node parseNode(Parsing parsing) {
throw "internal error: AbstractFieldElement has no node";
}
@@ -1951,7 +1967,7 @@
List<FunctionElement> nestedClosures = new List<FunctionElement>();
- FunctionSignature functionSignatureCache;
+ FunctionSignature _functionSignatureCache;
AsyncMarker asyncMarker = AsyncMarker.SYNC;
@@ -1971,20 +1987,26 @@
&& !isStatic;
}
- bool get hasFunctionSignature => functionSignatureCache != null;
+ bool get hasFunctionSignature => _functionSignatureCache != null;
- FunctionSignature computeSignature(Compiler compiler) {
- if (functionSignatureCache != null) return functionSignatureCache;
- compiler.withCurrentElement(this, () {
- functionSignatureCache = compiler.resolver.resolveSignature(this);
- });
- return functionSignatureCache;
+ void _computeSignature(Resolution resolution) {
+ if (hasFunctionSignature) return;
+ functionSignature = resolution.resolveSignature(this);
}
FunctionSignature get functionSignature {
- assert(invariant(this, functionSignatureCache != null,
+ assert(invariant(this, hasFunctionSignature,
message: "Function signature has not been computed for $this."));
- return functionSignatureCache;
+ return _functionSignatureCache;
+ }
+
+ void set functionSignature(FunctionSignature value) {
+ // TODO(johnniwinther): Strengthen the invariant to `!hasFunctionSignature`
+ // when checked mode checks are not enqueued eagerly.
+ assert(invariant(this, !hasFunctionSignature || type == value.type,
+ message: "Function signature has already been computed for $this."));
+ _functionSignatureCache = value;
+ typeCache = _functionSignatureCache.type;
}
List<ParameterElement> get parameters {
@@ -1995,9 +2017,11 @@
return list;
}
- FunctionType computeType(Compiler compiler) {
+ FunctionType computeType(Resolution resolution) {
if (typeCache != null) return typeCache;
- typeCache = computeSignature(compiler).type;
+ _computeSignature(resolution);
+ assert(invariant(this, typeCache != null,
+ message: "Type cache expected to be set on $this."));
return typeCache;
}
@@ -2043,7 +2067,7 @@
void reuseElement() {
super.reuseElement();
nestedClosures.clear();
- functionSignatureCache = null;
+ _functionSignatureCache = null;
typeCache = null;
}
}
@@ -2114,7 +2138,7 @@
bool get hasNode => true;
- FunctionExpression parseNode(DiagnosticListener listener) => node;
+ FunctionExpression parseNode(Parsing parsing) => node;
Token get position {
// Use the name as position if this is not an unnamed closure.
@@ -2233,15 +2257,8 @@
super("loadLibrary",
Modifiers.EMPTY,
prefix,
- false);
-
- FunctionSignature computeSignature(Compiler compiler) {
- if (functionSignatureCache != null) return functionSignature;
- compiler.withCurrentElement(this, () {
- DartType inner = new FunctionType(this);
- functionSignatureCache = new FunctionSignatureX(type: inner);
- });
- return functionSignatureCache;
+ false) {
+ functionSignature = new FunctionSignatureX(type: new FunctionType(this));
}
bool get isClassMember => false;
@@ -2255,7 +2272,7 @@
// error messages.
Token get position => null;
- FunctionExpression parseNode(DiagnosticListener listener) => null;
+ FunctionExpression parseNode(Parsing parsing) => null;
bool get hasNode => false;
@@ -2275,7 +2292,7 @@
ElementKind.GENERATIVE_CONSTRUCTOR_BODY,
Modifiers.EMPTY,
constructor.enclosingElement) {
- functionSignatureCache = constructor.functionSignature;
+ functionSignature = constructor.functionSignature;
}
bool get hasNode => constructor.hasNode;
@@ -2286,8 +2303,9 @@
bool get isInstanceMember => true;
- FunctionType computeType(Compiler compiler) {
- compiler.internalError(this, '$this.computeType.');
+ FunctionType computeType(Resolution resolution) {
+ DiagnosticReporter reporter = resolution.reporter;
+ reporter.internalError(this, '$this.computeType.');
return null;
}
@@ -2331,11 +2349,11 @@
ElementKind.GENERATIVE_CONSTRUCTOR,
Modifiers.EMPTY,
enclosing) {
- typeCache = new FunctionType.synthesized(enclosingClass.thisType);
- functionSignatureCache = new FunctionSignatureX(type: type);
+ functionSignature = new FunctionSignatureX(
+ type: new FunctionType.synthesized(enclosingClass.thisType));
}
- FunctionExpression parseNode(DiagnosticListener listener) => null;
+ FunctionExpression parseNode(Parsing parsing) => null;
bool get hasNode => false;
@@ -2355,18 +2373,16 @@
}
}
- FunctionSignature computeSignature(compiler) {
- if (functionSignatureCache != null) return functionSignatureCache;
+ void _computeSignature(Resolution resolution) {
+ if (hasFunctionSignature) return;
if (definingConstructor.isErroneous) {
- return functionSignatureCache =
- compiler.objectClass.localLookup('').computeSignature(compiler);
+ functionSignature = new FunctionSignatureX(
+ type: new FunctionType.synthesized(enclosingClass.thisType));
}
// TODO(johnniwinther): Ensure that the function signature (and with it the
// function type) substitutes type variables correctly.
- definingConstructor.computeType(compiler);
- functionSignatureCache = definingConstructor.functionSignature;
- typeCache = definingConstructor.type;
- return functionSignatureCache;
+ definingConstructor.computeType(resolution);
+ functionSignature = definingConstructor.functionSignature;
}
accept(ElementVisitor visitor, arg) {
@@ -2423,7 +2439,7 @@
T createType(List<DartType> typeArguments);
- void setThisAndRawTypes(Compiler compiler, List<DartType> typeParameters) {
+ void setThisAndRawTypes(List<DartType> typeParameters) {
assert(invariant(this, thisTypeCache == null,
message: "This type has already been set on $this."));
assert(invariant(this, rawTypeCache == null,
@@ -2510,23 +2526,25 @@
@override
bool get isEnumClass => false;
- InterfaceType computeType(Compiler compiler) {
+ InterfaceType computeType(Resolution resolution) {
if (isPatch) {
- origin.computeType(compiler);
+ origin.computeType(resolution);
thisTypeCache = origin.thisType;
rawTypeCache = origin.rawType;
} else if (thisTypeCache == null) {
- computeThisAndRawType(compiler, computeTypeParameters(compiler));
+ computeThisAndRawType(
+ resolution, computeTypeParameters(resolution.parsing));
}
return thisTypeCache;
}
- void computeThisAndRawType(Compiler compiler, List<DartType> typeVariables) {
+ void computeThisAndRawType(Resolution resolution,
+ List<DartType> typeVariables) {
if (thisTypeCache == null) {
if (origin == null) {
- setThisAndRawTypes(compiler, typeVariables);
+ setThisAndRawTypes(typeVariables);
} else {
- thisTypeCache = origin.computeType(compiler);
+ thisTypeCache = origin.computeType(resolution);
rawTypeCache = origin.rawType;
}
}
@@ -2537,7 +2555,7 @@
return new InterfaceType(this, typeArguments);
}
- List<DartType> computeTypeParameters(Compiler compiler);
+ List<DartType> computeTypeParameters(Parsing parsing);
bool get isObject {
assert(invariant(this, isResolved,
@@ -2545,14 +2563,15 @@
return supertype == null;
}
- void ensureResolved(Compiler compiler) {
+ void ensureResolved(Resolution resolution) {
if (resolutionState == STATE_NOT_STARTED) {
- compiler.resolver.resolveClass(this);
- compiler.world.registerClass(this);
+ resolution.resolveClass(this);
+ resolution.registerClass(this);
}
}
- void setDefaultConstructor(FunctionElement constructor, Compiler compiler);
+ void setDefaultConstructor(FunctionElement constructor,
+ DiagnosticReporter reporter);
void addBackendMember(Element member) {
// TODO(ngeoffray): Deprecate this method.
@@ -2593,7 +2612,8 @@
* The returned element may not be resolved yet.
*/
ClassElement get superclass {
- assert(supertypeLoadState == STATE_DONE);
+ assert(invariant(this, supertypeLoadState == STATE_DONE,
+ message: "Superclass has not been computed for $this."));
return supertype == null ? null : supertype.element;
}
@@ -2645,18 +2665,18 @@
bool get isMixinApplication => false;
bool get hasLocalScopeMembers => !localScope.isEmpty;
- void addMember(Element element, DiagnosticListener listener) {
+ void addMember(Element element, DiagnosticReporter reporter) {
localMembersCache = null;
localMembersReversed = localMembersReversed.prepend(element);
- addToScope(element, listener);
+ addToScope(element, reporter);
}
- void addToScope(Element element, DiagnosticListener listener) {
+ void addToScope(Element element, DiagnosticReporter reporter) {
if (element.isField && element.name == name) {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
element, MessageKind.MEMBER_USES_CLASS_NAME);
}
- localScope.add(element, listener);
+ localScope.add(element, reporter);
}
Element localLookup(String elementName) {
@@ -2679,13 +2699,14 @@
return false;
}
- void setDefaultConstructor(FunctionElement constructor, Compiler compiler) {
+ void setDefaultConstructor(FunctionElement constructor,
+ DiagnosticReporter reporter) {
// The default constructor, although synthetic, is part of a class' API.
- addMember(constructor, compiler);
+ addMember(constructor, reporter);
}
- List<DartType> computeTypeParameters(Compiler compiler) {
- ClassNode node = parseNode(compiler);
+ List<DartType> computeTypeParameters(Parsing parsing) {
+ ClassNode node = parseNode(parsing);
return createTypeVariables(node.typeParameters);
}
@@ -2719,14 +2740,14 @@
bool get isEnumClass => true;
@override
- Node parseNode(Compiler compiler) => node;
+ Node parseNode(Parsing parsing) => node;
@override
accept(ElementVisitor visitor, arg) {
return visitor.visitEnumClassElement(this, arg);
}
- List<DartType> computeTypeParameters(Compiler compiler) => const <DartType>[];
+ List<DartType> computeTypeParameters(Parsing parsing) => const <DartType>[];
List<FieldElement> get enumValues {
assert(invariant(this, _enumValues != null,
@@ -2756,7 +2777,7 @@
bool get hasNode => true;
@override
- FunctionExpression parseNode(Compiler compiler) => node;
+ FunctionExpression parseNode(Parsing parsing) => node;
}
class EnumMethodElementX extends MethodElementX {
@@ -2772,7 +2793,7 @@
bool get hasNode => true;
@override
- FunctionExpression parseNode(Compiler compiler) => node;
+ FunctionExpression parseNode(Parsing parsing) => node;
}
class EnumFormalElementX extends InitializingFormalElementX {
@@ -2826,7 +2847,7 @@
Token get position => node.getBeginToken();
- Node parseNode(DiagnosticListener listener) => node;
+ Node parseNode(Parsing parsing) => node;
FunctionElement lookupLocalConstructor(String name) {
for (Link<Element> link = constructors;
@@ -2853,24 +2874,25 @@
});
}
- void addMember(Element element, DiagnosticListener listener) {
+ void addMember(Element element, DiagnosticReporter reporter) {
throw new UnsupportedError("Cannot add member to $this.");
}
- void addToScope(Element element, DiagnosticListener listener) {
- listener.internalError(this, 'Cannot add to scope of $this.');
+ void addToScope(Element element, DiagnosticReporter reporter) {
+ reporter.internalError(this, 'Cannot add to scope of $this.');
}
void addConstructor(FunctionElement constructor) {
constructors = constructors.prepend(constructor);
}
- void setDefaultConstructor(FunctionElement constructor, Compiler compiler) {
+ void setDefaultConstructor(FunctionElement constructor,
+ DiagnosticReporter reporter) {
assert(!hasConstructor);
addConstructor(constructor);
}
- List<DartType> computeTypeParameters(Compiler compiler) {
+ List<DartType> computeTypeParameters(Parsing parsing) {
NamedMixinApplication named = node.asNamedMixinApplication();
if (named == null) {
throw new SpannableAssertionFailure(node,
@@ -2955,7 +2977,7 @@
TypeDeclarationElement get typeDeclaration => enclosingElement;
- TypeVariableType computeType(compiler) => type;
+ TypeVariableType computeType(Resolution resolution) => type;
TypeVariableType get type {
assert(invariant(this, typeCache != null,
@@ -2971,7 +2993,7 @@
bool get hasNode => true;
- Node parseNode(compiler) => node;
+ Node parseNode(Parsing parsing) => node;
Token get position => node.getBeginToken();
@@ -3023,18 +3045,18 @@
MetadataAnnotationX([this.resolutionState = STATE_NOT_STARTED]);
- MetadataAnnotation ensureResolved(Compiler compiler) {
+ MetadataAnnotation ensureResolved(Resolution resolution) {
if (annotatedElement.isClass || annotatedElement.isTypedef) {
TypeDeclarationElement typeDeclaration = annotatedElement;
- typeDeclaration.ensureResolved(compiler);
+ typeDeclaration.ensureResolved(resolution);
}
if (resolutionState == STATE_NOT_STARTED) {
- compiler.resolver.resolveMetadataAnnotation(this);
+ resolution.resolveMetadataAnnotation(this);
}
return this;
}
- Node parseNode(DiagnosticListener listener);
+ Node parseNode(Parsing parsing);
String toString() => 'MetadataAnnotation($constant, $resolutionState)';
}
@@ -3045,7 +3067,7 @@
ParameterMetadataAnnotation(Metadata this.metadata);
- Node parseNode(DiagnosticListener listener) => metadata.expression;
+ Node parseNode(Parsing parsing) => metadata.expression;
Token get beginToken => metadata.getBeginToken();
diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
index b6ecbad..212218d 100644
--- a/pkg/compiler/lib/src/enqueue.dart
+++ b/pkg/compiler/lib/src/enqueue.dart
@@ -9,6 +9,8 @@
import 'common/names.dart' show
Identifiers;
+import 'common/resolution.dart' show
+ Resolution;
import 'common/work.dart' show
ItemCompilationContext,
WorkItem;
@@ -25,6 +27,8 @@
import 'dart_types.dart' show
DartType,
InterfaceType;
+import 'diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import 'diagnostics/invariant.dart' show
invariant;
import 'diagnostics/spannable.dart' show
@@ -108,9 +112,15 @@
// TODO(johnniwinther): Collect checked types for checked mode separately to
// support serialization.
- Iterable<DartType> get checkedTypes => const <DartType>[];
+ Iterable<DartType> get isChecks => const <DartType>[];
+
+ Iterable<DartType> get checkedModeChecks => const <DartType>[];
+
+ Iterable<DartType> get asCasts => const <DartType>[];
Iterable<MethodElement> get closurizedFunctions => const <MethodElement>[];
+
+ Iterable<LocalFunctionElement> get closures => const <LocalFunctionElement>[];
}
abstract class Enqueuer {
@@ -141,6 +151,9 @@
this.itemCompilationContextCreator,
this.strategy);
+ // TODO(johnniwinther): Move this to [ResolutionEnqueuer].
+ Resolution get resolution => compiler.resolution;
+
Queue<WorkItem> get queue;
bool get queueIsEmpty => queue.isEmpty;
@@ -149,9 +162,15 @@
QueueFilter get filter => compiler.enqueuerFilter;
+ DiagnosticReporter get reporter => compiler.reporter;
+
/// Returns [:true:] if [member] has been processed by this enqueuer.
bool isProcessed(Element member);
+ bool isClassProcessed(ClassElement cls) => _processedClasses.contains(cls);
+
+ Iterable<ClassElement> get processedClasses => _processedClasses;
+
/**
* Documentation wanted -- johnniwinther
*
@@ -181,10 +200,14 @@
worldImpact.dynamicGetters.forEach(registerDynamicGetter);
worldImpact.dynamicSetters.forEach(registerDynamicSetter);
worldImpact.staticUses.forEach(registerStaticUse);
- // TODO(johnniwinther): Register [worldImpact.instantiatedTypes] when it
- // doesn't require a [Registry].
- worldImpact.checkedTypes.forEach(registerIsCheck);
+ worldImpact.instantiatedTypes.forEach(registerInstantiatedType);
+ worldImpact.isChecks.forEach(registerIsCheck);
+ worldImpact.asCasts.forEach(registerIsCheck);
+ if (compiler.enableTypeAssertions) {
+ worldImpact.checkedModeChecks.forEach(registerIsCheck);
+ }
worldImpact.closurizedFunctions.forEach(registerGetOfStaticFunction);
+ worldImpact.closures.forEach(registerClosure);
}
// TODO(johnniwinther): Remove the need for passing the [registry].
@@ -192,7 +215,7 @@
{bool mirrorUsage: false}) {
task.measure(() {
ClassElement cls = type.element;
- cls.ensureResolved(compiler);
+ cls.ensureResolved(resolution);
universe.registerTypeInstantiation(
type,
byMirrors: mirrorUsage,
@@ -261,7 +284,7 @@
}
} else if (member.isFunction) {
FunctionElement function = member;
- function.computeType(compiler);
+ function.computeType(resolution);
if (function.name == Identifiers.noSuchMethod_) {
registerNoSuchMethod(function);
}
@@ -286,7 +309,7 @@
}
} else if (member.isGetter) {
FunctionElement getter = member;
- getter.computeType(compiler);
+ getter.computeType(resolution);
if (universe.hasInvokedGetter(getter, compiler.world)) {
addToWorkList(getter);
return;
@@ -299,7 +322,7 @@
}
} else if (member.isSetter) {
FunctionElement setter = member;
- setter.computeType(compiler);
+ setter.computeType(resolution);
if (universe.hasInvokedSetter(setter, compiler.world)) {
addToWorkList(setter);
return;
@@ -321,14 +344,23 @@
if (_processedClasses.contains(cls)) return;
// The class must be resolved to compute the set of all
// supertypes.
- cls.ensureResolved(compiler);
+ cls.ensureResolved(resolution);
void processClass(ClassElement superclass) {
if (_processedClasses.contains(superclass)) return;
+ // TODO(johnniwinther): Re-insert this invariant when unittests don't
+ // fail. There is already a similar invariant on the members.
+ /*if (!isResolutionQueue) {
+ assert(invariant(superclass,
+ superclass.isClosure ||
+ compiler.enqueuer.resolution.isClassProcessed(superclass),
+ message: "Class $superclass has not been "
+ "processed in resolution."));
+ }*/
_processedClasses.add(superclass);
recentClasses.add(superclass);
- superclass.ensureResolved(compiler);
+ superclass.ensureResolved(resolution);
superclass.implementation.forEachMember(processInstantiatedClassMember);
if (isResolutionQueue && !superclass.isSynthesized) {
compiler.resolver.checkClass(superclass);
@@ -416,7 +448,7 @@
logEnqueueReflectiveAction(element);
if (element.isTypedef) {
TypedefElement typedef = element;
- typedef.ensureResolved(compiler);
+ typedef.ensureResolved(resolution);
compiler.world.allTypedefs.add(element);
} else if (Elements.isStaticOrTopLevel(element)) {
registerStaticUse(element.declaration);
@@ -450,7 +482,7 @@
if (includeClass) {
logEnqueueReflectiveAction(cls, "register");
ClassElement decl = cls.declaration;
- decl.ensureResolved(compiler);
+ decl.ensureResolved(resolution);
compiler.backend.registerInstantiatedType(
decl.rawType,
this,
@@ -484,7 +516,7 @@
for (ClassElement cls in classes) {
if (compiler.backend.referencedFromMirrorSystem(cls)) {
logEnqueueReflectiveAction(cls);
- cls.ensureResolved(compiler);
+ cls.ensureResolved(resolution);
compiler.backend.registerInstantiatedType(
cls.rawType,
this,
@@ -521,7 +553,7 @@
// have run before tree shaking is disabled and thus everything is
// enqueued.
recents = _processedClasses.toSet();
- compiler.log('Enqueuing everything');
+ reporter.log('Enqueuing everything');
for (LibraryElement lib in compiler.libraryLoader.libraries) {
enqueueReflectiveElementsInLibrary(lib, recents);
}
@@ -700,7 +732,7 @@
void registerClosurizedMember(TypedElement element) {
assert(element.isInstanceMember);
- if (element.computeType(compiler).containsTypeVariables) {
+ if (element.computeType(resolution).containsTypeVariables) {
compiler.backend.registerClosureWithFreeTypeVariables(
element, this, compiler.globalDependencies);
}
@@ -758,7 +790,7 @@
*
* Invariant: Key elements are declaration elements.
*/
- final Set<AstElement> resolvedElements;
+ final Set<AstElement> processedElements;
final Queue<ResolutionWorkItem> queue;
@@ -775,22 +807,22 @@
compiler,
itemCompilationContextCreator,
strategy),
- resolvedElements = new Set<AstElement>(),
+ processedElements = new Set<AstElement>(),
queue = new Queue<ResolutionWorkItem>(),
deferredTaskQueue = new Queue<DeferredTask>();
bool get isResolutionQueue => true;
- bool isProcessed(Element member) => resolvedElements.contains(member);
+ bool isProcessed(Element member) => processedElements.contains(member);
/// Returns `true` if [element] has been processed by the resolution enqueuer.
- bool hasBeenResolved(Element element) {
- return resolvedElements.contains(element.analyzableElement.declaration);
+ bool hasBeenProcessed(Element element) {
+ return processedElements.contains(element.analyzableElement.declaration);
}
- /// Registers [element] as resolved for the resolution enqueuer.
- void registerResolvedElement(AstElement element) {
- resolvedElements.add(element);
+ /// Registers [element] as processed by the resolution enqueuer.
+ void registerProcessedElement(AstElement element) {
+ processedElements.add(element);
}
/**
@@ -811,7 +843,7 @@
assert(invariant(element, element is AnalyzableElement,
message: 'Element $element is not analyzable.'));
- if (hasBeenResolved(element)) return false;
+ if (hasBeenProcessed(element)) return false;
if (queueIsClosed) {
throw new SpannableAssertionFailure(element,
"Resolution work list is closed. Trying to add $element.");
@@ -898,29 +930,17 @@
void emptyDeferredTaskQueue() {
while (!deferredTaskQueue.isEmpty) {
DeferredTask task = deferredTaskQueue.removeFirst();
- compiler.withCurrentElement(task.element, task.action);
+ reporter.withCurrentElement(task.element, task.action);
}
}
- void registerJsCall(Send node, ResolverVisitor resolver) {
- nativeEnqueuer.registerJsCall(node, resolver);
- }
-
- void registerJsEmbeddedGlobalCall(Send node, ResolverVisitor resolver) {
- nativeEnqueuer.registerJsEmbeddedGlobalCall(node, resolver);
- }
-
- void registerJsBuiltinCall(Send node, ResolverVisitor resolver) {
- nativeEnqueuer.registerJsBuiltinCall(node, resolver);
- }
-
void _logSpecificSummary(log(message)) {
- log('Resolved ${resolvedElements.length} elements.');
+ log('Resolved ${processedElements.length} elements.');
}
void forgetElement(Element element) {
super.forgetElement(element);
- resolvedElements.remove(element);
+ processedElements.remove(element);
}
}
diff --git a/pkg/compiler/lib/src/helpers/helpers.dart b/pkg/compiler/lib/src/helpers/helpers.dart
index 3a67978..6b3e787 100644
--- a/pkg/compiler/lib/src/helpers/helpers.dart
+++ b/pkg/compiler/lib/src/helpers/helpers.dart
@@ -15,6 +15,8 @@
import '../../compiler.dart';
import '../compiler.dart' show
Compiler;
+import '../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import '../diagnostics/invariant.dart' show
DEBUG_MODE;
import '../diagnostics/messages.dart' show
@@ -88,7 +90,9 @@
}
/// Function signature of [reportHere].
-typedef ReportHere(Compiler compiler, Spannable node, String debugMessage);
+typedef ReportHere(DiagnosticReporter reporter,
+ Spannable node,
+ String debugMessage);
/// Print a message with a source location.
ReportHere get reportHere {
@@ -97,8 +101,8 @@
}
/// Implementation of [reportHere]
-_reportHere(Compiler compiler, Spannable node, String debugMessage) {
- compiler.reportInfo(node,
+_reportHere(DiagnosticReporter reporter, Spannable node, String debugMessage) {
+ reporter.reportInfo(node,
MessageKind.GENERIC, {'text': 'HERE: $debugMessage'});
}
diff --git a/pkg/compiler/lib/src/helpers/trace.dart b/pkg/compiler/lib/src/helpers/trace.dart
index b928bb6..0889efd 100644
--- a/pkg/compiler/lib/src/helpers/trace.dart
+++ b/pkg/compiler/lib/src/helpers/trace.dart
@@ -60,8 +60,11 @@
}
/// Function signature of [traceAndReport].
-typedef void TraceAndReport(Compiler compiler, Spannable node, String message,
- {bool condition(String stackTrace), int limit,
+typedef void TraceAndReport(DiagnosticReporter reporter,
+ Spannable node,
+ String message,
+ {bool condition(String stackTrace),
+ int limit,
bool throwOnPrint});
/// Calls [reportHere] and [trace] with the same message.
@@ -74,7 +77,9 @@
TraceAndReport get reportAndTrace => traceAndReport;
/// Implementation of [traceAndReport].
-void _traceAndReport(Compiler compiler, Spannable node, String message,
+void _traceAndReport(DiagnosticReporter reporter,
+ Spannable node,
+ String message,
{bool condition(String stackTrace), int limit,
bool throwOnPrint: false}) {
@@ -82,7 +87,7 @@
condition: (String stackTrace) {
bool result = condition != null ? condition(stackTrace) : true;
if (result) {
- reportHere(compiler, node, message);
+ reportHere(reporter, node, message);
}
return result;
});
diff --git a/pkg/compiler/lib/src/inferrer/concrete_types_inferrer.dart b/pkg/compiler/lib/src/inferrer/concrete_types_inferrer.dart
deleted file mode 100644
index 7b0cf06..0000000
--- a/pkg/compiler/lib/src/inferrer/concrete_types_inferrer.dart
+++ /dev/null
@@ -1,2405 +0,0 @@
-// Copyright (c) 2012, 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.
-
-library concrete_types_inferrer;
-
-import 'dart:collection' show
- Queue,
- IterableBase;
-
-import '../native/native.dart' as native;
-import '../closure.dart' show
- BoxFieldElement;
-import '../compiler.dart' show
- Compiler;
-import '../dart_types.dart' show
- DartType,
- TypeKind;
-import '../diagnostics/spannable.dart' show
- Spannable;
-import '../elements/elements.dart';
-import '../tree/tree.dart';
-import '../types/types.dart' show
- FlatTypeMask,
- TypeMask,
- TypesInferrer,
- UnionTypeMask;
-import '../universe/selector.dart' show
- Selector,
- SelectorKind;
-import '../universe/side_effects.dart' show
- SideEffects;
-import '../world.dart' show
- ClassWorld;
-
-import 'inferrer_visitor.dart';
-import 'simple_types_inferrer.dart';
-
-/**
- * A singleton concrete type. More precisely, a [BaseType] is one of the
- * following:
- *
- * - a non-asbtract class like [:int:] or [:Uri:] (but not [:List:])
- * - the null base type
- * - the unknown base type
- */
-abstract class BaseType {
- bool isClass();
- bool isUnknown();
- bool isNull();
-}
-
-/**
- * A non-asbtract class like [:int:] or [:Uri:] (but not [:List:]).
- */
-class ClassBaseType implements BaseType {
- final ClassElement element;
-
- ClassBaseType(this.element);
-
- bool operator ==(var other) {
- if (identical(this, other)) return true;
- if (other is! ClassBaseType) return false;
- return element == other.element;
- }
- int get hashCode => element.hashCode;
- String toString() {
- return element == null ? 'toplevel' : element.name;
- }
- bool isClass() => true;
- bool isUnknown() => false;
- bool isNull() => false;
-}
-
-/**
- * The unknown base type.
- */
-class UnknownBaseType implements BaseType {
- const UnknownBaseType();
- bool operator ==(BaseType other) => other is UnknownBaseType;
- int get hashCode => 0;
- bool isClass() => false;
- bool isUnknown() => true;
- bool isNull() => false;
- toString() => "unknown";
-}
-
-/**
- * The null base type.
- */
-class NullBaseType implements BaseType {
- const NullBaseType();
- bool operator ==(BaseType other) => identical(other, this);
- int get hashCode => 1;
- bool isClass() => false;
- bool isUnknown() => false;
- bool isNull() => true;
- toString() => "null";
-}
-
-/**
- * An immutable set of base types like [:{int, bool}:], or the unknown concrete
- * type.
- */
-abstract class ConcreteType {
- ConcreteType();
-
- factory ConcreteType.empty(int maxConcreteTypeSize,
- BaseTypes classBaseTypes) {
- return new UnionType(maxConcreteTypeSize, classBaseTypes,
- new Set<BaseType>());
- }
-
- /**
- * The singleton constituted of the unknown base type is the unknown concrete
- * type.
- */
- factory ConcreteType.singleton(int maxConcreteTypeSize,
- BaseTypes classBaseTypes,
- BaseType baseType) {
- if (baseType.isUnknown() || maxConcreteTypeSize < 1) {
- return const UnknownConcreteType();
- }
- Set<BaseType> singletonSet = new Set<BaseType>();
- singletonSet.add(baseType);
- return new UnionType(maxConcreteTypeSize, classBaseTypes, singletonSet);
- }
-
- factory ConcreteType.unknown() {
- return const UnknownConcreteType();
- }
-
- ConcreteType union(ConcreteType other);
- ConcreteType intersection(ConcreteType other);
- ConcreteType refine(Selector selector, Compiler compiler);
- bool isUnknown();
- bool isEmpty();
- Set<BaseType> get baseTypes;
-
- /**
- * Returns the unique element of [:this:] if [:this:] is a singleton, null
- * otherwise.
- */
- ClassElement getUniqueType();
-}
-
-/**
- * The unkown concrete type: it is absorbing for the union.
- */
-class UnknownConcreteType implements ConcreteType {
- const UnknownConcreteType();
- bool isUnknown() => true;
- bool isEmpty() => false;
- bool operator ==(ConcreteType other) => identical(this, other);
- Set<BaseType> get baseTypes =>
- new Set<BaseType>.from([const UnknownBaseType()]);
- int get hashCode => 0;
- ConcreteType union(ConcreteType other) => this;
- ConcreteType intersection(ConcreteType other) => other;
- ConcreteType refine(Selector selector, Compiler compiler) => this;
- ClassElement getUniqueType() => null;
- toString() => "unknown";
-}
-
-/**
- * An immutable set of base types, like [: {int, bool} :].
- */
-class UnionType implements ConcreteType {
- final int maxConcreteTypeSize;
- final BaseTypes classBaseTypes;
-
- final Set<BaseType> baseTypes;
-
- /**
- * The argument should NOT be mutated later. Do not call directly, use
- * ConcreteType.singleton instead.
- */
- UnionType(this.maxConcreteTypeSize, this.classBaseTypes, this.baseTypes);
-
- bool isUnknown() => false;
- bool isEmpty() => baseTypes.isEmpty;
-
- bool operator ==(ConcreteType other) {
- if (other is! UnionType) return false;
- if (baseTypes.length != other.baseTypes.length) return false;
- return baseTypes.containsAll(other.baseTypes);
- }
-
- int get hashCode {
- int result = 1;
- for (final baseType in baseTypes) {
- result = 31 * result + baseType.hashCode;
- }
- return result;
- }
-
- ConcreteType _simplify(Set<BaseType> baseTypes) {
- // normalize all flavors of ints to int
- // TODO(polux): handle different ints better
- if (baseTypes.contains(classBaseTypes.uint31Type)) {
- baseTypes.remove(classBaseTypes.uint31Type);
- baseTypes.add(classBaseTypes.intBaseType);
- }
- if (baseTypes.contains(classBaseTypes.uint32Type)) {
- baseTypes.remove(classBaseTypes.uint32Type);
- baseTypes.add(classBaseTypes.intBaseType);
- }
- if (baseTypes.contains(classBaseTypes.positiveIntType)) {
- baseTypes.remove(classBaseTypes.positiveIntType);
- baseTypes.add(classBaseTypes.intBaseType);
- }
- // normalize {int, float}, {int, num} or {float, num} into num
- // TODO(polux): generalize this to all types when we extend the concept of
- // "concrete type" to other abstract classes than num
- if (baseTypes.contains(classBaseTypes.numBaseType) ||
- (baseTypes.contains(classBaseTypes.intBaseType)
- && baseTypes.contains(classBaseTypes.doubleBaseType))) {
- baseTypes.remove(classBaseTypes.intBaseType);
- baseTypes.remove(classBaseTypes.doubleBaseType);
- baseTypes.add(classBaseTypes.numBaseType);
- }
-
- // widen big types to dynamic
- return baseTypes.length > maxConcreteTypeSize
- ? const UnknownConcreteType()
- : new UnionType(maxConcreteTypeSize, classBaseTypes, baseTypes);
- }
-
- ConcreteType union(ConcreteType other) {
- if (other.isUnknown()) {
- return const UnknownConcreteType();
- }
- UnionType otherUnion = other; // cast
- Set<BaseType> newBaseTypes = new Set<BaseType>.from(baseTypes);
- newBaseTypes.addAll(otherUnion.baseTypes);
- return _simplify(newBaseTypes);
- }
-
- ConcreteType intersection(ConcreteType other) {
- if (other.isUnknown()) {
- return this;
- }
- Set<BaseType> thisBaseTypes = new Set<BaseType>.from(baseTypes);
- Set<BaseType> otherBaseTypes = new Set<BaseType>.from(other.baseTypes);
- return _simplify(thisBaseTypes.intersection(otherBaseTypes));
- }
-
- ConcreteType refine(Selector selector, Compiler compiler) {
- Set<BaseType> newBaseTypes = new Set<BaseType>();
- for (BaseType baseType in baseTypes) {
- if (baseType.isClass()) {
- ClassBaseType classBaseType = baseType;
- if (classBaseType.element.lookupByName(selector.memberName) != null) {
- newBaseTypes.add(baseType);
- }
- } else {
- newBaseTypes.add(baseType);
- }
- }
- return _simplify(newBaseTypes);
- }
-
- ClassElement getUniqueType() {
- if (baseTypes.length == 1) {
- var iterator = baseTypes.iterator;
- iterator.moveNext();
- BaseType uniqueBaseType = iterator.current;
- if (uniqueBaseType.isClass()) {
- ClassBaseType uniqueClassType = uniqueBaseType;
- return uniqueClassType.element;
- }
- }
- return null;
- }
-
- String toString() => baseTypes.toString();
-}
-
-class ConcreteTypeSystem extends TypeSystem<ConcreteType> {
- final Compiler compiler;
- final ConcreteTypesInferrer inferrer;
- final BaseTypes baseTypes;
-
- final ConcreteType nullType;
- final ConcreteType _intType;
- final ConcreteType _uint31Type;
- final ConcreteType _uint32Type;
- final ConcreteType _positiveIntType;
- final ConcreteType _doubleType;
- final ConcreteType _numType;
- final ConcreteType _boolType;
- final ConcreteType _functionType;
- final ConcreteType _listType;
- final ConcreteType _constListType;
- final ConcreteType _fixedListType;
- final ConcreteType _growableListType;
- final ConcreteType _mapType;
- final ConcreteType _constMapType;
- final ConcreteType _stringType;
-
- final ConcreteType dynamicType;
- final ConcreteType typeType;
- final ConcreteType nonNullEmptyType;
-
- ConcreteTypeSystem.internal(ConcreteTypesInferrer inferrer,
- BaseTypes baseTypes,
- ConcreteType singleton(BaseType baseType))
- : this.compiler = inferrer.compiler
- , this.inferrer = inferrer
- , this.baseTypes = baseTypes
- , this._constListType = singleton(baseTypes.constMapBaseType)
- , this._constMapType = singleton(baseTypes.constMapBaseType)
- , this._doubleType = singleton(baseTypes.doubleBaseType)
- , this._fixedListType = singleton(baseTypes.fixedListBaseType)
- , this._functionType = singleton(baseTypes.functionBaseType)
- , this._growableListType = singleton(baseTypes.growableListBaseType)
- , this._intType = singleton(baseTypes.intBaseType)
- , this._listType = singleton(baseTypes.listBaseType)
- , this._mapType = singleton(baseTypes.mapBaseType)
- , this._numType = singleton(baseTypes.numBaseType)
- , this._boolType = singleton(baseTypes.boolBaseType)
- , this._stringType = singleton(baseTypes.stringBaseType)
- , this.typeType = singleton(baseTypes.typeBaseType)
- , this.dynamicType = const UnknownConcreteType()
- , this.nullType = singleton(const NullBaseType())
- , this.nonNullEmptyType = new ConcreteType.empty(
- inferrer.compiler.maxConcreteTypeSize, baseTypes)
- // TODO(polux): have better types here
- , this._uint31Type = singleton(baseTypes.intBaseType)
- , this._uint32Type = singleton(baseTypes.intBaseType)
- , this._positiveIntType = singleton(baseTypes.intBaseType);
-
- factory ConcreteTypeSystem(ConcreteTypesInferrer inferrer) {
- Compiler compiler = inferrer.compiler;
- BaseTypes baseTypes = new BaseTypes(compiler);
- return new ConcreteTypeSystem.internal(
- inferrer,
- baseTypes,
- (BaseType baseType) => new ConcreteType.singleton(
- compiler.maxConcreteTypeSize, baseTypes, baseType));
- }
-
- @override
- ConcreteType get intType {
- inferrer.augmentSeenClasses(compiler.backend.intImplementation);
- return _intType;
- }
-
- @override
- ConcreteType get uint31Type {
- inferrer.augmentSeenClasses(compiler.backend.uint31Implementation);
- return _uint31Type;
- }
-
- @override
- ConcreteType get uint32Type {
- inferrer.augmentSeenClasses(compiler.backend.uint32Implementation);
- return _uint32Type;
- }
-
- @override
- ConcreteType get positiveIntType {
- inferrer.augmentSeenClasses(compiler.backend.positiveIntImplementation);
- return _positiveIntType;
- }
-
- @override
- ConcreteType get doubleType {
- inferrer.augmentSeenClasses(compiler.backend.doubleImplementation);
- return _doubleType;
- }
-
- @override
- ConcreteType get numType {
- inferrer.augmentSeenClasses(compiler.backend.numImplementation);
- return _numType;
- }
-
- @override
- ConcreteType get boolType {
- inferrer.augmentSeenClasses(compiler.backend.boolImplementation);
- return _boolType;
- }
-
- @override
- ConcreteType get functionType {
- inferrer.augmentSeenClasses(compiler.backend.functionImplementation);
- return _functionType;
- }
-
- @override
- ConcreteType get listType {
- inferrer.augmentSeenClasses(compiler.backend.listImplementation);
- return _listType;
- }
-
- @override
- ConcreteType get constListType {
- inferrer.augmentSeenClasses(compiler.backend.constListImplementation);
- return _constListType;
- }
-
- @override
- ConcreteType get fixedListType {
- inferrer.augmentSeenClasses(compiler.backend.fixedListImplementation);
- return _fixedListType;
- }
-
- @override
- ConcreteType get growableListType {
- inferrer.augmentSeenClasses(compiler.backend.growableListImplementation);
- return _growableListType;
- }
-
- @override
- ConcreteType get mapType {
- inferrer.augmentSeenClasses(compiler.backend.mapImplementation);
- return _mapType;
- }
-
- @override
- ConcreteType get constMapType {
- inferrer.augmentSeenClasses(compiler.backend.constMapImplementation);
- return _constMapType;
- }
-
- @override
- ConcreteType get stringType {
- inferrer.augmentSeenClasses(compiler.backend.stringImplementation);
- return _stringType;
- }
-
- @override
- ConcreteType stringLiteralType(_) {
- inferrer.augmentSeenClasses(compiler.backend.stringImplementation);
- return _stringType;
- }
-
- @override
- ConcreteType boolLiteralType(_) {
- inferrer.augmentSeenClasses(compiler.backend.boolImplementation);
- return _boolType;
- }
-
- /**
- * Returns the [TypeMask] representation of [baseType].
- */
- TypeMask baseTypeToTypeMask(BaseType baseType) {
- if (baseType.isUnknown()) {
- return const DynamicTypeMask();
- } else if (baseType.isNull()) {
- return new TypeMask.empty();
- } else {
- ClassBaseType classBaseType = baseType;
- final element = classBaseType.element;
- assert(element != null);
- if (element == compiler.backend.numImplementation) {
- return new TypeMask.nonNullSubclass(compiler.backend.numImplementation,
- compiler.world);
- } else if (element == compiler.backend.intImplementation) {
- return new TypeMask.nonNullSubclass(compiler.backend.intImplementation,
- compiler.world);
- } else if (!compiler.world.isInstantiated(element.declaration)) {
- return new TypeMask.nonNullSubtype(element.declaration, compiler.world);
- } else {
- return new TypeMask.nonNullExact(element.declaration, compiler.world);
- }
- }
- }
-
- /**
- * Returns the [TypeMask] representation of [concreteType].
- */
- TypeMask concreteTypeToTypeMask(ConcreteType concreteType) {
- if (concreteType == null) return null;
- TypeMask typeMask = new TypeMask.nonNullEmpty();
- for (BaseType baseType in concreteType.baseTypes) {
- TypeMask baseMask = baseTypeToTypeMask(baseType);
- if (baseMask == const DynamicTypeMask()) return baseMask;
- typeMask = typeMask.union(baseMask, compiler.world);
- }
- return typeMask;
- }
-
- @override
- ConcreteType addPhiInput(Local variable,
- ConcreteType phiType,
- ConcreteType newType) {
- return computeLUB(phiType, newType);
- }
-
- @override
- ConcreteType allocateDiamondPhi(ConcreteType firstInput,
- ConcreteType secondInput) {
- return computeLUB(firstInput, secondInput);
- }
-
- @override
- ConcreteType allocatePhi(Node node, Local variable, ConcreteType inputType) {
- return inputType;
- }
-
- @override
- ConcreteType allocateLoopPhi(Node node, Local variable,
- ConcreteType inputType) {
- return inputType;
- }
-
- @override
- ConcreteType computeLUB(ConcreteType firstType, ConcreteType secondType) {
- if (firstType == null) {
- return secondType;
- } else if (secondType == null) {
- return firstType;
- } else {
- return firstType.union(secondType);
- }
- }
-
- // Implementation Inspired by
- // type_graph_inferrer.TypeInformationSystem.narrowType
- @override
- ConcreteType narrowType(ConcreteType type,
- DartType annotation,
- {bool isNullable: true}) {
- if (annotation.treatAsDynamic) return type;
- if (annotation.isVoid) return nullType;
- if (annotation.element == compiler.objectClass) return type;
- ConcreteType otherType;
- if (annotation.isTypedef || annotation.isFunctionType) {
- otherType = functionType;
- } else if (annotation.isTypeVariable) {
- // TODO(polux): Narrow to bound.
- return type;
- } else {
- assert(annotation.isInterfaceType);
- otherType = nonNullSubtype(annotation.element);
- }
- if (isNullable) otherType = otherType.union(nullType);
- if (type == null) return otherType;
- return type.intersection(otherType);
- }
-
- @override
- TypeMask newTypedSelector(ConcreteType receiver, TypeMask mask) {
- return concreteTypeToTypeMask(receiver);
- }
-
- @override
- ConcreteType nonNullEmpty() {
- return nonNullEmptyType;
- }
-
- @override
- ConcreteType nonNullExact(ClassElement cls) {
- return nonNullSubtype(cls);
- }
-
- /**
- * Helper method for [nonNullSubtype] and [nonNullSubclass].
- */
- ConcreteType nonNullSubX(ClassElement cls,
- Iterable<ClassElement> extractor(ClassElement cls)) {
- if (cls == compiler.objectClass) {
- return dynamicType;
- }
- ConcreteType result = nonNullEmptyType;
- void registerClass(ClassElement element) {
- if (!element.isAbstract) {
- result = result.union(
- new ConcreteType.singleton(compiler.maxConcreteTypeSize,
- baseTypes,
- new ClassBaseType(element)));
- inferrer.augmentSeenClasses(element);
- }
- }
- registerClass(cls);
- Iterable<ClassElement> subtypes = extractor(cls);
- subtypes.forEach(registerClass);
- return result;
- }
-
- @override
- ConcreteType nonNullSubclass(ClassElement cls) {
- return nonNullSubX(cls, compiler.world.strictSubclassesOf);
- }
-
- @override
- ConcreteType nonNullSubtype(ClassElement cls) {
- return nonNullSubX(cls, compiler.world.strictSubtypesOf);
- }
-
- @override
- ConcreteType simplifyPhi(Node node,
- Local variable,
- ConcreteType phiType) {
- return phiType;
- }
-
- @override
- bool selectorNeedsUpdate(ConcreteType type, TypeMask mask) {
- return concreteTypeToTypeMask(type) != mask;
- }
-
- @override
- ConcreteType refineReceiver(Selector selector,
- TypeMask mask,
- ConcreteType receiverType,
- bool isConditional) {
- if (isConditional) {
- throw new UnimplementedError("isConditional in concrete type inferrer");
- }
- return receiverType.refine(selector, compiler);
- }
-
- @override
- bool isNull(ConcreteType type) {
- return (type.baseTypes.length == 1) && (type.baseTypes.first.isNull());
- }
-
- @override
- ConcreteType allocateClosure(Node node, Element element) {
- // TODO(polux): register closure here instead of in visitor?
- return functionType;
- }
-
- @override
- ConcreteType allocateList(ConcreteType type,
- Node node,
- Element enclosing,
- [ConcreteType elementType, int length]) {
- if (elementType != null) {
- inferrer.augmentListElementType(elementType);
- }
- return type;
- }
-
- @override
- ConcreteType allocateMap(ConcreteType type,
- Node node,
- Element element,
- [List<ConcreteType> keyTypes,
- List<ConcreteType> valueTypes]) {
- // TODO(polux): treat maps the same way we treat lists
- return type;
- }
-
- @override
- ConcreteType getConcreteTypeFor(TypeMask mask) {
- if (mask.isUnion) {
- UnionTypeMask union = mask;
- return union.disjointMasks.fold(
- nonNullEmptyType,
- (type1, type2) => type1.union(getConcreteTypeFor(type2)));
- } else {
- FlatTypeMask flat = mask;
- ConcreteType result;
- if (flat.isEmpty) {
- result = nonNullEmptyType;
- } else if (flat.isExact) {
- result = nonNullExact(flat.base);
- } else if (flat.isSubclass) {
- result = nonNullSubclass(flat.base);
- } else if (flat.isSubtype) {
- result = nonNullSubtype(flat.base);
- } else {
- throw new ArgumentError("unexpected mask");
- }
- return flat.isNullable ? result.union(nullType) : result;
- }
- }
-}
-
-/**
- * The cartesian product of concrete types: an iterable of
- * [ConcreteTypesEnvironment]s.
- */
-class ConcreteTypeCartesianProduct
- extends IterableBase<ConcreteTypesEnvironment> {
- final ConcreteTypesInferrer inferrer;
- final ClassElement typeOfThis;
- final Map<Element, ConcreteType> concreteTypes;
- ConcreteTypeCartesianProduct(this.inferrer, this.typeOfThis,
- this.concreteTypes);
- Iterator get iterator => concreteTypes.isEmpty
- ? [new ConcreteTypesEnvironment(typeOfThis)].iterator
- : new ConcreteTypeCartesianProductIterator(inferrer, typeOfThis,
- concreteTypes);
- String toString() => this.toList().toString();
-}
-
-/**
- * An helper class for [ConcreteTypeCartesianProduct].
- */
-class ConcreteTypeCartesianProductIterator
- implements Iterator<ConcreteTypesEnvironment> {
- final ConcreteTypesInferrer inferrer;
- final ClassElement classOfThis;
- final Map<Element, ConcreteType> concreteTypes;
- final Map<Element, BaseType> nextValues;
- final Map<Element, Iterator> state;
- int size = 1;
- int counter = 0;
- ConcreteTypesEnvironment _current;
-
- ConcreteTypeCartesianProductIterator(this.inferrer, this.classOfThis,
- Map<Element, ConcreteType> concreteTypes)
- : this.concreteTypes = concreteTypes,
- nextValues = new Map<Element, BaseType>(),
- state = new Map<Element, Iterator>() {
- if (concreteTypes.isEmpty) {
- size = 0;
- return;
- }
- for (final e in concreteTypes.keys) {
- final baseTypes = concreteTypes[e].baseTypes;
- size *= baseTypes.length;
- }
- }
-
- ConcreteTypesEnvironment get current => _current;
-
- ConcreteTypesEnvironment takeSnapshot() {
- Map<Element, ConcreteType> result = new Map<Element, ConcreteType>();
- nextValues.forEach((k, v) {
- result[k] = inferrer.singletonConcreteType(v);
- });
- return new ConcreteTypesEnvironment.of(result, classOfThis);
- }
-
- bool moveNext() {
- if (counter >= size) {
- _current = null;
- return false;
- }
- for (final key in concreteTypes.keys) {
- final iterator = state[key];
- if (iterator != null && iterator.moveNext()) {
- nextValues[key] = state[key].current;
- break;
- }
- Iterator newIterator = concreteTypes[key].baseTypes.iterator;
- state[key] = newIterator;
- newIterator.moveNext();
- nextValues[key] = newIterator.current;
- }
- counter++;
- _current = takeSnapshot();
- return true;
- }
-}
-
-/**
- * [BaseType] Constants.
- */
-class BaseTypes {
- final ClassBaseType intBaseType;
- final ClassBaseType doubleBaseType;
- final ClassBaseType numBaseType;
- final ClassBaseType boolBaseType;
- final ClassBaseType stringBaseType;
- final ClassBaseType listBaseType;
- final ClassBaseType growableListBaseType;
- final ClassBaseType fixedListBaseType;
- final ClassBaseType constListBaseType;
- final ClassBaseType mapBaseType;
- final ClassBaseType constMapBaseType;
- final ClassBaseType objectBaseType;
- final ClassBaseType typeBaseType;
- final ClassBaseType functionBaseType;
- final ClassBaseType uint31Type;
- final ClassBaseType uint32Type;
- final ClassBaseType positiveIntType;
-
- BaseTypes(Compiler compiler) :
- intBaseType = new ClassBaseType(compiler.backend.intImplementation),
- doubleBaseType = new ClassBaseType(compiler.backend.doubleImplementation),
- numBaseType = new ClassBaseType(compiler.backend.numImplementation),
- boolBaseType = new ClassBaseType(compiler.backend.boolImplementation),
- stringBaseType = new ClassBaseType(compiler.backend.stringImplementation),
- listBaseType = new ClassBaseType(compiler.backend.listImplementation),
- growableListBaseType =
- new ClassBaseType(compiler.backend.growableListImplementation),
- fixedListBaseType =
- new ClassBaseType(compiler.backend.fixedListImplementation),
- constListBaseType =
- new ClassBaseType(compiler.backend.constListImplementation),
- mapBaseType = new ClassBaseType(compiler.backend.mapImplementation),
- constMapBaseType =
- new ClassBaseType(compiler.backend.constMapImplementation),
- objectBaseType = new ClassBaseType(compiler.objectClass),
- typeBaseType = new ClassBaseType(compiler.backend.typeImplementation),
- functionBaseType =
- new ClassBaseType(compiler.backend.functionImplementation),
- uint31Type = new ClassBaseType(compiler.backend.uint31Implementation),
- uint32Type = new ClassBaseType(compiler.backend.uint32Implementation),
- positiveIntType =
- new ClassBaseType(compiler.backend.positiveIntImplementation);
-}
-
-/**
- * An immutable mapping from method arguments to [ConcreteTypes].
- */
-class ConcreteTypesEnvironment {
- final Map<Element, ConcreteType> environment;
- final ClassElement classOfThis;
-
- ConcreteTypesEnvironment([this.classOfThis]) :
- environment = new Map<Element, ConcreteType>();
- ConcreteTypesEnvironment.of(this.environment, this.classOfThis);
-
- ConcreteType lookupType(Element element) => environment[element];
-
- bool operator ==(ConcreteTypesEnvironment other) {
- if (other is! ConcreteTypesEnvironment) return false;
- if (classOfThis != other.classOfThis) return false;
- if (environment.length != other.environment.length) return false;
- for (Element key in environment.keys) {
- if (!other.environment.containsKey(key)
- || (environment[key] != other.environment[key])) {
- return false;
- }
- }
- return true;
- }
-
- int get hashCode {
- int result = (classOfThis != null) ? classOfThis.hashCode : 1;
- environment.forEach((element, concreteType) {
- result = 31 * (31 * result + element.hashCode) + concreteType.hashCode;
- });
- return result;
- }
-
- String toString() => "{ this: $classOfThis, env: $environment }";
-}
-
-class ClosureEnvironment {
- ConcreteType thisType;
- final LocalsHandler locals;
-
- ClosureEnvironment(this.thisType, this.locals);
-
- bool mergeLocals(LocalsHandler newLocals) {
- assert((locals == null) == (newLocals == null));
- return (locals != null) ? locals.mergeAll([newLocals]) : false;
- }
-
- /// Returns true if changed.
- bool merge(ConcreteType thisType, LocalsHandler locals) {
- ConcreteType oldThisType = this.thisType;
- if (this.thisType == null) {
- this.thisType = thisType;
- } else if (thisType != null) {
- this.thisType = this.thisType.union(thisType);
- }
- return mergeLocals(locals) || (this.thisType != oldThisType);
- }
-
- toString() => "ClosureEnvironment { thisType = $thisType, locals = ... }";
-}
-
-/**
- * A set of encoutered closures.
- */
-class Closures {
- final Compiler compiler;
- final Map<FunctionElement, ClosureEnvironment> closures =
- new Map<FunctionElement, ClosureEnvironment>();
-
- Closures(this.compiler);
-
- /// Returns true if the environment of the closure has changed.
- bool put(FunctionElement closure,
- ConcreteType typeOfThis,
- LocalsHandler locals) {
- ClosureEnvironment oldEnvironent = closures[closure];
- if (oldEnvironent == null) {
- closures[closure] = new ClosureEnvironment(typeOfThis, locals);
- return true;
- } else {
- return oldEnvironent.merge(typeOfThis, locals);
- }
- }
-
- ClosureEnvironment getEnvironmentOrNull(FunctionElement function) {
- return closures[function];
- }
-
- Iterable<FunctionElement> get functionElements => closures.keys;
-
- bool contains(FunctionElement function) => closures.containsKey(function);
-
- String toString() => closures.toString();
-}
-
-/**
- * A work item for the type inference queue.
- */
-class InferenceWorkItem {
- Element method;
- ConcreteTypesEnvironment environment;
- InferenceWorkItem(this.method, this.environment);
-
- toString() => "{ method = $method, environment = $environment }";
-
- bool operator ==(other) {
- return (other is InferenceWorkItem)
- && method == other.method
- && environment == other.environment;
- }
-
- int get hashCode => 31 * method.hashCode + environment.hashCode;
-}
-
-/**
- * A sentinel type mask class representing the dynamicType. It is absorbing
- * for [:ConcreteTypesEnvironment.typeMaskUnion:].
- */
-class DynamicTypeMask implements TypeMask {
- const DynamicTypeMask();
-
- String toString() => 'sentinel type mask';
-
- TypeMask nullable() {
- throw new UnsupportedError("");
- }
-
- TypeMask nonNullable() {
- throw new UnsupportedError("");
- }
-
- bool get isEmpty {
- throw new UnsupportedError("");
- }
-
- bool get isNullable {
- throw new UnsupportedError("");
- }
-
- bool get isExact {
- throw new UnsupportedError("");
- }
-
- bool get isUnion {
- throw new UnsupportedError("");
- }
-
- bool get isContainer {
- throw new UnsupportedError("");
- }
-
- bool get isMap {
- throw new UnsupportedError("");
- }
-
- bool get isDictionary {
- throw new UnsupportedError("");
- }
-
- bool get isForwarding {
- throw new UnsupportedError("");
- }
-
- bool get isValue {
- throw new UnsupportedError("");
- }
-
- bool containsOnlyInt(ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool containsOnlyDouble(ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool containsOnlyNum(ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool containsOnlyBool(ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool containsOnlyString(ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool containsOnly(ClassElement element) {
- throw new UnsupportedError("");
- }
-
- bool satisfies(ClassElement cls, ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool contains(ClassElement type, ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool containsAll(ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- ClassElement singleClass(ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- TypeMask union(TypeMask other, ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- TypeMask intersection(TypeMask other, ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool canHit(Element element, Selector selector, ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- Element locateSingleElement(Selector selector,
- TypeMask mask,
- Compiler compiler) {
- throw new UnsupportedError("");
- }
-
- bool needsNoSuchMethodHandling(Selector selector, ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool isInMask(TypeMask other, ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool containsMask(TypeMask other, ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-}
-
-class WorkQueue {
- final Queue<InferenceWorkItem> queue = new Queue<InferenceWorkItem>();
-
- void add(InferenceWorkItem workItem) {
- if (!queue.contains(workItem)) {
- queue.addLast(workItem);
- }
- }
-
- InferenceWorkItem remove() {
- return queue.removeFirst();
- }
-
- bool get isEmpty => queue.isEmpty;
-}
-
-/**
- * A task which conservatively infers a [ConcreteType] for each sub expression
- * of the program. The entry point is [analyzeMain].
- */
-class ConcreteTypesInferrer
- extends InferrerEngine<ConcreteType, ConcreteTypeSystem>
- implements TypesInferrer {
-
- final String name = "Type inferrer";
-
- /**
- * When true, the string literal [:"__dynamic_for_test":] is inferred to
- * have the unknown type.
- */
- // TODO(polux): get rid of this hack once we have a natural way of inferring
- // the unknown type.
- bool testMode = false;
-
- // --- constants ---
-
- /**
- * Constants representing builtin base types. Initialized by [initialize]
- * and not by the constructor because the compiler elements are not yet
- * populated.
- */
- BaseTypes baseTypes;
-
- /** The associated type system */
- ConcreteTypeSystem types;
-
- /**
- * Constant representing [:ConcreteList#[]:] where [:ConcreteList:] is the
- * concrete implementation of lists for the selected backend.
- */
- FunctionElement listIndex;
-
- /**
- * Constant representing [:ConcreteList#[]=:] where [:ConcreteList:] is the
- * concrete implementation of lists for the selected backend.
- */
- FunctionElement listIndexSet;
-
- /**
- * Constant representing [:ConcreteList#add:] where [:ConcreteList:] is the
- * concrete implementation of lists for the selected backend.
- */
- FunctionElement listAdd;
-
- /**
- * Constant representing [:ConcreteList#removeAt:] where [:ConcreteList:] is
- * the concrete implementation of lists for the selected backend.
- */
- FunctionElement listRemoveAt;
-
- /**
- * Constant representing [:ConcreteList#insert:] where [:ConcreteList:] is
- * the concrete implementation of lists for the selected backend.
- */
- FunctionElement listInsert;
-
- /**
- * Constant representing [:ConcreteList#removeLast:] where [:ConcreteList:] is
- * the concrete implementation of lists for the selected backend.
- */
- FunctionElement listRemoveLast;
-
- /** Constant representing [:List():]. */
- FunctionElement listConstructor;
-
- /** The unknown concrete type */
- final ConcreteType unknownConcreteType;
-
- /** The empty concrete type */
- ConcreteType emptyConcreteType;
-
- /** The null concrete type */
- ConcreteType nullConcreteType;
-
- // --- state updated by the inference ---
-
- /**
- * A map from (function x argument base types) to their inferred concrete
- * type. Another way of seeing [methodToTemplates] is as a map from
- * [FunctionElement]s to "templates" in the sense of "The Cartesian Product
- * Algorithm - Simple and Precise Type Inference of Parametric Polymorphism"
- * by Ole Agesen.
- */
- // TODO(polux): build a better abstraction, like Closures
- final Map<FunctionElement, Map<ConcreteTypesEnvironment, ConcreteType>>
- methodToTemplates;
-
- /** The set of encountered closures. */
- final Closures closures;
-
- /** A map from expressions to their inferred concrete types. */
- final Map<Node, ConcreteType> inferredTypes;
-
- /** A map from fields to their inferred concrete types. */
- final Map<Element, ConcreteType> inferredFieldTypes;
-
- /**
- * [:callers[f]:] is the list of [:f:]'s possible callers or fields
- * whose initialization is a call to [:f:].
- */
- final Map<FunctionElement, Set<Element>> callers;
-
- /**
- * [:readers[field]:] is the list of [:field:]'s possible readers or fields
- * whose initialization is a read of [:field:].
- */
- final Map<Element, Set<Element>> fieldReaders;
-
- /**
- * [:readers[local]:] is the list of [:local:]'s possible readers.
- */
- final Map<Local, Set<FunctionElement>> capturedLocalsReaders;
-
- /// The set of classes encountered so far.
- final Set<ClassElement> seenClasses;
-
- /**
- * A map from selector names to callers of methods with this name on objects
- * of unknown inferred type.
- */
- final Map<String, Set<FunctionElement>> dynamicCallers;
-
- /** The inferred type of elements stored in Lists. */
- ConcreteType listElementType;
-
- /**
- * A map from parameters to their inferred concrete types. It plays no role
- * in the analysis, it is write only.
- */
- final Map<VariableElement, ConcreteType> inferredParameterTypes;
-
- /**
- * A map from selectors to their inferred type masks, indexed by the mask
- * of the receiver. It plays no role in the analysis, it is write only.
- */
- final Map<Selector, Map<TypeMask, TypeMask>> inferredSelectorTypes;
-
- /** The work queue consumed by [analyzeMain]. */
- final WorkQueue workQueue;
-
- /** The item being worked on. */
- InferenceWorkItem currentWorkItem;
-
- ConcreteTypesInferrer(Compiler compiler)
- : methodToTemplates = new Map<FunctionElement,
- Map<ConcreteTypesEnvironment, ConcreteType>>(),
- closures = new Closures(compiler),
- inferredTypes = new Map<Node, ConcreteType>(),
- inferredFieldTypes = new Map<Element, ConcreteType>(),
- inferredParameterTypes = new Map<VariableElement, ConcreteType>(),
- workQueue = new WorkQueue(),
- callers = new Map<FunctionElement, Set<Element>>(),
- fieldReaders = new Map<Element, Set<Element>>(),
- capturedLocalsReaders = new Map<Local, Set<FunctionElement>>(),
- seenClasses = new Set<ClassElement>(),
- dynamicCallers = new Map<String, Set<FunctionElement>>(),
- inferredSelectorTypes = new Map<Selector, Map<TypeMask, TypeMask>>(),
- unknownConcreteType = new ConcreteType.unknown(),
- super(compiler, null);
-
- /* Initialization code that cannot be run in the constructor because it
- * requires the compiler's elements to be populated.
- */
- void initialize() {
- baseTypes = new BaseTypes(compiler);
- types = new ConcreteTypeSystem(this);
- ClassElement jsArrayClass = baseTypes.listBaseType.element;
- listIndex = jsArrayClass.lookupMember('[]');
- listIndexSet = jsArrayClass.lookupMember('[]=');
- listAdd = jsArrayClass.lookupMember('add');
- listRemoveAt = jsArrayClass.lookupMember('removeAt');
- listInsert = jsArrayClass.lookupMember('insert');
- listRemoveLast =
- jsArrayClass.lookupMember('removeLast');
- listConstructor =
- compiler.listClass.lookupDefaultConstructor();
- if (listConstructor != null) {
- listConstructor = listConstructor.implementation;
- }
- emptyConcreteType = new ConcreteType.empty(compiler.maxConcreteTypeSize,
- baseTypes);
- nullConcreteType = singletonConcreteType(const NullBaseType());
- listElementType = emptyConcreteType;
- }
-
- // --- utility methods ---
-
- /** Creates a singleton concrete type containing [baseType]. */
- ConcreteType singletonConcreteType(BaseType baseType) {
- return new ConcreteType.singleton(compiler.maxConcreteTypeSize, baseTypes,
- baseType);
- }
-
- /**
- * Computes the union of [mask1] and [mask2] where [mask1] and [mask2] are
- * possibly equal to [: DynamicTypeMask.instance :].
- */
- TypeMask typeMaskUnion(TypeMask mask1, TypeMask mask2) {
- if (mask1 == const DynamicTypeMask() || mask2 == const DynamicTypeMask()) {
- return const DynamicTypeMask();
- }
- return mask1.union(mask2, compiler.world);
- }
-
- /**
- * Returns all the members matching [selector].
- */
- Set<Element> getMembersBySelector(Selector selector) {
- // TODO(polux): memoize?
- Set<Element> result = new Set<Element>();
- for (ClassElement cls in seenClasses) {
- Element elem = cls.lookupByName(selector.memberName);
- if (elem != null) {
- result.add(elem.implementation);
- }
- }
- return result;
- }
-
- /**
- * Returns all the subtypes of [cls], [cls] included.
- */
- Set<ClassElement> getReflexiveSubtypesOf(ClassElement cls) {
- // TODO(polux): memoize?
- Set<ClassElement> result = new Set<ClassElement>()..add(cls);
- for (ClassElement candidate in seenClasses) {
- if (compiler.world.isSubtypeOf(candidate, cls)) {
- result.add(candidate);
- }
- }
- return result;
- }
-
- /**
- * Sets the concrete type associated to [node] to the union of the inferred
- * concrete type so far and of [type].
- */
- void augmentInferredType(Node node, ConcreteType type) {
- ConcreteType currentType = inferredTypes[node];
- inferredTypes[node] =
- (currentType == null) ? type : currentType.union(type);
- }
-
- /**
- * Sets the concrete type associated to [selector] to the union of the
- * inferred concrete type so far and of [returnType].
- *
- * Precondition: [:(typeOfThis != null) && (returnType != null):]
- */
- void augmentInferredSelectorType(Selector selector,
- TypeMask typeOfThis,
- TypeMask returnType) {
- assert(returnType != null);
- assert(typeOfThis != null);
-
- Map<TypeMask, TypeMask> currentMap = inferredSelectorTypes.putIfAbsent(
- selector, () => new Map<TypeMask, TypeMask>());
- TypeMask currentReturnType = currentMap[typeOfThis];
- currentMap[typeOfThis] = (currentReturnType == null)
- ? returnType
- : typeMaskUnion(currentReturnType, returnType);
- }
-
- /**
- * Returns the current inferred concrete type of [field].
- */
- ConcreteType getFieldType(Selector selector, Element field) {
- ensureFieldInitialized(field);
- ConcreteType result = inferredFieldTypes[field];
- result = (result == null) ? emptyConcreteType : result;
- if (selector != null) {
- Element enclosing = field.enclosingElement;
- if (enclosing.isClass) {
- ClassElement cls = enclosing;
- TypeMask receiverMask = new TypeMask.exact(cls.declaration, classWorld);
- TypeMask resultMask = types.concreteTypeToTypeMask(result);
- augmentInferredSelectorType(selector, receiverMask, resultMask);
- }
- }
- return result;
- }
-
- /**
- * Sets the concrete type associated to [field] to the union of the inferred
- * concrete type so far and of [type].
- */
- void augmentFieldType(Element field, ConcreteType type) {
- ensureFieldInitialized(field);
- ConcreteType oldType = inferredFieldTypes[field];
- ConcreteType newType = (oldType != null) ? oldType.union(type) : type;
- if (oldType != newType) {
- inferredFieldTypes[field] = newType;
- invalidateReaders(field);
- }
- }
-
- /** Augment the inferred type of elements stored in Lists. */
- void augmentListElementType(ConcreteType type) {
- ConcreteType newType = listElementType.union(type);
- if (newType != listElementType) {
- invalidateCallers(listIndex);
- listElementType = newType;
- }
- }
-
- /**
- * Sets the concrete type associated to [parameter] to the union of the
- * inferred concrete type so far and of [type].
- */
- void augmentParameterType(VariableElement parameter, ConcreteType type) {
- ConcreteType oldType = inferredParameterTypes[parameter];
- inferredParameterTypes[parameter] =
- (oldType == null) ? type : oldType.union(type);
- }
-
- /** Augments the set of classes encountered so far. */
- void augmentSeenClasses(ClassElement cls) {
- if (!seenClasses.contains(cls)) {
- seenClasses.add(cls);
- cls.forEachMember((_, Element member) {
- Set<FunctionElement> functions = dynamicCallers[member.name];
- if (functions != null) {
- functions.forEach(invalidate);
- }
- }, includeSuperAndInjectedMembers: true);
- }
- }
-
- /**
- * Add [caller] to the set of [callee]'s callers.
- */
- void addCaller(FunctionElement callee, Element caller) {
- callers.putIfAbsent(callee, () => new Set<Element>())
- .add(caller);
- }
-
- /**
- * Add [caller] to the set of [callee]'s dynamic callers.
- */
- void addDynamicCaller(Selector callee, FunctionElement caller) {
- dynamicCallers
- .putIfAbsent(callee.name, () => new Set<FunctionElement>())
- .add(caller);
- }
-
- /**
- * Add [reader] to the set of [field]'s readers.
- */
- void addFieldReader(Element field, Element reader) {
- fieldReaders.putIfAbsent(field, () => new Set<Element>())
- .add(reader);
- }
-
- /**
- * Add [reader] to the set of [local]'s readers.
- */
- void addCapturedLocalReader(Local local, FunctionElement reader) {
- capturedLocalsReaders.putIfAbsent(local, () => new Set<FunctionElement>())
- .add(reader);
- }
-
- /**
- * Add a closure to the set of seen closures. Invalidate callers if
- * the set of locals has changed.
- */
- void addClosure(FunctionElement closure,
- ConcreteType typeOfThis,
- LocalsHandler locals) {
- if (closures.put(closure, typeOfThis, locals)) {
- invalidateCallers(closure);
- }
- }
-
- /**
- * Invalidate all callers of [function].
- */
- void invalidateCallers(FunctionElement function) {
- Set<Element> methodCallers = callers[function];
- if (methodCallers != null) {
- methodCallers.forEach(invalidate);
- }
- }
-
- /**
- * Invalidate all reader of [field].
- */
- void invalidateReaders(Element field) {
- Set<Element> readers = fieldReaders[field];
- if (readers != null) {
- readers.forEach(invalidate);
- }
- }
-
- /**
- * Add all templates of [methodOrField] to the workqueue.
- */
- void invalidate(Element methodOrField) {
- if (methodOrField.isField) {
- workQueue.add(new InferenceWorkItem(
- methodOrField, new ConcreteTypesEnvironment()));
- } else {
- Map<ConcreteTypesEnvironment, ConcreteType> templates =
- methodToTemplates[methodOrField];
- if (templates != null) {
- templates.forEach((environment, _) {
- workQueue.add(
- new InferenceWorkItem(methodOrField, environment));
- });
- }
- }
- }
-
- /**
- * Returns the template associated to [function] or create an empty template
- * for [function] return it.
- */
- // TODO(polux): encapsulate this in an abstraction for templates
- Map<ConcreteTypesEnvironment, ConcreteType>
- getTemplatesOrEmpty(FunctionElement function) {
- return methodToTemplates.putIfAbsent(
- function,
- () => new Map<ConcreteTypesEnvironment, ConcreteType>());
- }
-
- // -- methods of types.TypesInferrer (interface with the backend) --
-
- /** Get the inferred concrete type of [node]. */
- @override
- TypeMask getTypeOfNode(Element owner, Node node) {
- TypeMask result = types.concreteTypeToTypeMask(inferredTypes[node]);
- return (result == const DynamicTypeMask()) ? null : result;
- }
-
- /** Get the inferred concrete type of [element]. */
- @override
- TypeMask getTypeOfElement(Element element) {
- final result = types.concreteTypeToTypeMask(typeOfElement(element));
- return (result == const DynamicTypeMask()) ? null : result;
- }
-
- /**
- * Get the inferred concrete return type of [element]. A null return value
- * means "I don't know".
- */
- @override
- TypeMask getReturnTypeOfElement(Element element) {
- assert(element is FunctionElement);
- Map<ConcreteTypesEnvironment, ConcreteType> templates =
- methodToTemplates[element];
- if (templates == null) return null;
- ConcreteType returnType = emptyConcreteType;
- templates.forEach((_, concreteType) {
- returnType = returnType.union(concreteType);
- });
- TypeMask result = types.concreteTypeToTypeMask(returnType);
- return (result == const DynamicTypeMask()) ? null : result;
- }
-
- /**
- * Get the inferred concrete type of [selector]. A null return value means
- * "I don't know".
- */
- @override
- TypeMask getTypeOfSelector(Selector selector, TypeMask mask) {
- Map<TypeMask, TypeMask> candidates = inferredSelectorTypes[selector];
- if (candidates == null) {
- return null;
- }
- TypeMask result = new TypeMask.nonNullEmpty();
- if (mask == null) {
- candidates.forEach((TypeMask receiverType, TypeMask returnType) {
- result = typeMaskUnion(result, returnType);
- });
- } else {
- candidates.forEach((TypeMask receiverType, TypeMask returnType) {
- TypeMask intersection = receiverType.intersection(mask, compiler.world);
- if (!intersection.isEmpty || intersection.isNullable) {
- result = typeMaskUnion(result, returnType);
- }
- });
- }
- return result == const DynamicTypeMask() ? null : result;
- }
-
- @override
- void clear() {
- throw new UnsupportedError("clearing is not yet implemented");
- }
-
- @override
- bool isCalledOnce(Element element) {
- // Never called by SimpleTypeInferrer.
- throw new UnsupportedError("");
- }
-
- @override
- bool isFixedArrayCheckedForGrowable(Node node) {
- // Never called by SimpleTypeInferrer.
- throw new UnsupportedError("");
- }
-
- // --- analysis ---
-
- /**
- * Returns the concrete type returned by [function] given arguments of
- * concrete types [argumentsTypes]. If [function] is static then
- * [receiverType] must be null, else [function] must be a member of
- * [receiverType].
- */
- ConcreteType getSendReturnType(Selector selector,
- FunctionElement function,
- ClassElement receiverType,
- ArgumentsTypes<ConcreteType> argumentsTypes) {
- assert(function != null);
-
- ConcreteType result = emptyConcreteType;
- Map<Element, ConcreteType> argumentMap =
- associateArguments(function, argumentsTypes);
- // if the association failed, this send will never occur or will fail
- if (argumentMap == null) {
- return emptyConcreteType;
- }
-
- argumentMap.forEach(augmentParameterType);
- ConcreteTypeCartesianProduct product =
- new ConcreteTypeCartesianProduct(this, receiverType, argumentMap);
- for (ConcreteTypesEnvironment environment in product) {
- result = result.union(
- getMonomorphicSendReturnType(function, environment));
- }
-
- if (selector != null && receiverType != null) {
- // TODO(polux): generalize to any abstract class if we ever handle other
- // abstract classes than num.
- TypeMask receiverMask =
- (receiverType == compiler.backend.numImplementation
- || receiverType == compiler.backend.intImplementation)
- ? new TypeMask.nonNullSubclass(receiverType.declaration,
- compiler.world)
- : new TypeMask.nonNullExact(receiverType.declaration,
- compiler.world);
- TypeMask resultMask = types.concreteTypeToTypeMask(result);
- augmentInferredSelectorType(selector, receiverMask, resultMask);
- }
-
- return result;
- }
-
- /**
- * Given a method signature and a list of concrete types, builds a map from
- * formals to their corresponding concrete types. Returns null if the
- * association is impossible (for instance: too many arguments).
- */
- Map<Element, ConcreteType> associateArguments(
- FunctionElement function,
- ArgumentsTypes<ConcreteType> argumentsTypes) {
- final Map<Element, ConcreteType> result = new Map<Element, ConcreteType>();
- final FunctionSignature signature = function.functionSignature;
-
- // guard 1: too many arguments
- if (argumentsTypes.length > signature.parameterCount) {
- return null;
- }
- // guard 2: not enough arguments
- if (argumentsTypes.positional.length < signature.requiredParameterCount) {
- return null;
- }
- // guard 3: too many positional arguments
- if (signature.optionalParametersAreNamed &&
- argumentsTypes.positional.length > signature.requiredParameterCount) {
- return null;
- }
-
- handleLeftoverOptionalParameter(ParameterElement parameter) {
- Expression initializer = parameter.initializer;
- result[parameter] = (initializer == null)
- ? nullConcreteType
- : analyzeDefaultValue(function, initializer);
- }
-
- final Iterator<ConcreteType> remainingPositionalArguments =
- argumentsTypes.positional.iterator;
- // we attach each positional parameter to its corresponding positional
- // argument
- for (Element requiredParameter in signature.requiredParameters) {
- // we know moveNext() succeeds because of guard 2
- remainingPositionalArguments.moveNext();
- result[requiredParameter] = remainingPositionalArguments.current;
- }
- if (signature.optionalParametersAreNamed) {
- // we build a map out of the remaining named parameters
- final Map<String, Element> leftOverNamedParameters =
- new Map<String, Element>();
- for (Element namedParameter in signature.optionalParameters) {
- leftOverNamedParameters[namedParameter.name] = namedParameter;
- }
- // we attach the named arguments to their corresponding optional
- // parameters
- for (String source in argumentsTypes.named.keys) {
- final ConcreteType concreteType = argumentsTypes.named[source];
- final Element namedParameter = leftOverNamedParameters[source];
- // unexisting or already used named parameter
- if (namedParameter == null) return null;
- result[namedParameter] = concreteType;
- leftOverNamedParameters.remove(source);
- }
- leftOverNamedParameters.forEach((_, Element parameter) {
- handleLeftoverOptionalParameter(parameter);
- });
- } else { // optional parameters are positional
- // we attach the remaining positional arguments to their corresponding
- // optional parameters
- Iterator<Element> remainingOptionalParameters =
- signature.optionalParameters.iterator;
- while (remainingPositionalArguments.moveNext()) {
- // we know this is true because of guard 1
- remainingOptionalParameters.moveNext();
- final Element optionalParameter = remainingOptionalParameters.current;
- result[optionalParameter] = remainingPositionalArguments.current;
- }
- while (remainingOptionalParameters.moveNext()) {
- handleLeftoverOptionalParameter(remainingOptionalParameters.current);
- }
- }
- return result;
- }
-
- ConcreteType getMonomorphicSendReturnType(
- FunctionElement function,
- ConcreteTypesEnvironment environment) {
- Map<ConcreteTypesEnvironment, ConcreteType> template =
- getTemplatesOrEmpty(function);
- ConcreteType type = template[environment];
- ConcreteType specialType = getSpecialCaseReturnType(function, environment);
- if (type != null) {
- return specialType != null ? specialType : type;
- } else {
- workQueue.add(new InferenceWorkItem(function, environment));
- return specialType != null ? specialType : emptyConcreteType;
- }
- }
-
- /**
- * Handles external methods that cannot be cached because they depend on some
- * other state of [ConcreteTypesInferrer] like [:List#[]:] and
- * [:List#[]=:]. Returns null if [function] and [environment] don't form a
- * special case
- */
- ConcreteType getSpecialCaseReturnType(FunctionElement function,
- ConcreteTypesEnvironment environment) {
- // Handles int + int, double + double, int - int, ...
- // We cannot compare function to int#+, int#-, etc. because int and double
- // don't override these methods. So for 1+2, getSpecialCaseReturnType will
- // be invoked with function = num#+. We use environment.typeOfThis instead.
- ClassElement cls = environment.classOfThis;
- List<Element> parameters = function.parameters;
- if (cls != null) {
- String name = function.name;
- if ((cls == baseTypes.intBaseType.element
- || cls == baseTypes.doubleBaseType.element)
- && (name == '+' || name == '-' || name == '*')) {
- ConcreteType argumentType = environment.lookupType(parameters.single);
- if (argumentType.getUniqueType() == cls) {
- return singletonConcreteType(new ClassBaseType(cls));
- }
- }
- }
-
- if (function == listIndex || function == listRemoveAt) {
- ConcreteType indexType = environment.lookupType(parameters.single);
- if (!indexType.baseTypes.contains(baseTypes.intBaseType)) {
- return emptyConcreteType;
- }
- return listElementType;
- } else if (function == listIndexSet || function == listInsert) {
- ConcreteType indexType = environment.lookupType(parameters[0]);
- if (!indexType.baseTypes.contains(baseTypes.intBaseType)) {
- return emptyConcreteType;
- }
- ConcreteType elementType = environment.lookupType(parameters[1]);
- augmentListElementType(elementType);
- return emptyConcreteType;
- } else if (function == listAdd) {
- ConcreteType elementType = environment.lookupType(parameters.single);
- augmentListElementType(elementType);
- return emptyConcreteType;
- } else if (function == listRemoveLast) {
- return listElementType;
- }
- return null;
- }
-
- ConcreteType analyzeMethodOrClosure(Element element,
- ConcreteTypesEnvironment environment) {
- ConcreteType specialResult = handleSpecialMethod(element, environment);
- if (specialResult != null) return specialResult;
- ClosureEnvironment closureEnv = closures.getEnvironmentOrNull(element);
- return (closureEnv == null)
- ? analyzeMethod(element, environment)
- : analyzeClosure(element, closureEnv, environment);
- }
-
- ConcreteType analyzeMethod(Element element,
- ConcreteTypesEnvironment environment) {
- TypeInferrerVisitor visitor = new TypeInferrerVisitor(
- element,
- this,
- singletonConcreteType(new ClassBaseType(environment.classOfThis)),
- environment.environment);
- visitor.run();
- return visitor.returnType;
- }
-
- ConcreteType analyzeClosure(Element element,
- ClosureEnvironment closureEnv,
- ConcreteTypesEnvironment environment) {
- assert(environment.classOfThis == null);
- LocalsHandler locals = (closureEnv.locals != null)
- ? new LocalsHandler.deepCopyOf(closureEnv.locals)
- : null;
- TypeInferrerVisitor visitor = new TypeInferrerVisitor(element, this,
- closureEnv.thisType, environment.environment, locals);
- visitor.run();
- return visitor.returnType;
- }
-
- /**
- * Analyze the initializer of a field if it has not yet been done and update
- * [inferredFieldTypes] accordingly. Invalidate the readers of the field if
- * needed.
- */
- void ensureFieldInitialized(Element field) {
- // This is test is needed for fitering out BoxFieldElements.
- if (field is! BoxFieldElement && inferredFieldTypes[field] == null) {
- analyzeFieldInitialization(field);
- }
- }
-
- /**
- * Analyze the initializer of a field and update [inferredFieldTypes]
- * accordingly. Invalidate the readers of the field if needed.
- */
- ConcreteType analyzeFieldInitialization(VariableElement field) {
- Visitor visitor = new TypeInferrerVisitor(field, this, null, new Map());
- ConcreteType type;
- if (field.initializer != null) {
- type = field.initializer.accept(visitor);
- inferredFieldTypes[field] = type;
- invalidateReaders(field);
- }
- return type;
- }
-
- /**
- * Analyze a default value.
- */
- ConcreteType analyzeDefaultValue(Element function, Node expression) {
- assert((function != null) && (expression != null));
- Visitor visitor = new TypeInferrerVisitor(function, this, null, {});
- return expression.accept(visitor);
- }
-
- /**
- * Hook that performs side effects on some special method calls (like
- * [:List(length):]) and possibly returns a concrete type.
- */
- ConcreteType handleSpecialMethod(FunctionElement element,
- ConcreteTypesEnvironment environment) {
- // We trust the return type of native elements
- if (isNativeElement(element)) {
- var elementType = element.type;
- assert(elementType.isFunctionType);
- return typeOfNativeBehavior(
- native.NativeBehavior.ofMethod(element, compiler));
- }
- // When List([length]) is called with some length, we must augment
- // listElementType with {null}.
- if (element == listConstructor) {
- List<Element> parameters =
- listConstructor.functionSignature.optionalParameters;
- ConcreteType lengthType = environment.lookupType(parameters.first);
- if (lengthType.baseTypes.contains(baseTypes.intBaseType)) {
- augmentListElementType(nullConcreteType);
- }
- }
- return null;
- }
-
- /**
- * Performs concrete type inference of the code reachable from [element].
- */
- @override
- bool analyzeMain(Element element) {
- initialize();
- workQueue.add(
- new InferenceWorkItem(element, new ConcreteTypesEnvironment()));
- while (!workQueue.isEmpty) {
- currentWorkItem = workQueue.remove();
- if (currentWorkItem.method.isField) {
- analyzeFieldInitialization(currentWorkItem.method);
- } else {
- Map<ConcreteTypesEnvironment, ConcreteType> template =
- getTemplatesOrEmpty(currentWorkItem.method);
- template.putIfAbsent(
- currentWorkItem.environment, () => emptyConcreteType);
- recordReturnType(
- currentWorkItem.method,
- analyzeMethodOrClosure(currentWorkItem.method,
- currentWorkItem.environment));
- }
- }
- return true;
- }
-
- /**
- * Dumps debugging information on the standard output.
- */
- void debug() {
- print("queue:");
- for (InferenceWorkItem workItem in workQueue.queue) {
- print(" $workItem");
- }
- print("seen classes:");
- for (ClassElement cls in seenClasses) {
- print(" ${cls.name}");
- }
- print("callers:");
- callers.forEach((k,v) {
- print(" $k: $v");
- });
- print("dynamic callers:");
- dynamicCallers.forEach((k,v) {
- print(" $k: $v");
- });
- print("readers:");
- fieldReaders.forEach((k,v) {
- print(" $k: $v");
- });
- print("readers of captured locals:");
- capturedLocalsReaders.forEach((k,v) {
- print(" $k: $v");
- });
- print("inferredFieldTypes:");
- inferredFieldTypes.forEach((k,v) {
- print(" $k: $v");
- });
- print("listElementType:");
- print(" $listElementType");
- print("inferredParameterTypes:");
- inferredParameterTypes.forEach((k,v) {
- print(" $k: $v");
- });
- print("inferred selector types:");
- inferredSelectorTypes.forEach((selector, map) {
- print(" $selector:");
- map.forEach((k, v) {
- print(" $k: $v");
- });
- });
- print("cache:");
- methodToTemplates.forEach((k,v) {
- print(" $k: $v");
- });
- print("closures:");
- closures.closures.forEach((k, ClosureEnvironment v) {
- print(" $k");
- print(" this: ${v.thisType}");
- if (v.locals != null) {
- v.locals.locals.forEachLocal((local, type) {
- print(" $local: $type");
- });
- }
- });
- print("inferred expression types:");
- inferredTypes.forEach((k,v) {
- print(" $k: $v");
- });
- }
-
- @override
- ConcreteType addReturnTypeFor(Element analyzedElement,
- ConcreteType currentType,
- ConcreteType newType) {
- return (currentType == null) ? newType : currentType.union(newType);
- }
-
- @override
- void forEachElementMatching(Selector selector,
- TypeMask mask,
- bool f(Element element)) {
- getMembersBySelector(selector).forEach(f);
- }
-
- @override
- void recordReturnType(Element element, ConcreteType type) {
- assert((type != null) && (element == currentWorkItem.method));
- Map<ConcreteTypesEnvironment, ConcreteType> template =
- getTemplatesOrEmpty(element);
- if (template[currentWorkItem.environment] != type) {
- template[currentWorkItem.environment] = type;
- invalidateCallers(element);
- }
- }
-
- @override
- void recordType(Element element, ConcreteType type) {
- assert(element is FieldElement);
- augmentFieldType(element, type);
- }
-
- @override
- void recordTypeOfFinalField(Node node,
- Element nodeHolder,
- Element field,
- ConcreteType type) {
- augmentFieldType(field, type);
- }
-
- @override
- void recordTypeOfNonFinalField(Spannable node, Element field,
- ConcreteType type) {
- augmentFieldType(field, type);
- }
-
- @override
- void recordCapturedLocalRead(Local local) {
- addCapturedLocalReader(local, currentWorkItem.method);
- }
-
- @override
- void recordLocalUpdate(Local local, ConcreteType type) {
- Set<FunctionElement> localReaders = capturedLocalsReaders[local];
- if (localReaders != null) {
- localReaders.forEach(invalidate);
- }
- }
-
- /**
- * Returns the caller of the current analyzed element, given the alleged
- * caller provided by SimpleTypeInferrer.
- *
- * SimpleTypeInferrer lies about the caller when it's a closure.
- * Unfortunately we cannot always trust currentWorkItem.method either because
- * it is wrong for fields initializers.
- */
- Element getRealCaller(Element allegedCaller) {
- Element currentMethod = currentWorkItem.method;
- if ((currentMethod != allegedCaller)
- && currentMethod.isFunction
- && closures.contains(currentMethod)) {
- return currentMethod;
- } else {
- return allegedCaller;
- }
- }
-
- @override
- ConcreteType registerCalledElement(Spannable node,
- Selector selector,
- TypeMask mask,
- Element caller,
- Element callee,
- ArgumentsTypes<ConcreteType> arguments,
- SideEffects sideEffects,
- bool inLoop) {
- caller = getRealCaller(caller);
- if ((selector == null) || (selector.isCall)) {
- callee = callee.implementation;
- if (selector != null && selector.name == 'JS') {
- return null;
- }
- if (callee.isField) { // toplevel closure call
- getFieldType(selector, callee); // trigger toplevel field analysis
- addFieldReader(callee, caller);
- ConcreteType result = emptyConcreteType;
- for (FunctionElement function in closures.functionElements) {
- addCaller(function, caller);
- result = result.union(
- getSendReturnType(selector, function, null, arguments));
- }
- return result;
- } else { // method or constructor call
- addCaller(callee, caller);
- ClassElement receiverClass = null;
- if (callee.isGenerativeConstructor) {
- receiverClass = callee.enclosingClass;
- } else if (node is Send) {
- Send send = node;
- if (send.receiver != null) {
- if (send.receiver.isSuper()) {
- receiverClass =
- currentWorkItem.environment.classOfThis.superclass;
- } else {
- receiverClass = currentWorkItem.environment.classOfThis;
- }
- }
- }
- return getSendReturnType(selector, callee, receiverClass, arguments);
- }
- } else if (selector.isGetter) {
- if (callee.isField) {
- addFieldReader(callee, caller);
- return getFieldType(selector, callee);
- } else if (callee.isGetter) {
- Element enclosing = callee.enclosingElement.isCompilationUnit
- ? null : callee.enclosingElement;
- addCaller(callee, caller);
- ArgumentsTypes noArguments = new ArgumentsTypes([], new Map());
- return getSendReturnType(selector, callee, enclosing, noArguments);
- } else if (callee.isFunction) {
- addClosure(callee, null, null);
- return singletonConcreteType(baseTypes.functionBaseType);
- }
- } else if (selector.isSetter) {
- ConcreteType argumentType = arguments.positional.first;
- if (callee.isField) {
- augmentFieldType(callee, argumentType);
- } else if (callee.isSetter) {
- FunctionElement setter = callee;
- // TODO(polux): A setter always returns void so there's no need to
- // invalidate its callers even if it is called with new arguments.
- // However, if we start to record more than returned types, like
- // exceptions for instance, we need to do it by uncommenting the
- // following line.
- // inferrer.addCaller(setter, currentMethod);
- Element enclosing = callee.enclosingElement.isCompilationUnit
- ? null : callee.enclosingElement;
- return getSendReturnType(selector, setter, enclosing,
- new ArgumentsTypes([argumentType], new Map()));
- }
- } else {
- throw new ArgumentError("unexpected selector kind");
- }
- return null;
- }
-
- @override
- ConcreteType registerCalledSelector(Node node,
- Selector selector,
- TypeMask mask,
- ConcreteType receiverType,
- Element caller,
- ArgumentsTypes<ConcreteType> arguments,
- SideEffects sideEffects,
- bool inLoop) {
- caller = getRealCaller(caller);
- switch (selector.kind) {
- case SelectorKind.GETTER:
- return registerDynamicGetterSend(selector, receiverType, caller);
- case SelectorKind.SETTER:
- return registerDynamicSetterSend(
- selector, receiverType, caller, arguments);
- default:
- return registerDynamicSend(selector, receiverType, caller, arguments);
- }
- }
-
- ConcreteType registerDynamicGetterSend(Selector selector,
- ConcreteType receiverType,
- Element caller) {
- caller = getRealCaller(caller);
- ConcreteType result = emptyConcreteType;
-
- void augmentResult(ClassElement baseReceiverType, Element member) {
- if (member.isField) {
- addFieldReader(member, caller);
- result = result.union(getFieldType(selector, member));
- } else if (member.isGetter) {
- addCaller(member, caller);
- ArgumentsTypes noArguments = new ArgumentsTypes([], new Map());
- result = result.union(
- getSendReturnType(selector, member, baseReceiverType, noArguments));
- } else if (member.isFunction) {
- addClosure(member, receiverType, null);
- result = result.union(
- singletonConcreteType(baseTypes.functionBaseType));
- } else {
- throw new ArgumentError("unexpected element type");
- }
- }
-
- if (receiverType.isUnknown()) {
- addDynamicCaller(selector, caller);
- Set<Element> members = getMembersBySelector(selector);
- for (Element member in members) {
- if (!(member.isField || member.isGetter)) continue;
- for (ClassElement cls in
- getReflexiveSubtypesOf(member.enclosingElement)) {
- augmentResult(cls, member);
- }
- }
- } else {
- for (BaseType baseReceiverType in receiverType.baseTypes) {
- if (!baseReceiverType.isNull()) {
- ClassBaseType classBaseType = baseReceiverType;
- ClassElement cls = classBaseType.element;
- Element getterOrField = cls.lookupByName(selector.memberName);
- if (getterOrField != null) {
- augmentResult(cls, getterOrField.implementation);
- }
- }
- }
- }
- return result;
- }
-
- ConcreteType registerDynamicSetterSend(
- Selector selector,
- ConcreteType receiverType,
- Element caller,
- ArgumentsTypes<ConcreteType> arguments) {
- caller = getRealCaller(caller);
- ConcreteType argumentType = arguments.positional.first;
-
- void augmentField(ClassElement receiverType, Element setterOrField) {
- if (setterOrField.isField) {
- augmentFieldType(setterOrField, argumentType);
- } else if (setterOrField.isSetter) {
- // A setter always returns void so there's no need to invalidate its
- // callers even if it is called with new arguments. However, if we
- // start to record more than returned types, like exceptions for
- // instance, we need to do it by uncommenting the following line.
- // inferrer.addCaller(setter, currentMethod);
- getSendReturnType(selector, setterOrField, receiverType,
- new ArgumentsTypes([argumentType], new Map()));
- } else {
- throw new ArgumentError("unexpected element type");
- }
- }
-
- if (receiverType.isUnknown()) {
- // Same remark as above
- // addDynamicCaller(selector, caller);
- for (Element member in getMembersBySelector(selector)) {
- if (!(member.isField || member.isSetter)) continue;
- Element cls = member.enclosingClass;
- augmentField(cls, member);
- }
- } else {
- for (BaseType baseReceiverType in receiverType.baseTypes) {
- if (!baseReceiverType.isNull()) {
- ClassBaseType classBaseType = baseReceiverType;
- ClassElement cls = classBaseType.element;
- Element setterOrField = cls.lookupByName(selector.memberName);
- if (setterOrField != null) {
- augmentField(cls, setterOrField.implementation);
- }
- }
- }
- }
- return argumentType;
- }
-
- ConcreteType registerDynamicSend(Selector selector,
- ConcreteType receiverType,
- Element caller,
- ArgumentsTypes<ConcreteType> arguments) {
- caller = getRealCaller(caller);
- ConcreteType result = emptyConcreteType;
- if (receiverType.isUnknown()) {
- addDynamicCaller(selector, caller);
- Set<Element> elements = getMembersBySelector(selector);
- for (Element element in elements) {
- if (element.isFunction) {
- FunctionElement method = element;
- addCaller(method, caller);
- for (ClassElement cls in
- getReflexiveSubtypesOf(method.enclosingElement)) {
- result = result.union(
- getSendReturnType(selector, method, cls, arguments));
- }
- } else { // closure call
- assert(element.isField);
- for (FunctionElement function in closures.functionElements) {
- addCaller(function, caller);
- result = result.union(
- getSendReturnType(selector, function, null, arguments));
- }
- }
- }
- } else {
- for (BaseType baseReceiverType in receiverType.baseTypes) {
- if (!baseReceiverType.isNull()) {
- ClassBaseType classBaseReceiverType = baseReceiverType;
- ClassElement cls = classBaseReceiverType.element;
- Element method = cls.lookupByName(selector.memberName);
- if (method != null) {
- if (method.isFunction) {
- assert(method is FunctionElement);
- method = method.implementation;
- addCaller(method, caller);
- result = result.union(
- getSendReturnType(selector, method, cls, arguments));
- } else { // closure call
- for (FunctionElement function in closures.functionElements) {
- addCaller(function, caller);
- result = result.union(
- getSendReturnType(selector, function, null, arguments));
- }
- }
- }
- }
- }
- }
- return result;
- }
-
- ConcreteType registerAwait(Node node, ConcreteType argumentType) {
- // TODO(polux): Properly handle await expressions.
- return types.dynamicType;
- }
-
- @override
- void setDefaultTypeOfParameter(ParameterElement parameter,
- ConcreteType type) {
- // We handle default parameters our own way in associateArguments
- }
-
- /**
- * TODO(johnniwinther): Remove once synthetic parameters get their own default
- * values.
- */
- bool hasAlreadyComputedTypeOfParameterDefault(Element parameter) => false;
-
- @override
- ConcreteType registerCalledClosure(Node node,
- Selector selector,
- TypeMask mask,
- ConcreteType closure,
- Element caller,
- ArgumentsTypes<ConcreteType> arguments,
- SideEffects sideEffects,
- bool inLoop) {
- caller = getRealCaller(caller);
- ConcreteType result = emptyConcreteType;
- for (FunctionElement function in closures.functionElements) {
- addCaller(function, caller);
- result = result.union(
- getSendReturnType(selector, function, null, arguments));
- }
- return result;
- }
-
- @override
- ConcreteType returnTypeOfElement(Element element) {
- // Never called by SimpleTypeInferrer.
- throw new UnsupportedError("");
- }
-
- @override
- ConcreteType typeOfElement(Element element) {
- if (currentWorkItem != null) {
- final result = currentWorkItem.environment.lookupType(element);
- if (result != null) return result;
- }
- if (element.isParameter || element.isInitializingFormal) {
- return inferredParameterTypes[element];
- } else if (element.isField) {
- return inferredFieldTypes[element];
- }
- throw new ArgumentError("unexpected element type");
- }
-
- @override
- void analyze(Element element, ArgumentsTypes arguments) {
- FunctionElement function = element;
- getSendReturnType(
- null, function, currentWorkItem.environment.classOfThis, arguments);
- }
-}
-
-class TypeInferrerVisitor extends SimpleTypeInferrerVisitor<ConcreteType> {
- final ConcreteType thisType;
- ConcreteTypesInferrer get inferrer => super.inferrer;
-
- TypeInferrerVisitor(Element element,
- ConcreteTypesInferrer inferrer,
- this.thisType,
- Map<Element, ConcreteType> environment,
- [LocalsHandler<ConcreteType> handler])
- : super(element, inferrer.compiler, inferrer, handler);
-
- @override
- ConcreteType visitFunctionExpression(FunctionExpression node) {
- Element element = elements[node];
- // visitFunctionExpression should be only called for closures
- assert(element != analyzedElement);
- inferrer.addClosure(
- element, thisType, new LocalsHandler.deepCopyOf(locals));
- return types.functionType;
- }
-
- @override
- ConcreteType visitLiteralString(LiteralString node) {
- // TODO(polux): get rid of this hack once we have a natural way of inferring
- // the unknown type.
- if (inferrer.testMode
- && (node.dartString.slowToString() == "__dynamic_for_test")) {
- return inferrer.unknownConcreteType;
- }
- return super.visitLiteralString(node);
- }
-
- /**
- * Same as super.visitLiteralList except it doesn't cache anything.
- */
- @override
- ConcreteType visitLiteralList(LiteralList node) {
- ConcreteType elementType;
- int length = 0;
- for (Node element in node.elements.nodes) {
- ConcreteType type = visit(element);
- elementType = elementType == null
- ? types.allocatePhi(null, null, type)
- : types.addPhiInput(null, elementType, type);
- length++;
- }
- elementType = elementType == null
- ? types.nonNullEmpty()
- : types.simplifyPhi(null, null, elementType);
- ConcreteType containerType = node.isConst
- ? types.constListType
- : types.growableListType;
- return types.allocateList(
- containerType,
- node,
- outermostElement,
- elementType,
- length);
- }
-
- /**
- * Same as super.handleLocalGet except it records the type of nodes in test
- * mode.
- */
- @override
- ConcreteType handleLocalGet(Send node, LocalElement local) {
- if (inferrer.testMode) {
- ConcreteType type = locals.use(local);
- if (type != null) {
- inferrer.augmentInferredType(node, type);
- }
- }
- return super.handleLocalGet(node, local);
- }
-}
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart b/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
index bfd3360..b1cf504 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
@@ -12,6 +12,8 @@
import '../constants/constant_system.dart';
import '../constants/expressions.dart';
import '../dart_types.dart';
+import '../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import '../diagnostics/spannable.dart' show
Spannable;
import '../elements/elements.dart';
@@ -749,6 +751,8 @@
locals = new LocalsHandler<T>(inferrer, types, compiler, node, fieldScope);
}
+ DiagnosticReporter get reporter => compiler.reporter;
+
@override
SemanticSendVisitor get sendVisitor => this;
@@ -1463,7 +1467,7 @@
}
internalError(Spannable node, String reason) {
- compiler.internalError(node, reason);
+ reporter.internalError(node, reason);
}
T visitSwitchStatement(SwitchStatement node) {
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
index 1bcb5d5..d1f9253 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
@@ -21,6 +21,8 @@
FunctionType,
InterfaceType,
TypeKind;
+import '../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import '../diagnostics/invariant.dart' show
invariant;
import '../diagnostics/spannable.dart' show
@@ -588,6 +590,7 @@
JavaScriptBackend get backend => compiler.backend;
Annotations get annotations => backend.annotations;
+ DiagnosticReporter get reporter => compiler.reporter;
/**
* A set of selector names that [List] implements, that we know return
@@ -668,15 +671,16 @@
compiler.progress.reset();
}
sortResolvedElements().forEach((Element element) {
+ assert(compiler.enqueuer.resolution.hasBeenProcessed(element));
if (compiler.shouldPrintProgress) {
- compiler.log('Added $addedInGraph elements in inferencing graph.');
+ reporter.log('Added $addedInGraph elements in inferencing graph.');
compiler.progress.reset();
}
// This also forces the creation of the [ElementTypeInformation] to ensure
// it is in the graph.
types.withMember(element, () => analyze(element, null));
});
- compiler.log('Added $addedInGraph elements in inferencing graph.');
+ reporter.log('Added $addedInGraph elements in inferencing graph.');
buildWorkQueue();
refine();
@@ -820,7 +824,7 @@
});
}
- compiler.log('Inferred $overallRefineCount types.');
+ reporter.log('Inferred $overallRefineCount types.');
processLoopInformation();
}
@@ -833,7 +837,7 @@
SimpleTypeInferrerVisitor visitor =
new SimpleTypeInferrerVisitor(element, compiler, this);
TypeInformation type;
- compiler.withCurrentElement(element, () {
+ reporter.withCurrentElement(element, () {
type = visitor.run();
});
addedInGraph++;
@@ -913,7 +917,7 @@
void refine() {
while (!workQueue.isEmpty) {
if (compiler.shouldPrintProgress) {
- compiler.log('Inferred $overallRefineCount types.');
+ reporter.log('Inferred $overallRefineCount types.');
compiler.progress.reset();
}
TypeInformation info = workQueue.remove();
@@ -1217,10 +1221,10 @@
Iterable<Element> sortResolvedElements() {
int max = 0;
Map<int, Setlet<Element>> methodSizes = new Map<int, Setlet<Element>>();
- compiler.enqueuer.resolution.resolvedElements.forEach((AstElement element) {
+ compiler.enqueuer.resolution.processedElements.forEach((AstElement element) {
// TODO(ngeoffray): Not sure why the resolver would put a null
// mapping.
- if (!compiler.enqueuer.resolution.hasBeenResolved(element)) return;
+ if (!compiler.enqueuer.resolution.hasBeenProcessed(element)) return;
TreeElementMapping mapping = element.resolvedAst.elements;
element = element.implementation;
if (element.impliesType) return;
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index df00807..c1d51cc 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -928,10 +928,11 @@
return containerTypeMask.elementType;
} else if (inferrer.returnsMapValueType(selector, typeMask)) {
if (typeMask.isDictionary &&
- arguments.positional[0].type.isValue) {
+ arguments.positional[0].type.isValue &&
+ arguments.positional[0].type.value.isString) {
DictionaryTypeMask dictionaryTypeMask = typeMask;
ValueTypeMask arg = arguments.positional[0].type;
- String key = arg.value;
+ String key = arg.value.primitiveValue.slowToString();
if (dictionaryTypeMask.typeMap.containsKey(key)) {
if (_VERBOSE) {
print("Dictionary lookup for $key yields "
@@ -1116,7 +1117,7 @@
final ast.DartString value;
StringLiteralTypeInformation(value, TypeMask mask)
- : super(new ValueTypeMask(mask, value.slowToString())),
+ : super(new ValueTypeMask(mask, new StringConstantValue(value))),
this.value = value;
String asString() => value.slowToString();
@@ -1131,7 +1132,8 @@
final ast.LiteralBool value;
BoolLiteralTypeInformation(value, TypeMask mask)
- : super(new ValueTypeMask(mask, value.value)),
+ : super(new ValueTypeMask(mask,
+ value.value ? new TrueConstantValue() : new FalseConstantValue())),
this.value = value;
String toString() => 'Type $type value ${value.value}';
diff --git a/pkg/compiler/lib/src/info/analysis_result.dart b/pkg/compiler/lib/src/info/analysis_result.dart
new file mode 100644
index 0000000..5266a01
--- /dev/null
+++ b/pkg/compiler/lib/src/info/analysis_result.dart
@@ -0,0 +1,73 @@
+// Copyright (c) 2015, 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.
+
+/// API to get results from a static analysis of the source program.
+library compiler.src.stats.analysis_result;
+
+import '../tree/tree.dart' show Node;
+import '../universe/selector.dart' show Selector;
+
+/// A three-value logic bool (yes, no, maybe). We say that `yes` and `maybe` are
+/// "truthy", while `no` and `maybe` are "falsy".
+// TODO(sigmund): is it worth using an enum? or switch to true/false/null?
+enum Boolish { yes, no, maybe }
+
+/// Specifies results of some kind of static analysis on a source program.
+abstract class AnalysisResult {
+ /// Information computed about a specific [receiver].
+ ReceiverInfo infoForReceiver(Node receiver);
+
+ /// Information computed about a specific [selector] applied to a specific
+ /// [receiver].
+ SelectorInfo infoForSelector(Node receiver, Selector selector);
+}
+
+/// Analysis information about a receiver of a send.
+abstract class ReceiverInfo {
+ /// Receiver node for which this information is computed.
+ Node get receiver;
+
+ /// Return whether [receiver] resolves to a value that implements no such
+ /// method. The answer is `yes` if all values that [receiver] could evaluate
+ /// to at runtime contain it, or `no` if none of them does. Maybe if it
+ /// depends on some context or we can't determine this information precisely.
+ Boolish get hasNoSuchMethod;
+
+ /// When [hasNoSuchMethod] is yes, the precise number of possible noSuchMethod
+ /// handlers for this receiver.
+ int get possibleNsmTargets;
+
+ /// Return whether [receiver] may ever be null.
+ Boolish get isNull;
+}
+
+/// Information about a specific selector applied to a specific receiver.
+abstract class SelectorInfo {
+ /// Receiver node of the [selector].
+ Node get receiver;
+
+ /// Specific selector on [receiver] for which this information is computed.
+ Selector get selector;
+
+ /// Whether a member matching [selector] exists in [receiver].
+ Boolish get exists;
+
+ /// Whether [receiver] needs an interceptor to implement [selector].
+ Boolish get usesInterceptor;
+
+ /// Possible total number of methods that could be the target of the selector.
+ /// This needs to be combined with [isAccurate] to correctly understand the
+ /// value. Some invariants:
+ ///
+ /// * If [exists] is `no`, the value here should be 0, regardless of
+ /// accuracy.
+ /// * If [exists] is `yes`, the value is always considered 1 or more.
+ /// If [isAccurate] is false, we treat it as there may be many possible
+ /// targets.
+ /// * If [exists] is `maybe`, the value is considered 0 or more.
+ int get possibleTargets;
+
+ /// Whether the information about [possibleTargets] is accurate.
+ bool get isAccurate;
+}
diff --git a/pkg/compiler/lib/src/info/naive_analysis_result.dart b/pkg/compiler/lib/src/info/naive_analysis_result.dart
new file mode 100644
index 0000000..0061be4
--- /dev/null
+++ b/pkg/compiler/lib/src/info/naive_analysis_result.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2015, 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.
+
+/// API to get results from a static analysis of the source program.
+// TODO(sigmund): split out implementations out of this file.
+library compiler.src.stats.naive_analysis_result;
+
+import 'analysis_result.dart';
+import '../tree/tree.dart' show Node;
+import '../universe/selector.dart' show Selector;
+
+/// A naive [AnalysisResult] that tells us very little. This is the most
+/// conservative we can be when we only use information from the AST structure
+/// and from resolution, but no type information.
+class NaiveAnalysisResult implements AnalysisResult {
+ NaiveAnalysisResult();
+
+ ReceiverInfo infoForReceiver(Node receiver) =>
+ new NaiveReceiverInfo(receiver);
+ SelectorInfo infoForSelector(Node receiver, Selector selector) =>
+ new NaiveSelectorInfo(receiver, selector);
+}
+
+class NaiveReceiverInfo implements ReceiverInfo {
+ final Node receiver;
+
+ NaiveReceiverInfo(this.receiver);
+ Boolish get hasNoSuchMethod => Boolish.maybe;
+ Boolish get isNull => Boolish.maybe;
+ int get possibleNsmTargets => -1;
+}
+
+class NaiveSelectorInfo implements SelectorInfo {
+ final Node receiver;
+ final Selector selector;
+
+ NaiveSelectorInfo(this.receiver, this.selector);
+
+ Boolish get exists => Boolish.maybe;
+ Boolish get usesInterceptor => Boolish.maybe;
+ int get possibleTargets => -1;
+ bool get isAccurate => false;
+}
diff --git a/pkg/compiler/lib/src/info/send_info.dart b/pkg/compiler/lib/src/info/send_info.dart
new file mode 100644
index 0000000..0299142
--- /dev/null
+++ b/pkg/compiler/lib/src/info/send_info.dart
@@ -0,0 +1,2383 @@
+// Copyright (c) 2015, 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.
+
+/// Computes measurements about sends in a function.
+library compiler.src.info.send_info;
+
+import 'dart:convert';
+import 'package:dart2js_info/src/measurements.dart';
+import 'package:dart2js_info/src/util.dart' show recursiveDiagnosticString;
+
+import '../diagnostics/diagnostic_listener.dart' show DiagnosticReporter;
+import '../diagnostics/messages.dart' show MessageKind;
+import '../compiler.dart' show Compiler;
+import '../common/tasks.dart' show CompilerTask;
+import '../dart_types.dart';
+import '../closure.dart';
+import '../elements/elements.dart';
+import '../elements/visitor.dart' show ElementVisitor;
+import '../resolution/operators.dart';
+import '../resolution/semantic_visitor.dart';
+import '../resolution/send_resolver.dart';
+import '../resolution/tree_elements.dart';
+import '../constants/expressions.dart';
+import '../parser/partial_elements.dart' show PartialElement;
+import '../tree/tree.dart';
+import '../universe/selector.dart' show Selector;
+import '../universe/call_structure.dart' show CallStructure;
+
+import 'analysis_result.dart';
+import 'naive_analysis_result.dart';
+import 'trusted_types_analysis_result.dart';
+
+/// Collects a set of [Measurements] about send expressions in the function [f].
+// TODO(sigmund): collect information on initializers too.
+Measurements collectSendMeasurements(FunctionElement f,
+ Compiler compiler) {
+ DiagnosticReporter reporter = compiler.reporter;
+ return reporter.withCurrentElement(f, () {
+ // TODO(sigmund): enable for platform too.
+ if (f.library.isPlatformLibrary) return null;
+ var name = _qualifiedName(f);
+ if (!f.hasNode) {
+ if (f is PartialElement) return const Measurements.unreachableFunction();
+ assert (f is ConstructorElement && f.isSynthesized);
+ // TODO(sigmund): measure synthethic forwarding sends, measure
+ // initializers
+ return new Measurements.reachableFunction();
+ }
+ if (!f.hasResolvedAst) {
+ _debug('no resolved ast ${f.runtimeType}');
+ return null;
+ }
+ var resolvedAst = f.resolvedAst;
+ if (resolvedAst.node == null) {
+ _debug('no node ${f.runtimeType}');
+ return null;
+ }
+ var def = resolvedAst.elements.getFunctionDefinition(resolvedAst.node);
+ if (def == null) {
+ assert (f is PartialElement);
+ return const Measurements.unreachableFunction();
+ }
+
+ var visitor = new _StatsTraversalVisitor(
+ compiler, resolvedAst.elements,
+ reporter.spanFromSpannable(resolvedAst.node).uri);
+ resolvedAst.node.accept(visitor);
+ return visitor.measurements;
+ });
+}
+
+_qualifiedName(FunctionElement f) {
+ var cls = f.enclosingClass;
+ return (cls != null) ? '${cls.name}.${f.name}' : f.name;
+}
+
+/// Visitor that categorizes data about an individual send.
+class _StatsVisitor<T> extends Visitor
+ with SendResolverMixin, SemanticSendResolvedMixin<dynamic, T>
+ implements SemanticSendVisitor<dynamic, T> {
+
+ // TODO(sigmund): consider passing in several AnalysisResults at once, so we
+ // can compute the different metrics together.
+ /// Information we know about the program from static analysis.
+ final AnalysisResult info;
+
+ /// Results from this function.
+ final Measurements measurements;
+
+ final DiagnosticReporter reporter;
+ final TreeElements elements;
+
+ SemanticSendVisitor<dynamic, T> get sendVisitor => this;
+
+ _StatsVisitor(this.reporter, this.elements, this.info, Uri sourceUri)
+ : measurements = new Measurements.reachableFunction(sourceUri);
+
+ visitNode(Node node) => throw "unhandled ${node.runtimeType}: $node";
+ apply(Node node, T arg) => throw "missing apply ${node.runtimeType}: $node";
+ internalError(Node node, String arg) => throw "internal error on $node";
+
+ visitSend(Send node) {
+ _checkInvariant(node, 'before');
+ var span = reporter.spanFromSpannable(node);
+ measurements.record(Metric.send, span.begin, span.end);
+ if (node is SendSet) {
+ if ((node.assignmentOperator != null &&
+ node.assignmentOperator.source != '=') ||
+ node.isPrefix ||
+ node.isPostfix) {
+ assert(!node.isIfNullAssignment);
+ // We count get and set separately in case one of them is defined by the
+ // other could be a nSM error.
+ measurements.record(Metric.send, span.begin, span.end);
+ measurements.record(Metric.send, span.begin, span.end);
+ } else if (node.isIfNullAssignment) {
+ measurements.record(Metric.send, span.begin, span.end);
+ }
+ }
+ super.visitSend(node);
+ _checkInvariant(node, 'after ');
+ }
+
+ visitNewExpression(NewExpression node) {
+ _checkInvariant(node, 'before');
+ var span = reporter.spanFromSpannable(node);
+ measurements.record(Metric.send, span.begin, span.end);
+ super.visitNewExpression(node);
+ _checkInvariant(node, 'after ');
+ }
+
+ /// A monomorphic local variable read.
+ ///
+ /// See [Metric.send] for a full categorization of sends.
+ handleLocal(Node node) {
+ var span = reporter.spanFromSpannable(node);
+ measurements.record(Metric.monomorphicSend, span.begin, span.end);
+ measurements.record(Metric.localSend, span.begin, span.end);
+ }
+
+ /// A monomorphic virual call on [node], where we know which function is the
+ /// target of the call (for example, because only one type in a class
+ /// hierarchy implements a function with a given name).
+ ///
+ /// See [Metric.send] for a full categorization of sends.
+ handleSingleInstance(Node node) {
+ var span = reporter.spanFromSpannable(node);
+ measurements.record(Metric.monomorphicSend, span.begin, span.end);
+ measurements.record(Metric.instanceSend, span.begin, span.end);
+ }
+
+ /// A monomorphic call that goes through an interceptor. This is equivalent in
+ /// terms of what the compiler knows as we do with [handleSignleInstance], and
+ /// because we know the target of the call, we also know that it doesn't live
+ /// in the object instance, but on an interceptor on the side.
+ ///
+ /// See [Metric.send] for a full categorization of sends.
+ handleSingleInterceptor(Node node) {
+ var span = reporter.spanFromSpannable(node);
+ measurements.record(Metric.monomorphicSend, span.begin, span.end);
+ measurements.record(Metric.interceptorSend, span.begin, span.end);
+ }
+
+ /// A polymorphic call that goes through an interceptor.
+ ///
+ /// See [Metric.send] for a full categorization of sends.
+ handleMultiInterceptor(Node node) {
+ var span = reporter.spanFromSpannable(node);
+ measurements.record(Metric.polymorphicSend, span.begin, span.end);
+ measurements.record(Metric.multiInterceptorSend, span.begin, span.end);
+ }
+
+ handleConstructor(Node node) {
+ var span = reporter.spanFromSpannable(node);
+ measurements.record(Metric.monomorphicSend, span.begin, span.end);
+ measurements.record(Metric.constructorSend, span.begin, span.end);
+ }
+
+ handleDynamic(Node node) {
+ var span = reporter.spanFromSpannable(node);
+ measurements.record(Metric.polymorphicSend, span.begin, span.end);
+ measurements.record(Metric.dynamicSend, span.begin, span.end);
+ }
+
+ handleVirtual(Node node) {
+ var span = reporter.spanFromSpannable(node);
+ measurements.record(Metric.polymorphicSend, span.begin, span.end);
+ measurements.record(Metric.virtualSend, span.begin, span.end);
+ }
+
+ handleNSMError(Node node) {
+ var span = reporter.spanFromSpannable(node);
+ measurements.record(Metric.monomorphicSend, span.begin, span.end);
+ measurements.record(Metric.nsmErrorSend, span.begin, span.end);
+ }
+
+ handleNSMSingle(Node node) {
+ var span = reporter.spanFromSpannable(node);
+ measurements.record(Metric.monomorphicSend, span.begin, span.end);
+ measurements.record(Metric.singleNsmCallSend, span.begin, span.end);
+ }
+
+ handleNSMSuper(Node node, ClassElement type) {
+ var superclass = type.superclass;
+ var member = superclass.lookupMember('noSuchMethod');
+ if (!member.enclosingClass.isObject) {
+ handleNSMSingle(node);
+ } else {
+ handleNSMError(node);
+ }
+ }
+
+ handleNSMAny(Node node) {
+ var span = reporter.spanFromSpannable(node);
+ measurements.record(Metric.polymorphicSend, span.begin, span.end);
+ measurements.record(Metric.multiNsmCallSend, span.begin, span.end);
+ }
+
+ handleSuper(Node node) {
+ var span = reporter.spanFromSpannable(node);
+ measurements.record(Metric.monomorphicSend, span.begin, span.end);
+ measurements.record(Metric.superSend, span.begin, span.end);
+ }
+ handleTypeVariable(Node node) {
+ var span = reporter.spanFromSpannable(node);
+ measurements.record(Metric.monomorphicSend, span.begin, span.end);
+ measurements.record(Metric.typeVariableSend, span.begin, span.end);
+ }
+ handleStatic(Node node) {
+ var span = reporter.spanFromSpannable(node);
+ measurements.record(Metric.monomorphicSend, span.begin, span.end);
+ measurements.record(Metric.staticSend, span.begin, span.end);
+ }
+
+ handleNoSend(Node node) {
+ measurements.popLast(Metric.send);
+ }
+
+ void handleDynamicProperty(Node node, Node receiver, Selector selector) {
+ // staticSend: no (automatically)
+ // superSend: no (automatically)
+ // localSend: no (automatically)
+ // constructorSend: no (automatically)
+ // typeVariableSend: no (automatically)
+
+ // nsmErrorSend: receiver has no `selector` nor nSM.
+ // singleNsmCallSend: receiver has no `selector`, but definitely has `nSM`
+ // instanceSend: receiver has `selector`, no need to use an interceptor
+ // interceptorSend: receiver has `selector`, but we know we need an
+ // interceptor to get it
+
+ // multiNsmCallSend: receiver has no `selector`, not sure if receiver has
+ // nSM, or not sure which nSM is called (does this one
+ // matter, or does nSM is treated like an instance method
+ // call)?
+ // virtualSend: receiver has `selector`, we know we do not need an
+ // interceptor, not sure which specific type implements
+ // the selector.
+ // multiInterceptorSend: multiple possible receiver types, all using an
+ // interceptor to get the `selector`, might be
+ // possbile to pick a special selector logic for this
+ // combination?
+ // dynamicSend: any combination of the above.
+
+ ReceiverInfo receiverInfo = info.infoForReceiver(receiver);
+ SelectorInfo selectorInfo = info.infoForSelector(receiver, selector);
+ Boolish hasSelector = selectorInfo.exists;
+ Boolish hasNsm = receiverInfo.hasNoSuchMethod;
+
+ if (hasSelector == Boolish.no) {
+ if (hasNsm == Boolish.no) {
+ handleNSMError(node);
+ } else if (hasNsm == Boolish.yes) {
+ if (receiverInfo.possibleNsmTargets == 1) {
+ handleNSMSingle(node);
+ } else {
+ handleNSMAny(node);
+ }
+ } else {
+ handleDynamic(node);
+ }
+ return;
+ }
+
+ Boolish usesInterceptor = selectorInfo.usesInterceptor;
+ if (hasSelector == Boolish.yes) {
+ if (selectorInfo.isAccurate && selectorInfo.possibleTargets == 1) {
+ assert (usesInterceptor != Boolish.maybe);
+ if (usesInterceptor == Boolish.yes) {
+ handleSingleInterceptor(node);
+ } else {
+ handleSingleInstance(node);
+ }
+ } else {
+ if (usesInterceptor == Boolish.no) {
+ handleVirtual(node);
+ } else if (usesInterceptor == Boolish.yes) {
+ handleMultiInterceptor(node);
+ } else {
+ handleDynamic(node);
+ }
+ }
+ return;
+ }
+ handleDynamic(node);
+ }
+
+ void handleThisProperty(Send node, Selector selector) {
+ handleDynamicProperty(node, node.receiver, selector);
+ }
+
+ void handleIndex(Node node) {
+ handleDynamic(node);
+ }
+
+ void handleOperator(Node node) {
+ handleDynamic(node);
+ }
+
+ void handleInvoke(Node node) {
+ handleDynamic(node);
+ }
+
+ void handleEquals(Node node) {
+ handleDynamic(node);
+ }
+
+ // Constructors
+
+ void visitAbstractClassConstructorInvoke(NewExpression node,
+ ConstructorElement element, InterfaceType type, NodeList arguments,
+ CallStructure callStructure, T arg) {
+ handleConstructor(node);
+ }
+
+ void visitBoolFromEnvironmentConstructorInvoke(NewExpression node,
+ BoolFromEnvironmentConstantExpression constant, T arg) {
+ handleConstructor(node);
+ }
+
+ void visitConstConstructorInvoke(
+ NewExpression node, ConstructedConstantExpression constant, T arg) {
+ handleConstructor(node);
+ }
+
+ void visitGenerativeConstructorInvoke(NewExpression node,
+ ConstructorElement constructor, InterfaceType type, NodeList arguments,
+ CallStructure callStructure, T arg) {
+ handleConstructor(node);
+ }
+
+ void visitIntFromEnvironmentConstructorInvoke(NewExpression node,
+ IntFromEnvironmentConstantExpression constant, T arg) {
+ handleConstructor(node);
+ }
+
+ void visitRedirectingFactoryConstructorInvoke(NewExpression node,
+ ConstructorElement constructor, InterfaceType type,
+ ConstructorElement effectiveTarget, InterfaceType effectiveTargetType,
+ NodeList arguments, CallStructure callStructure, T arg) {
+ handleConstructor(node);
+ }
+
+ void visitRedirectingGenerativeConstructorInvoke(NewExpression node,
+ ConstructorElement constructor, InterfaceType type, NodeList arguments,
+ CallStructure callStructure, T arg) {
+ handleConstructor(node);
+ }
+
+ void visitStringFromEnvironmentConstructorInvoke(NewExpression node,
+ StringFromEnvironmentConstantExpression constant, T arg) {
+ handleConstructor(node);
+ }
+
+ // Dynamic sends
+
+
+ // TODO(sigmund): many many things to add:
+ // -- support for operators, indexers, etc.
+ // -- logic about nullables
+ // -- int, JSArray
+ // -- all interceptors
+
+ void visitBinary(
+ Send node, Node left, BinaryOperator operator, Node right, T arg) {
+ handleOperator(node);
+ }
+
+ void visitCompoundIndexSet(SendSet node, Node receiver, Node index,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleIndex(node); // t1 = receiver[index]
+ handleOperator(node); // t2 = t1 op rhs
+ handleIndex(node); // receiver[index] = t2
+ }
+
+ void visitDynamicPropertyCompound(Send node, Node receiver,
+ Name name, AssignmentOperator operator, Node rhs, T arg) {
+ handleDynamicProperty(node, receiver, new Selector.getter(name));
+ handleOperator(node);
+ handleDynamicProperty(node, receiver, new Selector.setter(name));
+ }
+
+
+ void visitDynamicPropertyGet(
+ Send node, Node receiver, Name name, T arg) {
+ handleDynamicProperty(node, receiver, new Selector.getter(name));
+ }
+
+ void visitDynamicPropertyInvoke(
+ Send node, Node receiver, NodeList arguments, Selector selector, T arg) {
+ handleDynamicProperty(node, receiver, selector);
+ }
+
+ void visitDynamicPropertyPostfix(Send node, Node receiver,
+ Name name, IncDecOperator operator, T arg) {
+ handleDynamicProperty(node, receiver, new Selector.getter(name));
+ handleOperator(node);
+ handleDynamicProperty(node, receiver, new Selector.setter(name));
+ }
+
+ void visitDynamicPropertyPrefix(Send node, Node receiver, Name name,
+ IncDecOperator operator, T arg) {
+ handleDynamicProperty(node, receiver, new Selector.getter(name));
+ handleOperator(node);
+ handleDynamicProperty(node, receiver, new Selector.setter(name));
+ }
+
+ void visitDynamicPropertySet(
+ SendSet node, Node receiver, Name name, Node rhs, T arg) {
+ handleDynamicProperty(node, receiver, new Selector.setter(name));
+ }
+
+ void visitDynamicPropertySetIfNull(
+ Send node, Node receiver, Name name, Node rhs, T arg) {
+ // read to check for null?
+ handleDynamicProperty(node, receiver, new Selector.getter(name));
+ handleDynamicProperty(node, receiver, new Selector.setter(name));
+ }
+
+ void visitEquals(Send node, Node left, Node right, T arg) {
+ handleEquals(node);
+ }
+
+ void visitExpressionInvoke(Send node, Node expression, NodeList arguments,
+ CallStructure callStructure, T arg) {
+ handleInvoke(node);
+ }
+
+ void visitIfNotNullDynamicPropertyCompound(Send node, Node receiver,
+ Name name, AssignmentOperator operator, Node rhs, T arg) {
+ handleDynamicProperty(node, receiver, new Selector.getter(name));
+ handleOperator(node);
+ handleDynamicProperty(node, receiver, new Selector.setter(name));
+ }
+
+ void visitIfNotNullDynamicPropertyGet(
+ Send node, Node receiver, Name name, T arg) {
+ handleDynamicProperty(node, receiver, new Selector.getter(name));
+ }
+
+ void visitIfNotNullDynamicPropertyInvoke(
+ Send node, Node receiver, NodeList arguments, Selector selector, T arg) {
+ handleDynamicProperty(node, receiver, selector);
+ }
+
+ void visitIfNotNullDynamicPropertyPostfix(Send node, Node receiver, Name name,
+ IncDecOperator operator, T arg) {
+ handleDynamicProperty(node, receiver, new Selector.getter(name));
+ handleOperator(node);
+ handleDynamicProperty(node, receiver, new Selector.setter(name));
+ }
+
+ void visitIfNotNullDynamicPropertyPrefix(Send node, Node receiver, Name name,
+ IncDecOperator operator, T arg) {
+ handleDynamicProperty(node, receiver, new Selector.getter(name));
+ handleOperator(node);
+ handleDynamicProperty(node, receiver, new Selector.setter(name));
+ }
+
+ void visitIfNotNullDynamicPropertySet(
+ SendSet node, Node receiver, Name name, Node rhs, T arg) {
+ handleDynamicProperty(node, receiver, new Selector.setter(name));
+ }
+
+ void visitIfNotNullDynamicPropertySetIfNull(
+ Send node, Node receiver, Name name, Node rhs, T arg) {
+ handleDynamicProperty(node, receiver, new Selector.getter(name));
+ handleDynamicProperty(node, receiver, new Selector.setter(name));
+ }
+
+ void visitIndex(Send node, Node receiver, Node index, T arg) {
+ handleIndex(node);
+ }
+
+ void visitIndexPostfix(
+ Send node, Node receiver, Node index, IncDecOperator operator, T arg) {
+ handleIndex(node);
+ handleOperator(node);
+ handleIndex(node);
+ }
+
+ void visitIndexPrefix(
+ Send node, Node receiver, Node index, IncDecOperator operator, T arg) {
+ handleIndex(node);
+ handleOperator(node);
+ handleIndex(node);
+ }
+
+ void visitIndexSet(SendSet node, Node receiver, Node index, Node rhs, T arg) {
+ handleIndex(node);
+ }
+
+ void visitLocalVariableCompound(Send node, LocalVariableElement variable,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleLocal(node);
+ handleOperator(node);
+ handleLocal(node);
+ }
+
+ void visitLocalVariableInvoke(Send node, LocalVariableElement variable,
+ NodeList arguments, CallStructure callStructure, T arg) {
+ handleInvoke(node);
+ }
+
+ void visitLocalVariablePostfix(Send node, LocalVariableElement variable,
+ IncDecOperator operator, T arg) {
+ handleLocal(node);
+ handleOperator(node);
+ handleLocal(node);
+ }
+
+ void visitLocalVariablePrefix(Send node, LocalVariableElement variable,
+ IncDecOperator operator, T arg) {
+ handleLocal(node);
+ handleOperator(node);
+ handleLocal(node);
+ }
+
+ void visitNotEquals(Send node, Node left, Node right, T arg) {
+ handleEquals(node);
+ }
+
+ void visitParameterCompound(Send node, ParameterElement parameter,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleLocal(node);
+ handleOperator(node);
+ handleLocal(node);
+ }
+
+ void visitParameterInvoke(Send node, ParameterElement parameter,
+ NodeList arguments, CallStructure callStructure, T arg) {
+ handleInvoke(node);
+ }
+
+ void visitParameterPostfix(
+ Send node, ParameterElement parameter, IncDecOperator operator, T arg) {
+ handleLocal(node);
+ handleOperator(node);
+ handleLocal(node);
+ }
+
+ void visitParameterPrefix(
+ Send node, ParameterElement parameter, IncDecOperator operator, T arg) {
+ handleLocal(node);
+ handleOperator(node);
+ handleLocal(node);
+ }
+
+ void visitStaticFieldCompound(Send node, FieldElement field,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleStatic(node);
+ handleOperator(node);
+ handleStatic(node);
+ }
+
+ void visitStaticFieldInvoke(Send node, FieldElement field, NodeList arguments,
+ CallStructure callStructure, T arg) {
+ handleInvoke(node);
+ }
+
+ void visitStaticFieldPostfix(
+ Send node, FieldElement field, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleOperator(node);
+ handleStatic(node);
+ }
+
+ void visitStaticFieldPrefix(
+ Send node, FieldElement field, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleOperator(node);
+ handleStatic(node);
+ }
+
+ void visitStaticGetterInvoke(Send node, FunctionElement getter,
+ NodeList arguments, CallStructure callStructure, T arg) {
+ handleInvoke(node);
+ }
+
+ void visitStaticGetterSetterCompound(Send node, FunctionElement getter,
+ FunctionElement setter, AssignmentOperator operator, Node rhs, T arg) {
+ handleStatic(node);
+ handleOperator(node);
+ handleStatic(node);
+ }
+
+ void visitStaticGetterSetterPostfix(Send node, FunctionElement getter,
+ FunctionElement setter, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleOperator(node);
+ handleStatic(node);
+ }
+
+ void visitStaticGetterSetterPrefix(Send node, FunctionElement getter,
+ FunctionElement setter, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleOperator(node);
+ handleStatic(node);
+ }
+
+ void visitSuperFieldCompound(Send node, FieldElement field,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitSuperFieldFieldCompound(Send node, FieldElement readField,
+ FieldElement writtenField, AssignmentOperator operator, Node rhs, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitSuperFieldFieldPostfix(Send node, FieldElement readField,
+ FieldElement writtenField, IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitSuperFieldFieldPrefix(Send node, FieldElement readField,
+ FieldElement writtenField, IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitSuperFieldFieldSetIfNull(
+ Send node, FieldElement readField, FieldElement writtenField, Node rhs,
+ T arg) {
+ handleSuper(node);
+ handleNSMSuper(node, readField.enclosingClass);
+ }
+
+ void visitSuperFieldInvoke(Send node, FieldElement field, NodeList arguments,
+ CallStructure callStructure, T arg) {
+ handleInvoke(node);
+ }
+
+ void visitSuperFieldPostfix(
+ Send node, FieldElement field, IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitSuperFieldPrefix(
+ Send node, FieldElement field, IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitSuperFieldSetterCompound(Send node, FieldElement field,
+ FunctionElement setter, AssignmentOperator operator, Node rhs, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitSuperFieldSetterPostfix(Send node, FieldElement field,
+ FunctionElement setter, IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitSuperFieldSetterPrefix(Send node, FieldElement field,
+ FunctionElement setter, IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitSuperFieldSetterSetIfNull(Send node, FieldElement field,
+ FunctionElement setter, Node rhs, T arg) {
+ handleSuper(node);
+ handleSuper(node);
+ }
+
+ void visitSuperGetterFieldCompound(Send node, FunctionElement getter,
+ FieldElement field, AssignmentOperator operator, Node rhs, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitSuperGetterFieldPostfix(Send node, FunctionElement getter,
+ FieldElement field, IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitSuperGetterFieldPrefix(Send node, FunctionElement getter,
+ FieldElement field, IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitSuperGetterFieldSetIfNull(Send node, FunctionElement getter,
+ FieldElement field, Node rhs, T arg) {
+ handleSuper(node);
+ handleSuper(node);
+ }
+
+ void visitSuperGetterInvoke(Send node, FunctionElement getter,
+ NodeList arguments, CallStructure callStructure, T arg) {
+ handleInvoke(node);
+ }
+
+ void visitSuperGetterSetterCompound(Send node, FunctionElement getter,
+ FunctionElement setter, AssignmentOperator operator, Node rhs, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitSuperGetterSetterPostfix(Send node, FunctionElement getter,
+ FunctionElement setter, IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitSuperGetterSetterPrefix(Send node, FunctionElement getter,
+ FunctionElement setter, IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitSuperGetterSetterSetIfNull(Send node, FunctionElement getter,
+ FunctionElement setter, Node rhs, T arg) {
+ handleSuper(node);
+ handleSuper(node);
+ }
+
+ void visitSuperIndexPostfix(Send node, MethodElement indexFunction,
+ MethodElement indexSetFunction, Node index, IncDecOperator operator,
+ T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitSuperIndexPrefix(Send node, MethodElement indexFunction,
+ MethodElement indexSetFunction, Node index, IncDecOperator operator,
+ T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitSuperMethodSetterCompound(Send node, FunctionElement method,
+ FunctionElement setter, AssignmentOperator operator, Node rhs, T arg) {
+ handleSuper(node);
+ handleNSMSuper(node, method.enclosingClass);
+ handleSuper(node);
+ }
+
+ void visitSuperMethodSetterPostfix(Send node, FunctionElement method,
+ FunctionElement setter, IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleNSMSuper(node, method.enclosingClass);
+ handleSuper(node);
+ }
+
+ void visitSuperMethodSetterPrefix(Send node, FunctionElement method,
+ FunctionElement setter, IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleNSMSuper(node, method.enclosingClass);
+ handleSuper(node);
+ }
+
+ void visitSuperMethodSetterSetIfNull(Send node, FunctionElement method,
+ FunctionElement setter, Node rhs, T arg) {
+ handleSuper(node);
+ handleSuper(node);
+ }
+
+ void visitThisPropertyCompound(Send node, Name name,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleThisProperty(node, new Selector.getter(name));
+ handleOperator(node);
+ handleThisProperty(node, new Selector.setter(name));
+ }
+
+ void visitThisPropertyInvoke(
+ Send node, NodeList arguments, Selector selector, T arg) {
+ handleThisProperty(node, selector);
+ }
+
+ void visitThisPropertyPostfix(Send node, Name name, IncDecOperator operator,
+ T arg) {
+ handleThisProperty(node, new Selector.getter(name));
+ handleOperator(node);
+ handleThisProperty(node, new Selector.setter(name));
+ }
+
+ void visitThisPropertyPrefix(Send node, Name name, IncDecOperator operator,
+ T arg) {
+ handleThisProperty(node, new Selector.getter(name));
+ handleOperator(node);
+ handleThisProperty(node, new Selector.setter(name));
+ }
+
+ void visitTopLevelFieldCompound(Send node, FieldElement field,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleStatic(node);
+ handleOperator(node);
+ handleStatic(node);
+ }
+
+ void visitTopLevelFieldInvoke(Send node, FieldElement field,
+ NodeList arguments, CallStructure callStructure, T arg) {
+ handleInvoke(node);
+ }
+
+ void visitTopLevelFieldPostfix(
+ Send node, FieldElement field, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleOperator(node);
+ handleStatic(node);
+ }
+
+ void visitTopLevelFieldPrefix(
+ Send node, FieldElement field, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleOperator(node);
+ handleStatic(node);
+ }
+
+ void visitTopLevelGetterInvoke(Send node, FunctionElement getter,
+ NodeList arguments, CallStructure callStructure, T arg) {
+ handleInvoke(node);
+ }
+
+ void visitTopLevelGetterSetterCompound(Send node, FunctionElement getter,
+ FunctionElement setter, AssignmentOperator operator, Node rhs, T arg) {
+ handleStatic(node);
+ handleOperator(node);
+ handleStatic(node);
+ }
+
+ void visitTopLevelGetterSetterPostfix(Send node, FunctionElement getter,
+ FunctionElement setter, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleOperator(node);
+ handleStatic(node);
+ }
+
+ void visitTopLevelGetterSetterPrefix(Send node, FunctionElement getter,
+ FunctionElement setter, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleOperator(node);
+ handleStatic(node);
+ }
+
+ void visitUnary(Send node, UnaryOperator operator, Node expression, T arg) {
+ handleDynamic(node);
+ }
+
+ // Local variable sends
+
+ void visitLocalFunctionGet(Send node, LocalFunctionElement function, T arg) {
+ handleLocal(node);
+ }
+
+ void visitLocalFunctionInvoke(Send node, LocalFunctionElement function,
+ NodeList arguments, CallStructure callStructure, T arg) {
+ handleLocal(node);
+ }
+
+ void visitLocalVariableGet(Send node, LocalVariableElement variable, T arg) {
+ handleLocal(node);
+ }
+
+ void visitLocalVariableSet(
+ SendSet node, LocalVariableElement variable, Node rhs, T arg) {
+ handleLocal(node);
+ }
+
+ void visitLocalVariableSetIfNull(
+ SendSet node, LocalVariableElement variable, Node rhs, T arg) {
+ handleLocal(node);
+ handleLocal(node);
+ }
+
+ void visitParameterGet(Send node, ParameterElement parameter, T arg) {
+ handleLocal(node);
+ }
+
+ void visitParameterSet(
+ SendSet node, ParameterElement parameter, Node rhs, T arg) {
+ handleLocal(node);
+ }
+
+ void visitParameterSetIfNull(
+ Send node, ParameterElement parameter, Node rhs, T arg) {
+ handleLocal(node);
+ handleLocal(node);
+ }
+
+ // Super monomorphic sends
+
+ void visitSuperBinary(Send node, FunctionElement function,
+ BinaryOperator operator, Node argument, T arg) {
+ handleSuper(node);
+ }
+
+ void visitSuperEquals(
+ Send node, FunctionElement function, Node argument, T arg) {
+ handleSuper(node);
+ }
+
+ void visitSuperFieldGet(Send node, FieldElement field, T arg) {
+ handleSuper(node);
+ }
+
+ void visitSuperFieldSet(SendSet node, FieldElement field, Node rhs, T arg) {
+ handleSuper(node);
+ }
+
+ void visitSuperFieldSetIfNull(
+ SendSet node, FieldElement field, Node rhs, T arg) {
+ handleSuper(node);
+ handleSuper(node);
+ }
+
+ void visitSuperGetterGet(Send node, FunctionElement getter, T arg) {
+ handleSuper(node);
+ }
+
+ void visitSuperGetterSet(
+ SendSet node, FunctionElement getter, Node rhs, T arg) {
+ handleSuper(node);
+ }
+
+ void visitSuperIndex(Send node, FunctionElement function, Node index, T arg) {
+ handleSuper(node);
+ }
+
+ void visitSuperIndexSet(
+ SendSet node, FunctionElement function, Node index, Node rhs, T arg) {
+ handleSuper(node);
+ }
+
+ void visitSuperMethodGet(Send node, MethodElement method, T arg) {
+ handleSuper(node);
+ }
+
+ void visitSuperMethodInvoke(Send node, MethodElement method,
+ NodeList arguments, CallStructure callStructure, T arg) {
+ handleSuper(node);
+ }
+
+ void visitSuperNotEquals(
+ Send node, FunctionElement function, Node argument, T arg) {
+ handleSuper(node);
+ }
+
+ void visitSuperSetterSet(
+ SendSet node, FunctionElement setter, Node rhs, T arg) {
+ handleSuper(node);
+ }
+
+ void visitSuperUnary(
+ Send node, UnaryOperator operator, FunctionElement function, T arg) {
+ handleSuper(node);
+ }
+
+ // Statically known "no such method" sends
+
+ void visitConstructorIncompatibleInvoke(NewExpression node,
+ ConstructorElement constructor, InterfaceType type, NodeList arguments,
+ CallStructure callStructure, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitFinalLocalVariableCompound(Send node, LocalVariableElement variable,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleLocal(node);
+ handleOperator(node);
+ handleNSMError(node);
+ }
+
+ void visitFinalLocalVariablePostfix(Send node, LocalVariableElement variable,
+ IncDecOperator operator, T arg) {
+ handleLocal(node);
+ handleOperator(node);
+ handleNSMError(node);
+ }
+
+ void visitFinalLocalVariablePrefix(Send node, LocalVariableElement variable,
+ IncDecOperator operator, T arg) {
+ handleLocal(node);
+ handleOperator(node);
+ handleNSMError(node);
+ }
+
+ void visitFinalLocalVariableSet(
+ SendSet node, LocalVariableElement variable, Node rhs, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitFinalLocalVariableSetIfNull(
+ SendSet node, LocalVariableElement variable, Node rhs, T arg) {
+ handleLocal(node); // read for null
+ handleNSMError(node); // set fails
+ }
+
+ void visitFinalParameterCompound(Send node, ParameterElement parameter,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleLocal(node);
+ handleOperator(node);
+ handleNSMError(node);
+ }
+
+ void visitFinalParameterPostfix(
+ Send node, ParameterElement parameter, IncDecOperator operator, T arg) {
+ handleLocal(node);
+ handleOperator(node);
+ handleNSMError(node);
+ }
+
+ void visitFinalParameterPrefix(
+ Send node, ParameterElement parameter, IncDecOperator operator, T arg) {
+ handleLocal(node);
+ handleOperator(node);
+ handleNSMError(node);
+ }
+
+ void visitFinalParameterSet(
+ SendSet node, ParameterElement parameter, Node rhs, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitFinalParameterSetIfNull(
+ SendSet node, ParameterElement parameter, Node rhs, T arg) {
+ handleLocal(node);
+ handleNSMError(node);
+ }
+
+ void visitFinalStaticFieldCompound(Send node, FieldElement field,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleStatic(node);
+ handleOperator(node);
+ handleNSMError(node);
+ }
+
+ void visitFinalStaticFieldPostfix(
+ Send node, FieldElement field, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleOperator(node);
+ handleNSMError(node);
+ }
+
+ void visitFinalStaticFieldPrefix(
+ Send node, FieldElement field, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleOperator(node);
+ handleNSMError(node);
+ }
+
+ void visitFinalStaticFieldSet(
+ SendSet node, FieldElement field, Node rhs, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitFinalStaticFieldSetIfNull(
+ SendSet node, FieldElement field, Node rhs, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ }
+
+ void visitFinalSuperFieldSetIfNull(Send node, FieldElement field,
+ Node rhs, T arg) {
+ handleSuper(node);
+ handleNSMSuper(node, field.enclosingClass);
+ }
+
+ void visitFinalSuperFieldCompound(Send node, FieldElement field,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleNSMSuper(node, field.enclosingClass);
+ }
+
+ void visitFinalSuperFieldPostfix(
+ Send node, FieldElement field, IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleNSMSuper(node, field.enclosingClass);
+ }
+
+ void visitFinalSuperFieldPrefix(
+ Send node, FieldElement field, IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleNSMSuper(node, field.enclosingClass);
+ }
+
+ void visitFinalSuperFieldSet(
+ SendSet node, FieldElement field, Node rhs, T arg) {
+ handleNSMSuper(node, field.enclosingClass);
+ }
+
+ void visitFinalTopLevelFieldCompound(Send node, FieldElement field,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleStatic(node);
+ handleOperator(node);
+ handleNSMError(node);
+ }
+
+ void visitFinalTopLevelFieldPostfix(
+ Send node, FieldElement field, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleOperator(node);
+ handleNSMError(node);
+ }
+
+ void visitFinalTopLevelFieldPrefix(
+ Send node, FieldElement field, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleOperator(node);
+ handleNSMError(node);
+ }
+
+ void visitFinalTopLevelFieldSet(
+ SendSet node, FieldElement field, Node rhs, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitFinalTopLevelFieldSetIfNull(
+ SendSet node, FieldElement field, Node rhs, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ }
+
+ void visitTopLevelGetterSetterSetIfNull(Send node, FunctionElement getter,
+ FunctionElement setter, Node rhs, T arg) {
+ handleStatic(node);
+ handleStatic(node);
+ }
+
+ void visitTopLevelMethodSetterSetIfNull(Send node, FunctionElement method,
+ FunctionElement setter, Node rhs, T arg) {
+ handleStatic(node);
+ handleStatic(node);
+ }
+
+ void visitTopLevelMethodSetIfNull(Send node, FunctionElement method,
+ Node rhs, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ }
+
+ void visitLocalFunctionIncompatibleInvoke(Send node,
+ LocalFunctionElement function, NodeList arguments,
+ CallStructure callStructure, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitLocalFunctionCompound(Send node, LocalFunctionElement function,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleLocal(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitLocalFunctionPostfix(Send node, LocalFunctionElement function,
+ IncDecOperator operator, T arg) {
+ handleLocal(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitLocalFunctionPrefix(Send node, LocalFunctionElement function,
+ IncDecOperator operator, T arg) {
+ handleLocal(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitLocalFunctionSet(
+ SendSet node, LocalFunctionElement function, Node rhs, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitLocalFunctionSetIfNull(
+ SendSet node, LocalFunctionElement function, Node rhs, T arg) {
+ handleLocal(node);
+ handleNSMError(node);
+ }
+
+ void visitStaticFunctionIncompatibleInvoke(Send node, MethodElement function,
+ NodeList arguments, CallStructure callStructure, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitStaticFunctionSet(
+ Send node, MethodElement function, Node rhs, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitStaticMethodCompound(Send node, MethodElement method,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleStatic(node);
+ handleNSMError(node); // operator on a method closure yields nSM
+ handleNoSend(node); // setter is not invoked, don't count it.
+ }
+
+ void visitStaticMethodPostfix(
+ Send node, MethodElement method, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitStaticMethodPrefix(
+ Send node, MethodElement method, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitStaticMethodSetterCompound(Send node, MethodElement method,
+ MethodElement setter, AssignmentOperator operator, Node rhs, T arg) {
+ handleStatic(node);
+ handleNSMError(node); // operator on a method closure yields nSM
+ handleNoSend(node); // setter is not invoked, don't count it.
+ }
+
+ void visitStaticMethodSetterPostfix(Send node, FunctionElement getter,
+ FunctionElement setter, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitStaticMethodSetterPrefix(Send node, FunctionElement getter,
+ FunctionElement setter, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitStaticSetterGet(Send node, FunctionElement setter, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitStaticSetterInvoke(Send node, FunctionElement setter,
+ NodeList arguments, CallStructure callStructure, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitSuperMethodCompound(Send node, FunctionElement method,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleSuper(node);
+
+ // An operator send on a method closure yields nSM
+ handleNSMSuper(node, method.enclosingClass);
+
+ handleNoSend(node); // setter is not invoked, don't count it.
+ }
+
+ void visitSuperMethodIncompatibleInvoke(Send node, MethodElement method,
+ NodeList arguments, CallStructure callStructure, T arg) {
+ handleNSMSuper(node, method.enclosingClass);
+ }
+
+ void visitSuperMethodPostfix(
+ Send node, FunctionElement method, IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleNSMSuper(node, method.enclosingClass);
+ handleNoSend(node);
+ }
+
+ void visitSuperMethodPrefix(
+ Send node, FunctionElement method, IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleNSMSuper(node, method.enclosingClass);
+ handleNoSend(node);
+ }
+
+ void visitSuperMethodSet(Send node, MethodElement method, Node rhs, T arg) {
+ handleNSMSuper(node, method.enclosingClass);
+ }
+
+ void visitSuperMethodSetIfNull(
+ Send node, MethodElement method, Node rhs, T arg) {
+ handleNSMSuper(node, method.enclosingClass);
+ }
+
+ void visitSuperSetterGet(Send node, FunctionElement setter, T arg) {
+ handleNSMSuper(node, setter.enclosingClass);
+ }
+
+ void visitSuperSetterInvoke(Send node, FunctionElement setter,
+ NodeList arguments, CallStructure callStructure, T arg) {
+ handleNSMSuper(node, setter.enclosingClass);
+ }
+
+ void visitTopLevelFunctionIncompatibleInvoke(Send node,
+ MethodElement function, NodeList arguments, CallStructure callStructure,
+ T arg) {
+ handleNSMError(node);
+ }
+
+ void visitTopLevelFunctionSet(
+ Send node, MethodElement function, Node rhs, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitTopLevelGetterSet(
+ SendSet node, FunctionElement getter, Node rhs, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitTopLevelMethodCompound(Send node, FunctionElement method,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleStatic(node);
+ handleNSMError(node); // operator on a method closure yields nSM
+ handleNoSend(node); // setter is not invoked, don't count it.
+ }
+
+ void visitTopLevelMethodPostfix(
+ Send node, MethodElement method, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitTopLevelMethodPrefix(
+ Send node, MethodElement method, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitTopLevelMethodSetterCompound(Send node, FunctionElement method,
+ FunctionElement setter, AssignmentOperator operator, Node rhs, T arg) {
+ handleStatic(node);
+ handleNSMError(node); // operator on a method closure yields nSM
+ handleNoSend(node); // setter is not invoked, don't count it.
+ }
+
+ void visitTopLevelMethodSetterPostfix(Send node, FunctionElement method,
+ FunctionElement setter, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitTopLevelMethodSetterPrefix(Send node, FunctionElement method,
+ FunctionElement setter, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitTopLevelSetterGet(Send node, FunctionElement setter, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitTopLevelSetterInvoke(Send node, FunctionElement setter,
+ NodeList arguments, CallStructure callStructure, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitTypeVariableTypeLiteralCompound(Send node,
+ TypeVariableElement element, AssignmentOperator operator, Node rhs,
+ T arg) {
+ handleTypeVariable(node);
+ handleNSMError(node); // operator on a method closure yields nSM
+ handleNoSend(node); // setter is not invoked, don't count it.
+ }
+
+ void visitTypeVariableTypeLiteralGet(
+ Send node, TypeVariableElement element, T arg) {
+ handleTypeVariable(node);
+ }
+
+ void visitTypeVariableTypeLiteralInvoke(Send node,
+ TypeVariableElement element, NodeList arguments,
+ CallStructure callStructure, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitTypeVariableTypeLiteralPostfix(
+ Send node, TypeVariableElement element, IncDecOperator operator, T arg) {
+ handleTypeVariable(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitTypeVariableTypeLiteralPrefix(
+ Send node, TypeVariableElement element, IncDecOperator operator, T arg) {
+ handleTypeVariable(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitTypeVariableTypeLiteralSet(
+ SendSet node, TypeVariableElement element, Node rhs, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitTypeVariableTypeLiteralSetIfNull(
+ SendSet node, TypeVariableElement element, Node rhs, T arg) {
+ handleTypeVariable(node);
+ handleNSMError(node);
+ }
+
+ void visitTypedefTypeLiteralCompound(Send node, ConstantExpression constant,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleTypeVariable(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitTypedefTypeLiteralGet(
+ Send node, ConstantExpression constant, T arg) {
+ handleTypeVariable(node);
+ }
+
+ void visitTypedefTypeLiteralInvoke(Send node, ConstantExpression constant,
+ NodeList arguments, CallStructure callStructure, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitTypedefTypeLiteralPostfix(
+ Send node, ConstantExpression constant, IncDecOperator operator, T arg) {
+ handleTypeVariable(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitTypedefTypeLiteralPrefix(
+ Send node, ConstantExpression constant, IncDecOperator operator, T arg) {
+ handleTypeVariable(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitTypedefTypeLiteralSet(
+ SendSet node, ConstantExpression constant, Node rhs, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitTypedefTypeLiteralSetIfNull(
+ SendSet node, ConstantExpression constant, Node rhs, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ }
+
+ void visitUnresolvedClassConstructorInvoke(NewExpression node,
+ Element element, DartType type, NodeList arguments, Selector selector,
+ T arg) {
+ handleNSMError(node);
+ }
+
+ void visitUnresolvedCompound(Send node, Element element,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedConstructorInvoke(NewExpression node, Element constructor,
+ DartType type, NodeList arguments, Selector selector, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitUnresolvedGet(Send node, Element element, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitUnresolvedInvoke(Send node, Element element, NodeList arguments,
+ Selector selector, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitUnresolvedPostfix(
+ Send node, Element element, IncDecOperator operator, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedPrefix(
+ Send node, Element element, IncDecOperator operator, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedRedirectingFactoryConstructorInvoke(NewExpression node,
+ ConstructorElement constructor, InterfaceType type, NodeList arguments,
+ CallStructure callStructure, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitUnresolvedSet(Send node, Element element, Node rhs, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitUnresolvedSetIfNull(Send node, Element element, Node rhs, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedStaticGetterCompound(Send node, Element element,
+ MethodElement setter, AssignmentOperator operator, Node rhs, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedStaticGetterPostfix(Send node, Element element,
+ MethodElement setter, IncDecOperator operator, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedStaticGetterPrefix(Send node, Element element,
+ MethodElement setter, IncDecOperator operator, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedStaticGetterSetIfNull(Send node, Element element,
+ MethodElement setter, Node rhs, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedStaticSetterCompound(Send node, MethodElement getter,
+ Element element, AssignmentOperator operator, Node rhs, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedStaticSetterPostfix(Send node, MethodElement getter,
+ Element element, IncDecOperator operator, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedStaticSetterPrefix(Send node, MethodElement getter,
+ Element element, IncDecOperator operator, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedStaticSetterSetIfNull(Send node, MethodElement getter,
+ Element element, Node rhs, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedSuperBinary(Send node, Element element,
+ BinaryOperator operator, Node argument, T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ }
+
+ void visitUnresolvedSuperCompound(Send node, Element element,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ // TODO(sigmund): we should only count the next 2 if we know that the
+ // superclass has a nSM method.
+ handleOperator(node);
+ handleNSMSuper(node, element.enclosingClass);
+ }
+
+ void visitUnresolvedSuperCompoundIndexSet(Send node, Element element,
+ Node index, AssignmentOperator operator, Node rhs, T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ handleNoSend(node);
+ handleNSMSuper(node, element.enclosingClass);
+ }
+
+ void visitUnresolvedSuperGet(Send node, Element element, T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ }
+
+ void visitUnresolvedSuperSetIfNull(
+ Send node, Element element, Node rhs, T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedSuperGetterCompound(Send node, Element element,
+ MethodElement setter, AssignmentOperator operator, Node rhs, T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitUnresolvedSuperGetterCompoundIndexSet(Send node, Element element,
+ MethodElement setter, Node index, AssignmentOperator operator, Node rhs,
+ T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitUnresolvedSuperGetterIndexPostfix(Send node, Element element,
+ MethodElement setter, Node index, IncDecOperator operator, T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitUnresolvedSuperGetterIndexPrefix(Send node, Element element,
+ MethodElement setter, Node index, IncDecOperator operator, T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitUnresolvedSuperGetterPostfix(Send node, Element element,
+ MethodElement setter, IncDecOperator operator, T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitUnresolvedSuperGetterPrefix(Send node, Element element,
+ MethodElement setter, IncDecOperator operator, T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitUnresolvedSuperGetterSetIfNull(Send node, Element element,
+ MethodElement setter, Node rhs, T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ handleSuper(node);
+ }
+
+ void visitUnresolvedSuperIndex(
+ Send node, Element element, Node index, T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ }
+
+ void visitUnresolvedSuperIndexPostfix(
+ Send node, Element element, Node index, IncDecOperator operator, T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ handleOperator(node);
+ handleNSMSuper(node, element.enclosingClass);
+ }
+
+ void visitUnresolvedSuperIndexPrefix(
+ Send node, Element element, Node index, IncDecOperator operator, T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ handleOperator(node);
+ handleNSMSuper(node, element.enclosingClass);
+ }
+
+ void visitUnresolvedSuperIndexSet(
+ Send node, Element element, Node index, Node rhs, T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ }
+
+ void visitUnresolvedSuperInvoke(Send node, Element element,
+ NodeList arguments, Selector selector, T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ }
+
+ void visitUnresolvedSuperPostfix(
+ Send node, Element element, IncDecOperator operator, T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ handleOperator(node);
+ handleNSMSuper(node, element.enclosingClass);
+ }
+
+ void visitUnresolvedSuperPrefix(
+ Send node, Element element, IncDecOperator operator, T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ handleOperator(node);
+ handleNSMSuper(node, element.enclosingClass);
+ }
+
+ void visitUnresolvedSuperSetterCompound(Send node, MethodElement getter,
+ Element element, AssignmentOperator operator, Node rhs, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleNSMSuper(node, element.enclosingClass);
+ }
+
+ void visitUnresolvedSuperSetterCompoundIndexSet(Send node,
+ MethodElement getter, Element element, Node index,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleNSMSuper(node, element.enclosingClass);
+ }
+
+ void visitUnresolvedSuperSetterIndexPostfix(Send node,
+ MethodElement indexFunction, Element element, Node index,
+ IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleNSMSuper(node, element.enclosingClass);
+ }
+
+ void visitUnresolvedSuperSetterIndexPrefix(Send node,
+ MethodElement indexFunction, Element element, Node index,
+ IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleNSMSuper(node, element.enclosingClass);
+ }
+
+ void visitUnresolvedSuperSetterPostfix(Send node, MethodElement getter,
+ Element element, IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleNSMSuper(node, element.enclosingClass);
+ }
+
+ void visitUnresolvedSuperSetterPrefix(Send node, MethodElement getter,
+ Element element, IncDecOperator operator, T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleNSMSuper(node, element.enclosingClass);
+ }
+
+ void visitUnresolvedSuperSetterSetIfNull(Send node, MethodElement getter,
+ Element element, Node rhs, T arg) {
+ handleSuper(node);
+ handleNSMSuper(node, element.enclosingClass);
+ }
+
+ void visitUnresolvedSuperUnary(
+ Send node, UnaryOperator operator, Element element, T arg) {
+ handleNSMSuper(node, element.enclosingClass);
+ }
+
+ void visitUnresolvedTopLevelGetterCompound(Send node, Element element,
+ MethodElement setter, AssignmentOperator operator, Node rhs, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedTopLevelGetterPostfix(Send node, Element element,
+ MethodElement setter, IncDecOperator operator, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedTopLevelGetterPrefix(Send node, Element element,
+ MethodElement setter, IncDecOperator operator, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedTopLevelGetterSetIfNull(Send node, Element element,
+ MethodElement setter, Node rhs, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedTopLevelSetterCompound(Send node, MethodElement getter,
+ Element element, AssignmentOperator operator, Node rhs, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedTopLevelSetterPostfix(Send node, MethodElement getter,
+ Element element, IncDecOperator operator, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedTopLevelSetterPrefix(Send node, MethodElement getter,
+ Element element, IncDecOperator operator, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ handleNoSend(node);
+ }
+
+ void visitUnresolvedTopLevelSetterSetIfNull(Send node, MethodElement getter,
+ Element element, Node rhs, T arg) {
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ // Static
+
+ void visitConstantGet(Send node, ConstantExpression constant, T arg) {
+ handleStatic(node);
+ }
+
+ void visitConstantInvoke(Send node, ConstantExpression constant,
+ NodeList arguments, CallStructure callStreucture, T arg) {
+ handleStatic(node);
+ }
+
+ void visitFactoryConstructorInvoke(NewExpression node,
+ ConstructorElement constructor, InterfaceType type, NodeList arguments,
+ CallStructure callStructure, T arg) {
+ handleStatic(node);
+ }
+
+ void visitStaticFieldGet(Send node, FieldElement field, T arg) {
+ handleStatic(node);
+ }
+
+ void visitStaticFieldSet(SendSet node, FieldElement field, Node rhs, T arg) {
+ handleStatic(node);
+ }
+
+ void visitStaticFieldSetIfNull(
+ SendSet node, FieldElement field, Node rhs, T arg) {
+ handleStatic(node);
+ handleStatic(node);
+ }
+
+ void visitStaticFunctionGet(Send node, MethodElement function, T arg) {
+ handleStatic(node);
+ }
+
+ void visitStaticFunctionInvoke(Send node, MethodElement function,
+ NodeList arguments, CallStructure callStructure, T arg) {
+ handleStatic(node);
+ }
+
+ void visitStaticGetterGet(Send node, FunctionElement getter, T arg) {
+ handleStatic(node);
+ }
+
+ void visitStaticGetterSet(
+ SendSet node, FunctionElement getter, Node rhs, T arg) {
+ handleStatic(node);
+ }
+
+ void visitStaticSetterSet(
+ SendSet node, FunctionElement setter, Node rhs, T arg) {
+ handleStatic(node);
+ }
+
+ void visitStaticGetterSetterSetIfNull(
+ Send node,
+ FunctionElement getter,
+ FunctionElement setter,
+ Node rhs,
+ T arg) {
+ handleStatic(node);
+ handleStatic(node);
+ }
+
+ void visitStaticMethodSetterSetIfNull(
+ Send node,
+ MethodElement method,
+ MethodElement setter,
+ Node rhs,
+ T arg) {
+ handleStatic(node);
+ handleStatic(node);
+ }
+
+ void visitStaticMethodSetIfNull(
+ Send node,
+ FunctionElement method,
+ Node rhs,
+ T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ }
+
+ void visitTopLevelFieldGet(Send node, FieldElement field, T arg) {
+ handleStatic(node);
+ }
+
+ void visitTopLevelFieldSet(
+ SendSet node, FieldElement field, Node rhs, T arg) {
+ handleStatic(node);
+ }
+
+ void visitTopLevelFieldSetIfNull(
+ SendSet node, FieldElement field, Node rhs, T arg) {
+ handleStatic(node);
+ handleStatic(node);
+ }
+
+ void visitTopLevelFunctionGet(Send node, MethodElement function, T arg) {
+ handleStatic(node);
+ }
+
+ void visitTopLevelFunctionInvoke(Send node, MethodElement function,
+ NodeList arguments, CallStructure callStructure, T arg) {
+ handleStatic(node);
+ }
+
+ void visitTopLevelGetterGet(Send node, FunctionElement getter, T arg) {
+ handleStatic(node);
+ }
+
+ void visitTopLevelSetterSet(
+ SendSet node, FunctionElement setter, Node rhs, T arg) {
+ handleStatic(node);
+ }
+
+ // Virtual
+
+ void visitSuperCompoundIndexSet(SendSet node, MethodElement getter,
+ MethodElement setter, Node index, AssignmentOperator operator, Node rhs,
+ T arg) {
+ handleSuper(node);
+ handleOperator(node);
+ handleSuper(node);
+ }
+
+ void visitThisGet(Identifier node, T arg) {
+ handleLocal(node); // TODO(sigmund): should we add a metric for "this"?
+ }
+
+ void visitThisInvoke(
+ Send node, NodeList arguments, CallStructure callStructure, T arg) {
+ // TODO(sigmund): implement (treat like this.call())
+ handleDynamic(node);
+ }
+
+ void visitThisPropertyGet(Send node, Name name, T arg) {
+ handleThisProperty(node, new Selector.getter(name));
+ }
+
+ void visitThisPropertySet(SendSet node, Name name, Node rhs, T arg) {
+ handleThisProperty(node, new Selector.setter(name));
+ }
+
+ void visitThisPropertySetIfNull(Send node, Name name, Node rhs, T arg) {
+ handleThisProperty(node, new Selector.getter(name));
+ handleThisProperty(node, new Selector.setter(name));
+ }
+
+ // Not count
+
+ void errorNonConstantConstructorInvoke(NewExpression node, Element element,
+ DartType type, NodeList arguments, CallStructure callStructure, T arg) {
+ handleNoSend(node);
+ }
+
+ void errorUndefinedBinaryExpression(
+ Send node, Node left, Operator operator, Node right, T arg) {
+ handleNoSend(node);
+ }
+
+ void errorUndefinedUnaryExpression(
+ Send node, Operator operator, Node expression, T arg) {
+ handleNoSend(node);
+ }
+
+ void errorInvalidGet(
+ Send node,
+ ErroneousElement error,
+ T arg) {
+ handleNoSend(node);
+ }
+
+ void errorInvalidInvoke(
+ Send node,
+ ErroneousElement error,
+ NodeList arguments,
+ Selector selector,
+ T arg) {
+ handleNoSend(node);
+ }
+
+ void errorInvalidSet(
+ Send node,
+ ErroneousElement error,
+ Node rhs,
+ T arg) {
+ handleNoSend(node);
+ }
+
+ void errorInvalidSetIfNull(
+ Send node, ErroneousElement error, Node rhs, T arg) {
+ handleNoSend(node);
+ handleNoSend(node);
+ }
+
+
+ void errorInvalidPrefix(
+ Send node,
+ ErroneousElement error,
+ IncDecOperator operator,
+ T arg) {
+ handleNoSend(node);
+ }
+
+ void errorInvalidPostfix(
+ Send node,
+ ErroneousElement error,
+ IncDecOperator operator,
+ T arg) {
+ handleNoSend(node);
+ }
+
+ void errorInvalidCompound(
+ Send node,
+ ErroneousElement error,
+ AssignmentOperator operator,
+ Node rhs,
+ T arg) {
+ handleNoSend(node);
+ }
+
+ void errorInvalidUnary(
+ Send node,
+ UnaryOperator operator,
+ ErroneousElement error,
+ T arg) {
+ handleNoSend(node);
+ }
+
+ void errorInvalidEquals(
+ Send node,
+ ErroneousElement error,
+ Node right,
+ T arg) {
+ handleNoSend(node);
+ }
+
+ void errorInvalidNotEquals(
+ Send node,
+ ErroneousElement error,
+ Node right,
+ T arg) {
+ handleNoSend(node);
+ }
+
+ void errorInvalidBinary(
+ Send node,
+ ErroneousElement error,
+ BinaryOperator operator,
+ Node right,
+ T arg) {
+ handleNoSend(node);
+ }
+
+ void errorInvalidIndex(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ T arg) {
+ handleNoSend(node);
+ }
+
+ void errorInvalidIndexSet(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ Node rhs,
+ T arg) {
+ handleNoSend(node);
+ }
+
+ void errorInvalidCompoundIndexSet(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ AssignmentOperator operator,
+ Node rhs,
+ T arg) {
+ handleNoSend(node);
+ handleNoSend(node);
+ handleNoSend(node);
+ }
+
+ void errorInvalidIndexPrefix(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ IncDecOperator operator,
+ T arg) {
+ handleNoSend(node);
+ handleNoSend(node);
+ }
+
+ void errorInvalidIndexPostfix(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ IncDecOperator operator,
+ T arg) {
+ handleNoSend(node);
+ handleNoSend(node);
+ }
+
+ void previsitDeferredAccess(
+ Send node,
+ PrefixElement prefix,
+ T arg) {
+ }
+
+
+ void visitAs(Send node, Node expression, DartType type, T arg) {
+ handleNoSend(node);
+ }
+
+ void visitClassTypeLiteralCompound(Send node, ConstantExpression constant,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitClassTypeLiteralGet(Send node, ConstantExpression constant, T arg) {
+ handleStatic(node);
+ }
+
+ void visitClassTypeLiteralInvoke(Send node, ConstantExpression constant,
+ NodeList arguments, CallStructure callStructure, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitClassTypeLiteralPostfix(
+ Send node, ConstantExpression constant, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitClassTypeLiteralPrefix(
+ Send node, ConstantExpression constant, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitClassTypeLiteralSet(
+ SendSet node, ConstantExpression constant, Node rhs, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitClassTypeLiteralSetIfNull(
+ SendSet node, ConstantExpression constant, Node rhs, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ }
+
+ void visitDynamicTypeLiteralCompound(Send node, ConstantExpression constant,
+ AssignmentOperator operator, Node rhs, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitDynamicTypeLiteralGet(
+ Send node, ConstantExpression constant, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitDynamicTypeLiteralInvoke(Send node, ConstantExpression constant,
+ NodeList arguments, CallStructure callStructure, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitDynamicTypeLiteralPostfix(
+ Send node, ConstantExpression constant, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitDynamicTypeLiteralPrefix(
+ Send node, ConstantExpression constant, IncDecOperator operator, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ handleNoSend(node);
+ }
+
+ void visitDynamicTypeLiteralSet(
+ SendSet node, ConstantExpression constant, Node rhs, T arg) {
+ handleNSMError(node);
+ }
+
+ void visitDynamicTypeLiteralSetIfNull(
+ SendSet node, ConstantExpression constant, Node rhs, T arg) {
+ handleStatic(node);
+ handleNSMError(node);
+ }
+
+ void visitIfNull(Send node, Node left, Node right, T arg) {
+ handleNoSend(node);
+ }
+
+ void visitIs(Send node, Node expression, DartType type, T arg) {
+ handleNoSend(node);
+ }
+
+ void visitIsNot(Send node, Node expression, DartType type, T arg) {
+ handleNoSend(node);
+ }
+
+ void visitLogicalAnd(Send node, Node left, Node right, T arg) {
+ handleNoSend(node);
+ }
+
+ void visitLogicalOr(Send node, Node left, Node right, T arg) {
+ handleNoSend(node);
+ }
+
+ void visitNot(Send node, Node expression, T arg) {
+ handleNoSend(node);
+ }
+
+ String last;
+ _checkInvariant(node, String msg) {
+ msg = '$msg ${recursiveDiagnosticString(measurements, Metric.send)}';
+ if (!measurements.checkInvariant(Metric.send) ||
+ !measurements.checkInvariant(Metric.monomorphicSend) ||
+ !measurements.checkInvariant(Metric.polymorphicSend)) {
+ reporter.reportErrorMessage(node,
+ MessageKind.GENERIC, {'text': 'bad\n-- $msg\nlast:\n-- $last\n'});
+ last = msg;
+ } else {
+ last = msg;
+ }
+ }
+}
+
+/// Visitor that collects statistics for a single function.
+class _StatsTraversalVisitor<T> extends TraversalVisitor<dynamic, T>
+ implements SemanticSendVisitor<dynamic, T> {
+ final DiagnosticReporter reporter;
+ final _StatsVisitor statsVisitor;
+ Measurements get measurements => statsVisitor.measurements;
+ _StatsTraversalVisitor(
+ Compiler compiler, TreeElements elements, Uri sourceUri)
+ : reporter = compiler.reporter,
+ statsVisitor = new _StatsVisitor(compiler.reporter, elements,
+ // TODO(sigmund): accept a list of analyses, so we can compare them
+ // together.
+ true
+ ? new TrustTypesAnalysisResult(elements, compiler.world)
+ : new NaiveAnalysisResult(),
+ sourceUri),
+ super(elements);
+
+ void visitSend(Send node) {
+ try {
+ node.accept(statsVisitor);
+ } catch (e, t) {
+ reporter.reportErrorMessage(
+ node, MessageKind.GENERIC, {'text': '$e\n$t'});
+ }
+ super.visitSend(node);
+ }
+
+ void visitNewExpression(NewExpression node) {
+ try {
+ node.accept(statsVisitor);
+ } catch (e, t) {
+ reporter.reportErrorMessage(
+ node, MessageKind.GENERIC, {'text': '$e\n$t'});
+ }
+ super.visitNewExpression(node);
+ }
+}
+
+/// Helper to visit elements recursively
+// TODO(sigmund): maybe generalize and move to elements/visitor.dart?
+abstract class RecursiveElementVisitor<R, A> extends ElementVisitor<R, A> {
+
+ @override
+ R visitWarnOnUseElement(WarnOnUseElement e, A arg) =>
+ e.wrappedElement.accept(this, arg);
+
+ R visitScopeContainerElement(ScopeContainerElement e, A arg) {
+ e.forEachLocalMember((l) => l.accept(this, arg));
+ return null;
+ }
+
+ @override
+ R visitCompilationUnitElement(CompilationUnitElement e, A arg) {
+ e.forEachLocalMember((l) => l.accept(this, arg));
+ return null;
+ }
+
+ @override
+ R visitLibraryElement(LibraryElement e, A arg) {
+ e.implementation.compilationUnits.forEach((u) => u.accept(this, arg));
+ return null;
+ }
+
+ @override
+ R visitVariableElement(VariableElement e, A arg) => null;
+
+ @override
+ R visitParameterElement(ParameterElement e, A arg) => null;
+
+ @override
+ R visitFormalElement(FormalElement e, A arg) => null;
+
+ @override
+ R visitFieldElement(FieldElement e, A arg) => null;
+
+ @override
+ R visitFieldParameterElement(InitializingFormalElement e, A arg) => null;
+
+ @override
+ R visitAbstractFieldElement(AbstractFieldElement e, A arg) => null;
+
+ @override
+ R visitFunctionElement(FunctionElement e, A arg) => null;
+
+ @override
+ R visitConstructorElement(ConstructorElement e, A arg) {
+ return visitFunctionElement(e, arg);
+ }
+
+ @override
+ R visitConstructorBodyElement(ConstructorBodyElement e, A arg) {
+ return visitFunctionElement(e.constructor, arg);
+ }
+
+ @override
+ R visitClassElement(ClassElement e, A arg) {
+ return visitScopeContainerElement(e, arg);
+ }
+
+ @override
+ R visitEnumClassElement(EnumClassElement e, A arg) {
+ return visitClassElement(e, arg);
+ }
+
+ @override
+ R visitBoxFieldElement(BoxFieldElement e, A arg) => null;
+
+ @override
+ R visitClosureClassElement(ClosureClassElement e, A arg) {
+ return visitClassElement(e, arg);
+ }
+
+ @override
+ R visitClosureFieldElement(ClosureFieldElement e, A arg) {
+ return visitVariableElement(e, arg);
+ }
+}
+
+// TODO(sigmund): get rid of debug messages.
+_debug(String message) {
+ print('[33mdebug:[0m $message');
+}
diff --git a/pkg/compiler/lib/src/info/trusted_types_analysis_result.dart b/pkg/compiler/lib/src/info/trusted_types_analysis_result.dart
new file mode 100644
index 0000000..8de59ae
--- /dev/null
+++ b/pkg/compiler/lib/src/info/trusted_types_analysis_result.dart
@@ -0,0 +1,104 @@
+// Copyright (c) 2015, 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.
+
+/// API to get results from a static analysis of the source program.
+// TODO(sigmund): split out implementations out of this file.
+library compiler.src.stats.trusted_types_analysis_result;
+
+import 'analysis_result.dart';
+import '../tree/tree.dart' show Node;
+import '../universe/selector.dart' show Selector;
+import '../resolution/tree_elements.dart' show TreeElements;
+import '../world.dart' show ClassWorld;
+import '../dart_types.dart' show InterfaceType;
+
+/// An [AnalysisResult] produced by using type-propagation based on
+/// trusted type annotations.
+class TrustTypesAnalysisResult implements AnalysisResult {
+ final ClassWorld world;
+ final TreeElements elements;
+
+ TrustTypesAnalysisResult(this.elements, this.world);
+
+ ReceiverInfo infoForReceiver(Node receiver) =>
+ new TrustTypesReceiverInfo(receiver, elements.typesCache[receiver], world);
+ SelectorInfo infoForSelector(Node receiver, Selector selector) =>
+ new TrustTypesSelectorInfo(
+ receiver, elements.typesCache[receiver], selector, world);
+}
+
+class _SelectorLookupResult {
+ final Boolish exists;
+ // TODO(sigmund): implement
+ final Boolish usesInterceptor = Boolish.no;
+ final int possibleTargets;
+
+ _SelectorLookupResult(this.exists, this.possibleTargets);
+
+ const _SelectorLookupResult.dontKnow()
+ : exists = Boolish.maybe, possibleTargets = -1;
+}
+
+_SelectorLookupResult _lookupSelector(
+ String selectorName, InterfaceType type, ClassWorld world) {
+ if (type == null) return const _SelectorLookupResult.dontKnow();
+ bool isNsm = selectorName == 'noSuchMethod';
+ bool notFound = false;
+ var uniqueTargets = new Set();
+ for (var cls in world.subtypesOf(type.element)) {
+ var member = cls.lookupMember(selectorName);
+ if (member != null && !member.isAbstract
+ // Don't match nsm in Object
+ && (!isNsm || !member.enclosingClass.isObject)) {
+ uniqueTargets.add(member);
+ } else {
+ notFound = true;
+ }
+ }
+ Boolish exists = uniqueTargets.length > 0
+ ? (notFound ? Boolish.maybe : Boolish.yes)
+ : Boolish.no;
+ return new _SelectorLookupResult(exists, uniqueTargets.length);
+}
+
+class TrustTypesReceiverInfo implements ReceiverInfo {
+ final Node receiver;
+ final Boolish hasNoSuchMethod;
+ final int possibleNsmTargets;
+ final Boolish isNull = Boolish.maybe;
+
+ factory TrustTypesReceiverInfo(
+ Node receiver, InterfaceType type, ClassWorld world) {
+ // TODO(sigmund): refactor, maybe just store nsm as a SelectorInfo
+ var res = _lookupSelector('noSuchMethod', type, world);
+ return new TrustTypesReceiverInfo._(receiver,
+ res.exists, res.possibleTargets);
+ }
+
+ TrustTypesReceiverInfo._(this.receiver, this.hasNoSuchMethod,
+ this.possibleNsmTargets);
+}
+
+class TrustTypesSelectorInfo implements SelectorInfo {
+ final Node receiver;
+ final Selector selector;
+
+ final Boolish exists;
+ final Boolish usesInterceptor;
+ final int possibleTargets;
+ final bool isAccurate;
+
+ factory TrustTypesSelectorInfo(Node receiver, InterfaceType type,
+ Selector selector, ClassWorld world) {
+ var res = _lookupSelector(
+ selector != null ? selector.name : null, type, world);
+ return new TrustTypesSelectorInfo._(receiver, selector, res.exists,
+ res.usesInterceptor, res.possibleTargets,
+ res.exists != Boolish.maybe);
+ }
+ TrustTypesSelectorInfo._(
+ this.receiver, this.selector, this.exists, this.usesInterceptor,
+ this.possibleTargets, this.isAccurate);
+}
+
diff --git a/pkg/compiler/lib/src/js/js.dart b/pkg/compiler/lib/src/js/js.dart
index 7618b96..a72da8f 100644
--- a/pkg/compiler/lib/src/js/js.dart
+++ b/pkg/compiler/lib/src/js/js.dart
@@ -9,6 +9,8 @@
import '../compiler.dart' show
Compiler;
+import '../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import '../diagnostics/spannable.dart' show
NO_LOCATION_SPANNABLE;
import '../dump_info.dart' show
@@ -40,7 +42,7 @@
new SourceLocationsMapper(outBuffer));
Dart2JSJavaScriptPrintingContext context =
new Dart2JSJavaScriptPrintingContext(
- compiler, monitor, outBuffer, sourceInformationProcessor);
+ compiler.reporter, monitor, outBuffer, sourceInformationProcessor);
Printer printer = new Printer(options, context);
printer.visit(node);
sourceInformationProcessor.process(node);
@@ -48,20 +50,20 @@
}
class Dart2JSJavaScriptPrintingContext implements JavaScriptPrintingContext {
- final Compiler compiler;
+ final DiagnosticReporter reporter;
final DumpInfoTask monitor;
final CodeBuffer outBuffer;
final CodePositionListener codePositionListener;
Dart2JSJavaScriptPrintingContext(
- this.compiler,
+ this.reporter,
this.monitor,
this.outBuffer,
this.codePositionListener);
@override
void error(String message) {
- compiler.internalError(NO_LOCATION_SPANNABLE, message);
+ reporter.internalError(NO_LOCATION_SPANNABLE, message);
}
@override
diff --git a/pkg/compiler/lib/src/js/rewrite_async.dart b/pkg/compiler/lib/src/js/rewrite_async.dart
index e1e90c3..854213b 100644
--- a/pkg/compiler/lib/src/js/rewrite_async.dart
+++ b/pkg/compiler/lib/src/js/rewrite_async.dart
@@ -158,7 +158,7 @@
js.VariableUse get self => new js.VariableUse(selfName);
String selfName;
- final DiagnosticListener diagnosticListener;
+ final DiagnosticReporter reporter;
// For error reporting only.
Spannable get spannable {
return (_spannable == null) ? NO_LOCATION_SPANNABLE : _spannable;
@@ -178,11 +178,10 @@
bool get isSyncStar => false;
bool get isAsyncStar => false;
- AsyncRewriterBase(this.diagnosticListener,
- spannable,
+ AsyncRewriterBase(this.reporter,
+ this._spannable,
this.safeVariableName,
- this.bodyName)
- : _spannable = spannable;
+ this.bodyName);
/// Initialize names used by the subClass.
void initializeNames();
@@ -352,7 +351,7 @@
}
void unreachable(js.Node node) {
- diagnosticListener.internalError(
+ reporter.internalError(
spannable, "Internal error, trying to visit $node");
}
@@ -1376,7 +1375,7 @@
clauses.add(new js.Default(gotoAndBreak(labels[i])));
hasDefault = true;
} else {
- diagnosticListener.internalError(
+ reporter.internalError(
spannable, "Unknown clause type $clause");
}
i++;
@@ -1695,21 +1694,21 @@
final js.Expression wrapBody;
- AsyncRewriter(DiagnosticListener diagnosticListener,
- spannable,
+ AsyncRewriter(DiagnosticReporter reporter,
+ Spannable spannable,
{this.asyncHelper,
this.newCompleter,
this.wrapBody,
String safeVariableName(String proposedName),
js.Name bodyName})
- : super(diagnosticListener,
+ : super(reporter,
spannable,
safeVariableName,
bodyName);
@override
void addYield(js.DartYield node, js.Expression expression) {
- diagnosticListener.internalError(spannable,
+ reporter.internalError(spannable,
"Yield in non-generating async function");
}
@@ -1827,7 +1826,7 @@
/// Used by sync* functions to throw exeptions.
final js.Expression uncaughtErrorExpression;
- SyncStarRewriter(DiagnosticListener diagnosticListener,
+ SyncStarRewriter(DiagnosticReporter diagnosticListener,
spannable,
{this.endOfIteration,
this.newIterable,
@@ -1937,7 +1936,7 @@
@override
js.Statement awaitStatement(js.Expression value) {
- throw diagnosticListener.internalError(spannable,
+ throw reporter.internalError(spannable,
"Sync* functions cannot contain await statements.");
}
@@ -1998,17 +1997,17 @@
final js.Expression wrapBody;
- AsyncStarRewriter(DiagnosticListener diagnosticListener,
- spannable,
- {this.asyncStarHelper,
- this.streamOfController,
- this.newController,
- this.yieldExpression,
- this.yieldStarExpression,
- this.wrapBody,
- String safeVariableName(String proposedName),
- js.Name bodyName})
- : super(diagnosticListener,
+ AsyncStarRewriter(DiagnosticReporter reporter,
+ Spannable spannable,
+ {this.asyncStarHelper,
+ this.streamOfController,
+ this.newController,
+ this.yieldExpression,
+ this.yieldStarExpression,
+ this.wrapBody,
+ String safeVariableName(String proposedName),
+ js.Name bodyName})
+ : super(reporter,
spannable,
safeVariableName,
bodyName);
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index ff254c9d..cbf7de4 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -652,7 +652,7 @@
compiler, namer, generateSourceMap, useStartupEmitter);
typeVariableHandler = new TypeVariableHandler(compiler);
customElementsAnalysis = new CustomElementsAnalysis(this);
- lookupMapAnalysis = new LookupMapAnalysis(this);
+ lookupMapAnalysis = new LookupMapAnalysis(this, reporter);
noSuchMethodRegistry = new NoSuchMethodRegistry(this);
constantCompilerTask = new JavaScriptConstantTask(compiler);
resolutionCallbacks = new JavaScriptResolutionCallbacks(this);
@@ -665,6 +665,10 @@
ConstantSystem get constantSystem => constants.constantSystem;
+ DiagnosticReporter get reporter => compiler.reporter;
+
+ Resolution get resolution => compiler.resolution;
+
/// Returns constant environment for the JavaScript interpretation of the
/// constants.
JavaScriptConstantCompiler get constants {
@@ -886,7 +890,7 @@
void validateInterceptorImplementsAllObjectMethods(
ClassElement interceptorClass) {
if (interceptorClass == null) return;
- interceptorClass.ensureResolved(compiler);
+ interceptorClass.ensureResolved(resolution);
compiler.objectClass.forEachMember((_, Element member) {
if (member.isGenerativeConstructor) return;
Element interceptorMember = interceptorClass.lookupMember(member.name);
@@ -899,10 +903,10 @@
void addInterceptorsForNativeClassMembers(
ClassElement cls, Enqueuer enqueuer) {
if (enqueuer.isResolutionQueue) {
- cls.ensureResolved(compiler);
+ cls.ensureResolved(resolution);
cls.forEachMember((ClassElement classElement, Element member) {
if (member.name == Identifiers.call) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
member,
MessageKind.CALL_NOT_SUPPORTED_ON_NATIVE_CLASS);
return;
@@ -932,7 +936,7 @@
if (enqueuer.isResolutionQueue) {
_interceptedClasses.add(jsInterceptorClass);
_interceptedClasses.add(cls);
- cls.ensureResolved(compiler);
+ cls.ensureResolved(resolution);
cls.forEachMember((ClassElement classElement, Element member) {
// All methods on [Object] are shadowed by [Interceptor].
if (classElement == compiler.objectClass) return;
@@ -1087,7 +1091,7 @@
if (ctor == null
|| (Name.isPrivateName(name)
&& ctor.library != mapLiteralClass.library)) {
- compiler.internalError(mapLiteralClass,
+ reporter.internalError(mapLiteralClass,
"Map literal class $mapLiteralClass missing "
"'$name' constructor"
" ${mapLiteralClass.constructors}");
@@ -1100,7 +1104,7 @@
ClassElement implementation = cls.patch != null ? cls.patch : cls;
Element element = implementation.lookupLocalMember(name);
if (element == null || !element.isFunction || !element.isStatic) {
- compiler.internalError(mapLiteralClass,
+ reporter.internalError(mapLiteralClass,
"Map literal class $mapLiteralClass missing "
"'$name' static member function");
}
@@ -1264,7 +1268,7 @@
}
void registerBoundClosure(Enqueuer enqueuer) {
- boundClosureClass.ensureResolved(compiler);
+ boundClosureClass.ensureResolved(resolution);
registerInstantiatedType(
boundClosureClass.rawType,
enqueuer,
@@ -1273,7 +1277,7 @@
}
void registerGetOfStaticFunction(Enqueuer enqueuer) {
- closureClass.ensureResolved(compiler);
+ closureClass.ensureResolved(resolution);
registerInstantiatedType(
closureClass.rawType,
enqueuer,
@@ -1303,7 +1307,7 @@
Enqueuer world,
Registry registry) {
assert(!registry.isForResolution);
- type = type.unalias(compiler);
+ type = type.unalias(resolution);
enqueueClass(world, compiler.boolClass, registry);
bool inCheckedMode = compiler.enableTypeAssertions;
// [registerIsCheck] is also called for checked mode checks, so we
@@ -1349,6 +1353,40 @@
noSuchMethodRegistry.registerNoSuchMethod(noSuchMethod);
}
+ /// Called when resolving a call to a foreign function.
+ void registerForeignCall(Send node,
+ Element element,
+ CallStructure callStructure,
+ ForeignResolver resolver) {
+ native.NativeResolutionEnqueuer nativeEnqueuer =
+ compiler.enqueuer.resolution.nativeEnqueuer;
+ if (element.name == 'JS') {
+ nativeEnqueuer.registerJsCall(node, resolver);
+ } else if (element.name == 'JS_EMBEDDED_GLOBAL') {
+ nativeEnqueuer.registerJsEmbeddedGlobalCall(node, resolver);
+ } else if (element.name == 'JS_BUILTIN') {
+ nativeEnqueuer.registerJsBuiltinCall(node, resolver);
+ } else if (element.name == 'JS_INTERCEPTOR_CONSTANT') {
+ // The type constant that is an argument to JS_INTERCEPTOR_CONSTANT names
+ // a class that will be instantiated outside the program by attaching a
+ // native class dispatch record referencing the interceptor.
+ if (!node.argumentsNode.isEmpty) {
+ Node argument = node.argumentsNode.nodes.head;
+ ConstantExpression constant = resolver.getConstant(argument);
+ if (constant != null && constant.kind == ConstantExpressionKind.TYPE) {
+ TypeConstantExpression typeConstant = constant;
+ if (typeConstant.type is InterfaceType) {
+ resolver.registerInstantiatedType(typeConstant.type);
+ return;
+ }
+ }
+ }
+ reporter.reportErrorMessage(
+ node,
+ MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
+ }
+ }
+
void enableNoSuchMethod(Enqueuer world) {
enqueue(world, getCreateInvocationMirror(), compiler.globalDependencies);
world.registerInvocation(
@@ -1382,7 +1420,7 @@
}
}
- void registerRequiredType(DartType type, Element enclosingElement) {
+ void registerRequiredType(DartType type) {
// If [argument] has type variables or is a type variable, this method
// registers a RTI dependency between the class where the type variable is
// defined (that is the enclosing class of the current element being
@@ -1390,7 +1428,6 @@
// then the class of the type variable does too.
ClassElement contextClass = Types.getClassContext(type);
if (contextClass != null) {
- assert(contextClass == enclosingElement.enclosingClass.declaration);
rti.registerRtiDependency(type.element, contextClass);
}
}
@@ -1462,7 +1499,7 @@
if (cls.declaration != cls.implementation) {
helpersUsed.add(cls.implementation);
}
- cls.ensureResolved(compiler);
+ cls.ensureResolved(resolution);
registerInstantiatedType(cls.rawType, enqueuer, registry);
}
@@ -1535,7 +1572,7 @@
if (totalMethodCount != preMirrorsMethodCount) {
int mirrorCount = totalMethodCount - preMirrorsMethodCount;
double percentage = (mirrorCount / totalMethodCount) * 100;
- DiagnosticMessage hint = compiler.createMessage(
+ DiagnosticMessage hint = reporter.createMessage(
compiler.mainApp, MessageKind.MIRROR_BLOAT,
{'count': mirrorCount,
'total': totalMethodCount,
@@ -1551,12 +1588,12 @@
compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(library)
? MessageKind.MIRROR_IMPORT
: MessageKind.MIRROR_IMPORT_NO_USAGE;
- compiler.withCurrentElement(library, () {
- infos.add(compiler.createMessage(import, kind));
+ reporter.withCurrentElement(library, () {
+ infos.add(reporter.createMessage(import, kind));
});
}
}
- compiler.reportHint(hint, infos);
+ reporter.reportHint(hint, infos);
}
return programSize;
}
@@ -1902,19 +1939,19 @@
Element getYieldStar() {
ClassElement classElement = findAsyncHelper("_IterationMarker");
- classElement.ensureResolved(compiler);
+ classElement.ensureResolved(resolution);
return classElement.lookupLocalMember("yieldStar");
}
Element getYieldSingle() {
ClassElement classElement = findAsyncHelper("_IterationMarker");
- classElement.ensureResolved(compiler);
+ classElement.ensureResolved(resolution);
return classElement.lookupLocalMember("yieldSingle");
}
Element getSyncStarUncaughtError() {
ClassElement classElement = findAsyncHelper("_IterationMarker");
- classElement.ensureResolved(compiler);
+ classElement.ensureResolved(resolution);
return classElement.lookupLocalMember("uncaughtError");
}
@@ -1928,32 +1965,32 @@
Element getEndOfIteration() {
ClassElement classElement = findAsyncHelper("_IterationMarker");
- classElement.ensureResolved(compiler);
+ classElement.ensureResolved(resolution);
return classElement.lookupLocalMember("endOfIteration");
}
Element getSyncStarIterable() {
ClassElement classElement = findAsyncHelper("_SyncStarIterable");
- classElement.ensureResolved(compiler);
+ classElement.ensureResolved(resolution);
return classElement;
}
Element getSyncStarIterableConstructor() {
ClassElement classElement = getSyncStarIterable();
- classElement.ensureResolved(compiler);
+ classElement.ensureResolved(resolution);
return classElement.lookupConstructor("");
}
Element getSyncCompleterConstructor() {
ClassElement classElement = find(compiler.asyncLibrary, "Completer");
- classElement.ensureResolved(compiler);
+ classElement.ensureResolved(resolution);
return classElement.lookupConstructor("sync");
}
Element getASyncStarController() {
ClassElement classElement =
findAsyncHelper("_AsyncStarStreamController");
- classElement.ensureResolved(compiler);
+ classElement.ensureResolved(resolution);
return classElement;
}
@@ -1964,7 +2001,7 @@
Element getStreamIteratorConstructor() {
ClassElement classElement = find(compiler.asyncLibrary, "StreamIterator");
- classElement.ensureResolved(compiler);
+ classElement.ensureResolved(resolution);
return classElement.lookupConstructor("");
}
@@ -2052,7 +2089,7 @@
if (mustRetainMetadata) hasRetainedMetadata = true;
if (mustRetainMetadata && referencedFromMirrorSystem(element)) {
for (MetadataAnnotation metadata in element.metadata) {
- metadata.ensureResolved(compiler);
+ metadata.ensureResolved(resolution);
ConstantValue constant =
constants.getConstantValueForMetadata(metadata);
constants.addCompileTimeConstantForEmission(constant);
@@ -2092,7 +2129,7 @@
boundClosureClass = lookupHelperClass('BoundClosure');
closureClass = lookupHelperClass('Closure');
if (!missingHelperClasses.isEmpty) {
- compiler.internalError(jsHelperLibrary,
+ reporter.internalError(jsHelperLibrary,
'dart:_js_helper library does not contain required classes: '
'$missingHelperClasses');
}
@@ -2199,7 +2236,7 @@
assert(loadedLibraries.containsLibrary(DART_JS_HELPER));
if (jsInvocationMirrorClass != null) {
- jsInvocationMirrorClass.ensureResolved(compiler);
+ jsInvocationMirrorClass.ensureResolved(resolution);
invokeOnMethod = jsInvocationMirrorClass.lookupLocalMember(INVOKE_ON);
}
@@ -2225,16 +2262,16 @@
// subclasses, so we check to see if they are defined before
// trying to resolve them.
if (jsFixedArrayClass != null) {
- jsFixedArrayClass.ensureResolved(compiler);
+ jsFixedArrayClass.ensureResolved(resolution);
}
if (jsExtendableArrayClass != null) {
- jsExtendableArrayClass.ensureResolved(compiler);
+ jsExtendableArrayClass.ensureResolved(resolution);
}
if (jsUnmodifiableArrayClass != null) {
- jsUnmodifiableArrayClass.ensureResolved(compiler);
+ jsUnmodifiableArrayClass.ensureResolved(resolution);
}
- jsIndexableClass.ensureResolved(compiler);
+ jsIndexableClass.ensureResolved(resolution);
jsIndexableLength = compiler.lookupElementIn(
jsIndexableClass, 'length');
if (jsIndexableLength != null && jsIndexableLength.isAbstractField) {
@@ -2242,12 +2279,12 @@
jsIndexableLength = element.getter;
}
- jsArrayClass.ensureResolved(compiler);
+ jsArrayClass.ensureResolved(resolution);
jsArrayTypedConstructor = compiler.lookupElementIn(jsArrayClass, 'typed');
jsArrayRemoveLast = compiler.lookupElementIn(jsArrayClass, 'removeLast');
jsArrayAdd = compiler.lookupElementIn(jsArrayClass, 'add');
- jsStringClass.ensureResolved(compiler);
+ jsStringClass.ensureResolved(resolution);
jsStringSplit = compiler.lookupElementIn(jsStringClass, 'split');
jsStringOperatorAdd = compiler.lookupElementIn(jsStringClass, '+');
jsStringToString = compiler.lookupElementIn(jsStringClass, 'toString');
@@ -2341,7 +2378,7 @@
// TODO(kasperl): It would be nice if we didn't have to resolve
// all metadata but only stuff that potentially would match one
// of the used meta targets.
- metadata.ensureResolved(compiler);
+ metadata.ensureResolved(resolution);
ConstantValue value =
compiler.constants.getConstantValue(metadata.constant);
if (value == null) continue;
@@ -2389,13 +2426,13 @@
reflectableMembers.add(cls);
// 2) its constructors (if resolved)
cls.constructors.forEach((Element constructor) {
- if (resolution.hasBeenResolved(constructor)) {
+ if (resolution.hasBeenProcessed(constructor)) {
reflectableMembers.add(constructor);
}
});
// 3) all members, including fields via getter/setters (if resolved)
cls.forEachClassMember((Member member) {
- if (resolution.hasBeenResolved(member.element)) {
+ if (resolution.hasBeenProcessed(member.element)) {
memberNames.add(member.name);
reflectableMembers.add(member.element);
}
@@ -2407,8 +2444,8 @@
if (memberNames.contains(member.name)) {
// TODO(20993): find out why this assertion fails.
// assert(invariant(member.element,
- // resolution.hasBeenResolved(member.element)));
- if (resolution.hasBeenResolved(member.element)) {
+ // resolution.hasBeenProcessed(member.element)));
+ if (resolution.hasBeenProcessed(member.element)) {
reflectableMembers.add(member.element);
}
}
@@ -2424,13 +2461,13 @@
} else {
// check members themselves
cls.constructors.forEach((ConstructorElement element) {
- if (!resolution.hasBeenResolved(element)) return;
+ if (!resolution.hasBeenProcessed(element)) return;
if (referencedFromMirrorSystem(element, false)) {
reflectableMembers.add(element);
}
});
cls.forEachClassMember((Member member) {
- if (!resolution.hasBeenResolved(member.element)) return;
+ if (!resolution.hasBeenProcessed(member.element)) return;
if (referencedFromMirrorSystem(member.element, false)) {
reflectableMembers.add(member.element);
}
@@ -2455,7 +2492,7 @@
if (lib.isInternalLibrary) continue;
lib.forEachLocalMember((Element member) {
if (!member.isClass &&
- resolution.hasBeenResolved(member) &&
+ resolution.hasBeenProcessed(member) &&
referencedFromMirrorSystem(member)) {
reflectableMembers.add(member);
}
@@ -2608,13 +2645,21 @@
enqueuer.enqueueReflectiveStaticFields(_findStaticFieldTargets());
}
- if (mustPreserveNames) compiler.log('Preserving names.');
+ if (mustPreserveNames) reporter.log('Preserving names.');
if (mustRetainMetadata) {
- compiler.log('Retaining metadata.');
+ reporter.log('Retaining metadata.');
compiler.libraryLoader.libraries.forEach(retainMetadataOf);
- if (!enqueuer.isResolutionQueue) {
+ if (enqueuer.isResolutionQueue) {
+ for (Dependency dependency in metadataConstants) {
+ registerCompileTimeConstant(
+ dependency.constant,
+ new EagerRegistry(compiler,
+ dependency.annotatedElement.analyzableElement.treeElements),
+ addForEmission: false);
+ }
+ } else {
for (Dependency dependency in metadataConstants) {
registerCompileTimeConstant(
dependency.constant,
@@ -2649,7 +2694,7 @@
bool hasNoThrows = false;
bool hasNoSideEffects = false;
for (MetadataAnnotation metadata in element.implementation.metadata) {
- metadata.ensureResolved(compiler);
+ metadata.ensureResolved(resolution);
ConstantValue constantValue =
compiler.constants.getConstantValue(metadata.constant);
if (!constantValue.isConstructedObject) continue;
@@ -2658,7 +2703,7 @@
if (cls == forceInlineClass) {
hasForceInline = true;
if (VERBOSE_OPTIMIZER_HINTS) {
- compiler.reportHintMessage(
+ reporter.reportHintMessage(
element,
MessageKind.GENERIC,
{'text': "Must inline"});
@@ -2667,7 +2712,7 @@
} else if (cls == noInlineClass) {
hasNoInline = true;
if (VERBOSE_OPTIMIZER_HINTS) {
- compiler.reportHintMessage(
+ reporter.reportHintMessage(
element,
MessageKind.GENERIC,
{'text': "Cannot inline"});
@@ -2676,12 +2721,12 @@
} else if (cls == noThrowsClass) {
hasNoThrows = true;
if (!Elements.isStaticOrTopLevelFunction(element)) {
- compiler.internalError(element,
+ reporter.internalError(element,
"@NoThrows() is currently limited to top-level"
" or static functions");
}
if (VERBOSE_OPTIMIZER_HINTS) {
- compiler.reportHintMessage(
+ reporter.reportHintMessage(
element,
MessageKind.GENERIC,
{'text': "Cannot throw"});
@@ -2690,7 +2735,7 @@
} else if (cls == noSideEffectsClass) {
hasNoSideEffects = true;
if (VERBOSE_OPTIMIZER_HINTS) {
- compiler.reportHintMessage(
+ reporter.reportHintMessage(
element,
MessageKind.GENERIC,
{'text': "Has no side effects"});
@@ -2699,15 +2744,15 @@
}
}
if (hasForceInline && hasNoInline) {
- compiler.internalError(element,
+ reporter.internalError(element,
"@ForceInline() must not be used with @NoInline.");
}
if (hasNoThrows && !hasNoInline) {
- compiler.internalError(element,
+ reporter.internalError(element,
"@NoThrows() should always be combined with @NoInline.");
}
if (hasNoSideEffects && !hasNoInline) {
- compiler.internalError(element,
+ reporter.internalError(element,
"@NoSideEffects() should always be combined with @NoInline.");
}
if (element == invokeOnMethod) {
@@ -2761,33 +2806,48 @@
Enqueuer enqueuer,
Registry registry) {
if (element.asyncMarker == AsyncMarker.ASYNC) {
- enqueue(enqueuer, getAsyncHelper(), registry);
- enqueue(enqueuer, getSyncCompleterConstructor(), registry);
- enqueue(enqueuer, getStreamIteratorConstructor(), registry);
- enqueue(enqueuer, getWrapBody(), registry);
+ _registerAsync(enqueuer, registry);
} else if (element.asyncMarker == AsyncMarker.SYNC_STAR) {
- ClassElement clsSyncStarIterable = getSyncStarIterable();
- clsSyncStarIterable.ensureResolved(compiler);
- registerInstantiatedType(clsSyncStarIterable.rawType, enqueuer, registry);
- enqueue(enqueuer, getSyncStarIterableConstructor(), registry);
- enqueue(enqueuer, getEndOfIteration(), registry);
- enqueue(enqueuer, getYieldStar(), registry);
- enqueue(enqueuer, getSyncStarUncaughtError(), registry);
+ _registerSyncStar(enqueuer, registry);
} else if (element.asyncMarker == AsyncMarker.ASYNC_STAR) {
- ClassElement clsASyncStarController = getASyncStarController();
- clsASyncStarController.ensureResolved(compiler);
- registerInstantiatedType(
- clsASyncStarController.rawType, enqueuer, registry);
- enqueue(enqueuer, getAsyncStarHelper(), registry);
- enqueue(enqueuer, getStreamOfController(), registry);
- enqueue(enqueuer, getYieldSingle(), registry);
- enqueue(enqueuer, getYieldStar(), registry);
- enqueue(enqueuer, getASyncStarControllerConstructor(), registry);
- enqueue(enqueuer, getStreamIteratorConstructor(), registry);
- enqueue(enqueuer, getWrapBody(), registry);
+ _registerAsyncStar(enqueuer, registry);
}
}
+ void _registerAsync(Enqueuer enqueuer,
+ Registry registry) {
+ enqueue(enqueuer, getAsyncHelper(), registry);
+ enqueue(enqueuer, getSyncCompleterConstructor(), registry);
+ enqueue(enqueuer, getStreamIteratorConstructor(), registry);
+ enqueue(enqueuer, getWrapBody(), registry);
+ }
+
+ void _registerSyncStar(Enqueuer enqueuer,
+ Registry registry) {
+ ClassElement clsSyncStarIterable = getSyncStarIterable();
+ clsSyncStarIterable.ensureResolved(compiler.resolution);
+ registerInstantiatedType(clsSyncStarIterable.rawType, enqueuer, registry);
+ enqueue(enqueuer, getSyncStarIterableConstructor(), registry);
+ enqueue(enqueuer, getEndOfIteration(), registry);
+ enqueue(enqueuer, getYieldStar(), registry);
+ enqueue(enqueuer, getSyncStarUncaughtError(), registry);
+ }
+
+ void _registerAsyncStar(Enqueuer enqueuer,
+ Registry registry) {
+ ClassElement clsASyncStarController = getASyncStarController();
+ clsASyncStarController.ensureResolved(compiler.resolution);
+ registerInstantiatedType(
+ clsASyncStarController.rawType, enqueuer, registry);
+ enqueue(enqueuer, getAsyncStarHelper(), registry);
+ enqueue(enqueuer, getStreamOfController(), registry);
+ enqueue(enqueuer, getYieldSingle(), registry);
+ enqueue(enqueuer, getYieldStar(), registry);
+ enqueue(enqueuer, getASyncStarControllerConstructor(), registry);
+ enqueue(enqueuer, getStreamIteratorConstructor(), registry);
+ enqueue(enqueuer, getWrapBody(), registry);
+ }
+
@override
bool enableDeferredLoadingIfSupported(Spannable node, Registry registry) {
registerCheckDeferredIsLoaded(registry);
@@ -2797,7 +2857,7 @@
@override
bool enableCodegenWithErrorsIfSupported(Spannable node) {
if (compiler.useCpsIr) {
- compiler.reportHintMessage(
+ reporter.reportHintMessage(
node,
MessageKind.GENERIC,
{'text': "Generation of code with compile time errors is currently "
@@ -2814,8 +2874,8 @@
switch (element.asyncMarker) {
case AsyncMarker.ASYNC:
rewriter = new AsyncRewriter(
- compiler,
- compiler.currentElement,
+ reporter,
+ element,
asyncHelper:
emitter.staticFunctionAccess(getAsyncHelper()),
wrapBody:
@@ -2827,8 +2887,8 @@
break;
case AsyncMarker.SYNC_STAR:
rewriter = new SyncStarRewriter(
- compiler,
- compiler.currentElement,
+ reporter,
+ element,
endOfIteration: emitter.staticFunctionAccess(
getEndOfIteration()),
newIterable: emitter.staticFunctionAccess(
@@ -2842,8 +2902,8 @@
break;
case AsyncMarker.ASYNC_STAR:
rewriter = new AsyncStarRewriter(
- compiler,
- compiler.currentElement,
+ reporter,
+ element,
asyncStarHelper: emitter.staticFunctionAccess(
getAsyncStarHelper()),
streamOfController: emitter.staticFunctionAccess(
@@ -2880,6 +2940,8 @@
JavaScriptBackend get backend => compiler.backend;
+ DiagnosticReporter get reporter => compiler.reporter;
+
Annotations(this.compiler);
void onLibraryScanned(LibraryElement library) {
@@ -2921,7 +2983,7 @@
/// Returns `true` if [element] is annotated with [annotationClass].
bool _hasAnnotation(Element element, ClassElement annotationClass) {
if (annotationClass == null) return false;
- return compiler.withCurrentElement(element, () {
+ return reporter.withCurrentElement(element, () {
for (MetadataAnnotation metadata in element.metadata) {
assert(invariant(metadata, metadata.constant != null,
message: "Unevaluated metadata constant."));
@@ -2944,13 +3006,142 @@
JavaScriptResolutionCallbacks(this.backend);
+ WorldImpact transformImpact(ResolutionWorldImpact worldImpact) {
+ TransformedWorldImpact transformed =
+ new TransformedWorldImpact(worldImpact);
+ for (Feature feature in worldImpact.features) {
+ switch (feature) {
+ case Feature.ABSTRACT_CLASS_INSTANTIATION:
+ onAbstractClassInstantiation(transformed);
+ break;
+ case Feature.ASSERT:
+ onAssert(false, transformed);
+ break;
+ case Feature.ASSERT_WITH_MESSAGE:
+ onAssert(true, transformed);
+ break;
+ case Feature.ASYNC:
+ backend._registerAsync(
+ backend.compiler.enqueuer.resolution, transformed);
+ break;
+ case Feature.ASYNC_FOR_IN:
+ onAsyncForIn(null, transformed);
+ break;
+ case Feature.ASYNC_STAR:
+ backend._registerAsyncStar(
+ backend.compiler.enqueuer.resolution, transformed);
+ break;
+ case Feature.CATCH_STATEMENT:
+ onCatchStatement(transformed);
+ break;
+ case Feature.COMPILE_TIME_ERROR:
+ onCompileTimeError(transformed, null);
+ break;
+ case Feature.FALL_THROUGH_ERROR:
+ onFallThroughError(transformed);
+ break;
+ case Feature.INC_DEC_OPERATION:
+ onIncDecOperation(transformed);
+ break;
+ case Feature.LAZY_FIELD:
+ onLazyField(transformed);
+ break;
+ case Feature.NEW_SYMBOL:
+ backend.registerNewSymbol(transformed);
+ break;
+ case Feature.STACK_TRACE_IN_CATCH:
+ onStackTraceInCatch(transformed);
+ break;
+ case Feature.STRING_INTERPOLATION:
+ onStringInterpolation(transformed);
+ break;
+ case Feature.SUPER_NO_SUCH_METHOD:
+ onSuperNoSuchMethod(transformed);
+ break;
+ case Feature.SYMBOL_CONSTRUCTOR:
+ onSymbolConstructor(transformed);
+ break;
+ case Feature.SYNC_FOR_IN:
+ onSyncForIn(transformed);
+ break;
+ case Feature.SYNC_STAR:
+ backend._registerSyncStar(
+ backend.compiler.enqueuer.resolution, transformed);
+ break;
+ case Feature.THROW_EXPRESSION:
+ onThrowExpression(transformed);
+ break;
+ case Feature.THROW_NO_SUCH_METHOD:
+ onThrowNoSuchMethod(transformed);
+ break;
+ case Feature.THROW_RUNTIME_ERROR:
+ onThrowRuntimeError(transformed);
+ break;
+ case Feature.TYPE_VARIABLE_BOUNDS_CHECK:
+ onTypeVariableBoundCheck(transformed);
+ break;
+ }
+ }
+ for (DartType type in worldImpact.isChecks) {
+ onIsCheck(type, transformed);
+ }
+ for (DartType type in worldImpact.asCasts) {
+ onIsCheck(type, transformed);
+ onAsCheck(type, transformed);
+ }
+ if (backend.compiler.enableTypeAssertions) {
+ for (DartType type in worldImpact.checkedModeChecks) {
+ onIsCheck(type, transformed);
+ }
+ }
+ for (DartType requiredType in worldImpact.requiredTypes) {
+ backend.registerRequiredType(requiredType);
+ }
+ for (MapLiteralUse mapLiteralUse in worldImpact.mapLiterals) {
+ // TODO(johnniwinther): Use the [isEmpty] property when factory
+ // constructors are registered directly.
+ onMapLiteral(transformed, mapLiteralUse.type, mapLiteralUse.isConstant);
+ }
+ for (ListLiteralUse listLiteralUse in worldImpact.listLiterals) {
+ // TODO(johnniwinther): Use the [isConstant] and [isEmpty] property when
+ // factory constructors are registered directly.
+ transformed.registerInstantiation(listLiteralUse.type);
+ }
+ for (DartType typeLiteral in worldImpact.typeLiterals) {
+ onTypeLiteral(typeLiteral, transformed);
+ transformed.registerInstantiation(backend.compiler.coreTypes.typeType);
+ if (typeLiteral.isTypeVariable) {
+ onTypeVariableExpression(transformed, typeLiteral.element);
+ }
+ }
+ for (String constSymbolName in worldImpact.constSymbolNames) {
+ backend.registerConstSymbol(constSymbolName, transformed);
+ }
+ for (LocalFunctionElement closure in worldImpact.closures) {
+ if (closure.computeType(backend.resolution).containsTypeVariables) {
+ backend.registerClosureWithFreeTypeVariables(
+ closure, backend.compiler.enqueuer.resolution, transformed);
+ }
+ }
+ // TODO(johnniwinther): Remove this when dependency tracking is done on
+ // the world impact itself.
+ for (InterfaceType instantiatedType in worldImpact.instantiatedTypes) {
+ transformed.registerInstantiation(instantiatedType);
+ }
+ for (Element element in worldImpact.staticUses) {
+ transformed.registerStaticInvocation(element);
+ }
+
+ return transformed;
+ }
+
void registerBackendStaticInvocation(Element element, Registry registry) {
registry.registerStaticInvocation(backend.registerBackendUse(element));
}
void registerBackendInstantiation(ClassElement element, Registry registry) {
backend.registerBackendUse(element);
- element.ensureResolved(backend.compiler);
+ element.ensureResolved(backend.resolution);
registry.registerInstantiation(element.rawType);
}
@@ -3041,7 +3232,7 @@
// TODO(johnniwinther): Maybe split this into [onAssertType] and [onTestType].
void onIsCheck(DartType type, Registry registry) {
assert(registry.isForResolution);
- type = type.unalias(backend.compiler);
+ type = type.unalias(backend.resolution);
registerBackendInstantiation(backend.compiler.boolClass, registry);
bool inCheckedMode = backend.compiler.enableTypeAssertions;
if (inCheckedMode) {
@@ -3149,7 +3340,7 @@
'Needed to encode the name of super.noSuchMethod.');
}
- void onMapLiteral(ResolutionRegistry registry,
+ void onMapLiteral(Registry registry,
DartType type,
bool isConstant) {
assert(registry.isForResolution);
@@ -3164,7 +3355,7 @@
enqueue(JavaScriptMapConstant.DART_STRING_CLASS);
enqueue(JavaScriptMapConstant.DART_GENERAL_CLASS);
} else {
- registry.registerInstantiatedType(type);
+ registry.registerInstantiation(type);
}
}
diff --git a/pkg/compiler/lib/src/js_backend/codegen/glue.dart b/pkg/compiler/lib/src/js_backend/codegen/glue.dart
index 37dd0ae..3a229e3 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/glue.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/glue.dart
@@ -14,6 +14,10 @@
DartType,
TypeVariableType,
InterfaceType;
+import '../../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
+import '../../diagnostics/spannable.dart' show
+ CURRENT_ELEMENT_SPANNABLE;
import '../../enqueue.dart' show
CodegenEnqueuer;
import '../../elements/elements.dart';
@@ -46,12 +50,14 @@
ClassWorld get classWorld => _compiler.world;
+ DiagnosticReporter get reporter => _compiler.reporter;
+
js.Expression constantReference(ConstantValue value) {
return _emitter.constantReference(value);
}
reportInternalError(String message) {
- _compiler.internalError(_compiler.currentElement, message);
+ reporter.internalError(CURRENT_ELEMENT_SPANNABLE, message);
}
bool isUsedAsMixin(ClassElement classElement) {
diff --git a/pkg/compiler/lib/src/js_backend/codegen/task.dart b/pkg/compiler/lib/src/js_backend/codegen/task.dart
index 92cd2c0..0e12e63 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/task.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/task.dart
@@ -20,6 +20,8 @@
import '../../cps_ir/cps_ir_nodes.dart' as cps;
import '../../cps_ir/cps_ir_integrity.dart';
import '../../cps_ir/cps_ir_builder_task.dart';
+import '../../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import '../../diagnostics/invariant.dart' show
DEBUG_MODE;
import '../../tree_ir/tree_ir_nodes.dart' as tree_ir;
@@ -76,16 +78,18 @@
JavaScriptBackend get backend => compiler.backend;
+ DiagnosticReporter get reporter => compiler.reporter;
+
/// Generates JavaScript code for `work.element`.
js.Fun compile(CodegenWorkItem work) {
AstElement element = work.element;
- return compiler.withCurrentElement(element, () {
+ return reporter.withCurrentElement(element, () {
typeSystem = new TypeMaskSystem(compiler);
try {
// TODO(karlklose): remove this fallback when we do not need it for
// testing anymore.
if (false) {
- compiler.log('Using SSA compiler for platform element $element');
+ reporter.log('Using SSA compiler for platform element $element');
return fallbackCompiler.compile(work);
}
@@ -100,7 +104,7 @@
} on CodegenBailout catch (e) {
String message = "Unable to compile $element with the new compiler.\n"
" Reason: ${e.message}";
- compiler.internalError(element, message);
+ reporter.internalError(element, message);
}
});
}
@@ -203,7 +207,7 @@
tree_ir.FunctionDefinition compileToTreeIr(cps.FunctionDefinition cpsNode) {
tree_builder.Builder builder = new tree_builder.Builder(
- compiler.internalError);
+ reporter.internalError);
tree_ir.FunctionDefinition treeNode =
treeBuilderTask.measure(() => builder.buildFunction(cpsNode));
assert(treeNode != null);
diff --git a/pkg/compiler/lib/src/js_backend/constant_emitter.dart b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
index 3f38a28..f1d7f74 100644
--- a/pkg/compiler/lib/src/js_backend/constant_emitter.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
@@ -39,6 +39,8 @@
jsAst.Expression this.constantReferenceGenerator(ConstantValue constant),
this.makeConstantList);
+ DiagnosticReporter get reporter => compiler.reporter;
+
/**
* Constructs a literal expression that evaluates to the constant. Uses a
* canonical name unless the constant can be emitted multiple times (as for
@@ -54,7 +56,7 @@
@override
jsAst.Expression visitFunction(FunctionConstantValue constant, [_]) {
- compiler.internalError(NO_LOCATION_SPANNABLE,
+ reporter.internalError(NO_LOCATION_SPANNABLE,
"The function constant does not need specific JS code.");
return null;
}
@@ -220,7 +222,7 @@
} else if (field.name == JavaScriptMapConstant.JS_DATA_NAME) {
arguments.add(jsGeneralMap());
} else {
- compiler.internalError(field,
+ reporter.internalError(field,
"Compiler has unexpected field ${field.name} for "
"${className}.");
}
@@ -233,7 +235,7 @@
emittedArgumentCount != 4) ||
(className == JavaScriptMapConstant.DART_GENERAL_CLASS &&
emittedArgumentCount != 1)) {
- compiler.internalError(classElement,
+ reporter.internalError(classElement,
"Compiler and ${className} disagree on number of fields.");
}
@@ -273,7 +275,7 @@
case SyntheticConstantKind.NAME:
return constant.payload;
default:
- compiler.internalError(NO_LOCATION_SPANNABLE,
+ reporter.internalError(NO_LOCATION_SPANNABLE,
"Unexpected DummyConstantKind ${constant.kind}");
return null;
}
diff --git a/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart b/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart
index 5d0183a..dcb5661 100644
--- a/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart
@@ -196,7 +196,7 @@
ConstantExpression initialValue =
initialVariableValues[element.declaration];
if (initialValue == null) {
- compiler.internalError(element, "No initial value for given element.");
+ reporter.internalError(element, "No initial value for given element.");
}
return getConstantValue(initialValue);
}
diff --git a/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart b/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
index 3ebe90f6..3dca32b 100644
--- a/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
@@ -263,7 +263,8 @@
@override
ConstantValue createType(Compiler compiler, DartType type) {
return new TypeConstantValue(
- type, compiler.backend.typeImplementation.computeType(compiler));
+ type,
+ compiler.backend.typeImplementation.computeType(compiler.resolution));
}
// Integer checks don't verify that the number is not -0.0.
@@ -321,7 +322,7 @@
: JavaScriptMapConstant.DART_STRING_CLASS)
: JavaScriptMapConstant.DART_GENERAL_CLASS;
ClassElement classElement = backend.jsHelperLibrary.find(className);
- classElement.ensureResolved(compiler);
+ classElement.ensureResolved(compiler.resolution);
List<DartType> typeArgument = sourceType.typeArguments;
InterfaceType type;
if (sourceType.treatAsRaw) {
diff --git a/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart b/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
index 1cd0c43..00394a5 100644
--- a/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
@@ -67,7 +67,7 @@
enqueuer.isResolutionQueue ? resolutionJoin : codegenJoin;
void registerInstantiatedClass(ClassElement classElement, Enqueuer enqueuer) {
- classElement.ensureResolved(compiler);
+ classElement.ensureResolved(compiler.resolution);
if (!Elements.isNativeOrExtendsNative(classElement)) return;
if (classElement.isMixinApplication) return;
if (classElement.isAbstract) return;
@@ -191,7 +191,7 @@
if (member.isGenerativeConstructor) {
// Ignore constructors that cannot be called with zero arguments.
FunctionElement constructor = member;
- constructor.computeType(compiler);
+ constructor.computeType(compiler.resolution);
FunctionSignature parameters = constructor.functionSignature;
if (parameters.requiredParameterCount == 0) {
result.add(member);
diff --git a/pkg/compiler/lib/src/js_backend/js_backend.dart b/pkg/compiler/lib/src/js_backend/js_backend.dart
index 5cf86f4..f195be4 100644
--- a/pkg/compiler/lib/src/js_backend/js_backend.dart
+++ b/pkg/compiler/lib/src/js_backend/js_backend.dart
@@ -12,7 +12,8 @@
import '../closure.dart';
import '../common/backend_api.dart' show
- Backend;
+ Backend,
+ ForeignResolver;
import '../common/codegen.dart' show
CodegenRegistry,
CodegenWorkItem;
@@ -25,7 +26,13 @@
import '../common/tasks.dart' show
CompilerTask;
import '../common/resolution.dart' show
- ResolutionCallbacks;
+ Feature,
+ ListLiteralUse,
+ MapLiteralUse,
+ Resolution,
+ ResolutionCallbacks,
+ ResolutionWorldImpact,
+ TransformedWorldImpact;
import '../common/work.dart' show
ItemCompilationContext;
import '../compiler.dart' show
@@ -36,11 +43,13 @@
import '../constants/values.dart';
import '../dart_types.dart';
import '../diagnostics/diagnostic_listener.dart' show
- DiagnosticMessage;
+ DiagnosticMessage,
+ DiagnosticReporter;
import '../diagnostics/invariant.dart' show
invariant;
import '../diagnostics/messages.dart' show MessageKind;
import '../diagnostics/spannable.dart' show
+ CURRENT_ELEMENT_SPANNABLE,
NO_LOCATION_SPANNABLE,
Spannable,
SpannableAssertionFailure;
@@ -73,7 +82,7 @@
import '../library_loader.dart' show LibraryLoader, LoadedLibraries;
import '../native/native.dart' as native;
import '../resolution/registry.dart' show
- ResolutionRegistry;
+ EagerRegistry;
import '../resolution/tree_elements.dart' show
TreeElements;
import '../ssa/ssa.dart';
diff --git a/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart b/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
index fa70021..21a643a 100644
--- a/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
@@ -7,14 +7,17 @@
import '../common/registry.dart' show Registry;
import '../compiler.dart' show Compiler;
-import '../diagnostics/messages.dart' show MessageKind;
+import '../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
+import '../diagnostics/messages.dart' show
+ MessageKind;
import '../constants/values.dart' show
- ConstantValue,
- ConstructedConstantValue,
- ListConstantValue,
- NullConstantValue,
- StringConstantValue,
- TypeConstantValue;
+ ConstantValue,
+ ConstructedConstantValue,
+ ListConstantValue,
+ NullConstantValue,
+ StringConstantValue,
+ TypeConstantValue;
import '../dart_types.dart' show DartType;
import '../elements/elements.dart' show
ClassElement,
@@ -72,6 +75,10 @@
/// discover that a key in a map is potentially used.
final JavaScriptBackend backend;
+ /// Reference the diagnostic reporting system for logging and reporting issues
+ /// to the end-user.
+ final DiagnosticReporter reporter;
+
/// The resolved [VariableElement] associated with the top-level `_version`.
VariableElement lookupMapVersionVariable;
@@ -119,7 +126,7 @@
/// Whether the backend is currently processing the codegen queue.
bool _inCodegen = false;
- LookupMapAnalysis(this.backend);
+ LookupMapAnalysis(this.backend, this.reporter);
/// Whether this analysis and optimization is enabled.
bool get _isEnabled {
@@ -136,7 +143,7 @@
// the lookup_map package. We otherwise produce a warning.
lookupMapVersionVariable = library.implementation.findLocal('_version');
if (lookupMapVersionVariable == null) {
- backend.compiler.reportInfo(library,
+ reporter.reportInfo(library,
MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP);
} else {
backend.compiler.enqueuer.resolution.addToWorkList(
@@ -155,7 +162,7 @@
StringConstantValue value =
backend.constants.getConstantValueForVariable(lookupMapVersionVariable);
if (value == null) {
- backend.compiler.reportInfo(lookupMapVersionVariable,
+ reporter.reportInfo(lookupMapVersionVariable,
MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP);
return;
}
@@ -168,13 +175,13 @@
} catch (e) {}
if (version == null || !_validLookupMapVersionConstraint.allows(version)) {
- backend.compiler.reportInfo(lookupMapVersionVariable,
+ reporter.reportInfo(lookupMapVersionVariable,
MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP);
return;
}
ClassElement cls = lookupMapLibrary.findLocal('LookupMap');
- cls.computeType(backend.compiler);
+ cls.computeType(backend.resolution);
entriesField = cls.lookupMember('_entries');
keyField = cls.lookupMember('_key');
valueField = cls.lookupMember('_value');
@@ -311,7 +318,7 @@
count++;
}
}
- compiler.log(count == 0
+ reporter.log(count == 0
? 'lookup-map: nothing was tree-shaken'
: 'lookup-map: found $count unused keys ($sb)');
}
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 14a399c..de1279f 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -457,6 +457,8 @@
JavaScriptBackend get backend => compiler.backend;
+ DiagnosticReporter get reporter => compiler.reporter;
+
String get deferredTypesName => 'deferredTypes';
String get isolateName => 'Isolate';
String get isolatePropertiesName => r'$isolateProperties';
@@ -513,7 +515,7 @@
case JsGetName.FUNCTION_CLASS_TYPE_NAME:
return runtimeTypeName(compiler.functionClass);
default:
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node,
MessageKind.GENERIC,
{'text': 'Error: Namer has no name for "$name".'});
@@ -705,7 +707,8 @@
return disambiguatedName; // Methods other than call are not annotated.
default:
- compiler.internalError(compiler.currentElement,
+ reporter.internalError(
+ CURRENT_ELEMENT_SPANNABLE,
'Unexpected selector kind: ${selector.kind}');
return null;
}
@@ -1391,7 +1394,7 @@
String get functionTypeTag => r'func';
- String get functionTypeVoidReturnTag => r'void';
+ String get functionTypeVoidReturnTag => r'v';
String get functionTypeReturnTypeTag => r'ret';
@@ -1581,6 +1584,8 @@
ConstantNamingVisitor(this.compiler, this.hasher);
+ DiagnosticReporter get reporter => compiler.reporter;
+
String getName(ConstantValue constant) {
_visit(constant);
if (root == null) return 'CONSTANT';
@@ -1743,7 +1748,7 @@
add('name');
break;
default:
- compiler.internalError(compiler.currentElement,
+ reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
"Unexpected SyntheticConstantValue");
}
}
@@ -1773,6 +1778,8 @@
ConstantCanonicalHasher(this.compiler);
+ DiagnosticReporter get reporter => compiler.reporter;
+
int getHash(ConstantValue constant) => _visit(constant);
int _visit(ConstantValue constant) {
@@ -1856,9 +1863,10 @@
// resolve to integer indexes, they're always part of a larger constant.
return 0;
default:
- compiler.internalError(NO_LOCATION_SPANNABLE,
- 'SyntheticConstantValue should never be named and '
- 'never be subconstant');
+ reporter.internalError(
+ NO_LOCATION_SPANNABLE,
+ 'SyntheticConstantValue should never be named and '
+ 'never be subconstant');
return 0;
}
}
diff --git a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
index 0a322bd..3bb7e45 100644
--- a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
+++ b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
@@ -59,6 +59,8 @@
: this._backend = backend,
this._compiler = backend.compiler;
+ DiagnosticReporter get reporter => _compiler.reporter;
+
bool get hasThrowingNoSuchMethod => throwingImpls.isNotEmpty;
bool get hasComplexNoSuchMethod => otherImpls.isNotEmpty;
@@ -82,19 +84,19 @@
void emitDiagnostic() {
throwingImpls.forEach((e) {
if (!_hasForwardingSyntax(e)) {
- _compiler.reportHintMessage(
+ reporter.reportHintMessage(
e, MessageKind.DIRECTLY_THROWING_NSM);
}
});
complexNoReturnImpls.forEach((e) {
if (!_hasForwardingSyntax(e)) {
- _compiler.reportHintMessage(
+ reporter.reportHintMessage(
e, MessageKind.COMPLEX_THROWING_NSM);
}
});
complexReturningImpls.forEach((e) {
if (!_hasForwardingSyntax(e)) {
- _compiler.reportHintMessage(
+ reporter.reportHintMessage(
e, MessageKind.COMPLEX_RETURNING_NSM);
}
});
diff --git a/pkg/compiler/lib/src/js_backend/patch_resolver.dart b/pkg/compiler/lib/src/js_backend/patch_resolver.dart
index 36dfd07..d827a3e 100644
--- a/pkg/compiler/lib/src/js_backend/patch_resolver.dart
+++ b/pkg/compiler/lib/src/js_backend/patch_resolver.dart
@@ -4,6 +4,8 @@
library dart2js.js_backend.patch_resolver;
+import '../common/resolution.dart' show
+ Resolution;
import '../common/tasks.dart' show
CompilerTask;
import '../compiler.dart' show
@@ -22,19 +24,20 @@
class PatchResolverTask extends CompilerTask {
PatchResolverTask(Compiler compiler) : super(compiler);
+ Resolution get resolution => compiler.resolution;
+
String get name => 'JavaScript patch resolver';
FunctionElement resolveExternalFunction(FunctionElementX element) {
if (element.isPatched) {
FunctionElementX patch = element.patch;
- compiler.withCurrentElement(patch, () {
- patch.parseNode(compiler);
- patch.computeType(compiler);
+ reporter.withCurrentElement(patch, () {
+ patch.computeType(resolution);
});
checkMatchingPatchSignatures(element, patch);
element = patch;
} else {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
element, MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION);
}
return element;
@@ -56,19 +59,19 @@
assert(invariant(origin, originParameter.patch == patchParameter,
message: "Inconsistent repatch of $originParameter."));
}
- DartType originParameterType = originParameter.computeType(compiler);
- DartType patchParameterType = patchParameter.computeType(compiler);
+ DartType originParameterType = originParameter.computeType(resolution);
+ DartType patchParameterType = patchParameter.computeType(resolution);
if (originParameterType != patchParameterType) {
- compiler.reportError(
- compiler.createMessage(
- originParameter.parseNode(compiler),
+ reporter.reportError(
+ reporter.createMessage(
+ originParameter,
MessageKind.PATCH_PARAMETER_TYPE_MISMATCH,
{'methodName': origin.name,
'parameterName': originParameter.name,
'originParameterType': originParameterType,
'patchParameterType': patchParameterType}),
<DiagnosticMessage>[
- compiler.createMessage(
+ reporter.createMessage(
patchParameter,
MessageKind.PATCH_POINT_TO_PARAMETER,
{'parameterName': patchParameter.name}),
@@ -80,23 +83,21 @@
// The node contains the type, so there is a potential overlap.
// Therefore we only check the text if the types are identical.
- String originParameterText =
- originParameter.parseNode(compiler).toString();
- String patchParameterText =
- patchParameter.parseNode(compiler).toString();
+ String originParameterText = originParameter.node.toString();
+ String patchParameterText = patchParameter.node.toString();
if (originParameterText != patchParameterText
// We special case the list constructor because of the
// optional parameter.
&& origin != compiler.unnamedListConstructor) {
- compiler.reportError(
- compiler.createMessage(
- originParameter.parseNode(compiler),
+ reporter.reportError(
+ reporter.createMessage(
+ originParameter,
MessageKind.PATCH_PARAMETER_MISMATCH,
{'methodName': origin.name,
'originParameter': originParameterText,
'patchParameter': patchParameterText}),
<DiagnosticMessage>[
- compiler.createMessage(
+ reporter.createMessage(
patchParameter,
MessageKind.PATCH_POINT_TO_PARAMETER,
{'parameterName': patchParameter.name}),
@@ -115,10 +116,10 @@
FunctionSignature patchSignature = patch.functionSignature;
if (originSignature.type.returnType != patchSignature.type.returnType) {
- compiler.withCurrentElement(patch, () {
+ reporter.withCurrentElement(patch, () {
Node errorNode =
patchTree.returnType != null ? patchTree.returnType : patchTree;
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
errorNode, MessageKind.PATCH_RETURN_TYPE_MISMATCH,
{'methodName': origin.name,
'originReturnType': originSignature.type.returnType,
@@ -127,8 +128,8 @@
}
if (originSignature.requiredParameterCount !=
patchSignature.requiredParameterCount) {
- compiler.withCurrentElement(patch, () {
- compiler.reportErrorMessage(
+ reporter.withCurrentElement(patch, () {
+ reporter.reportErrorMessage(
patchTree,
MessageKind.PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH,
{'methodName': origin.name,
@@ -144,8 +145,8 @@
patchSignature.optionalParameterCount != 0) {
if (originSignature.optionalParametersAreNamed !=
patchSignature.optionalParametersAreNamed) {
- compiler.withCurrentElement(patch, () {
- compiler.reportErrorMessage(
+ reporter.withCurrentElement(patch, () {
+ reporter.reportErrorMessage(
patchTree,
MessageKind.PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH,
{'methodName': origin.name});
@@ -154,8 +155,8 @@
}
if (originSignature.optionalParameterCount !=
patchSignature.optionalParameterCount) {
- compiler.withCurrentElement(patch, () {
- compiler.reportErrorMessage(
+ reporter.withCurrentElement(patch, () {
+ reporter.reportErrorMessage(
patchTree,
MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH,
{'methodName': origin.name,
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index d6f02eb..81b4dd5 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -623,6 +623,7 @@
JavaScriptBackend get backend => compiler.backend;
Namer get namer => backend.namer;
+ DiagnosticReporter get reporter => compiler.reporter;
TypeRepresentationGenerator(Compiler this.compiler);
@@ -744,7 +745,7 @@
visitTypedefType(TypedefType type, _) {
bool shouldEncode = shouldEncodeTypedef(type);
- DartType unaliasedType = type.unalias(compiler);
+ DartType unaliasedType = type.unalias(compiler.resolution);
if (shouldEncode) {
jsAst.ObjectInitializer initializer = unaliasedType.accept(this, null);
// We have to encode the aliased type.
@@ -762,7 +763,7 @@
}
visitStatementType(StatementType type, _) {
- compiler.internalError(NO_LOCATION_SPANNABLE,
+ reporter.internalError(NO_LOCATION_SPANNABLE,
'Unexpected type: $type (${type.kind}).');
}
}
@@ -814,7 +815,7 @@
}
visitTypedefType(TypedefType type, bool isTypeArgument) {
- type.unalias(backend.compiler).accept(this, isTypeArgument);
+ type.unalias(backend.resolution).accept(this, isTypeArgument);
}
visitInterfaceType(InterfaceType type, bool isTypeArgument) {
@@ -846,7 +847,7 @@
}
visitTypedefType(TypedefType type, bool inFunctionType) {
- type.unalias(backend.compiler).accept(this, inFunctionType);
+ type.unalias(backend.resolution).accept(this, inFunctionType);
}
visitInterfaceType(InterfaceType type, bool inFunctionType) {
diff --git a/pkg/compiler/lib/src/js_backend/type_variable_handler.dart b/pkg/compiler/lib/src/js_backend/type_variable_handler.dart
index 6832d33..ec6eecf 100644
--- a/pkg/compiler/lib/src/js_backend/type_variable_handler.dart
+++ b/pkg/compiler/lib/src/js_backend/type_variable_handler.dart
@@ -36,6 +36,7 @@
CodeEmitterTask get _task => _backend.emitter;
MetadataCollector get _metadataCollector => _task.metadataCollector;
JavaScriptBackend get _backend => _compiler.backend;
+ DiagnosticReporter get reporter => _compiler.reporter;
void registerClassWithTypeVariables(ClassElement cls, Enqueuer enqueuer,
Registry registry) {
@@ -44,10 +45,10 @@
// resolved.
if (!_seenClassesWithTypeVariables) {
_backend.enqueueClass(enqueuer, _typeVariableClass, registry);
- _typeVariableClass.ensureResolved(_compiler);
+ _typeVariableClass.ensureResolved(_compiler.resolution);
Link constructors = _typeVariableClass.constructors;
if (constructors.isEmpty && constructors.tail.isEmpty) {
- _compiler.internalError(_typeVariableClass,
+ reporter.internalError(_typeVariableClass,
"Class '$_typeVariableClass' should only have one constructor");
}
_typeVariableConstructor = _typeVariableClass.constructors.head;
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart
index c5723ae..5a84ef2 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart
@@ -156,7 +156,7 @@
int code = field.getterFlags + (field.setterFlags << 2);
if (code == 0) {
- compiler.internalError(fieldElement,
+ reporter.internalError(fieldElement,
'Field code is 0 ($fieldElement).');
}
fieldNameParts.add(
@@ -212,7 +212,7 @@
for (Field field in cls.fields) {
Element member = field.element;
- compiler.withCurrentElement(member, () {
+ reporter.withCurrentElement(member, () {
if (field.needsGetter) {
emitGetterForCSP(member, field.name, field.accessorName, builder);
}
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/code_emitter_helper.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/code_emitter_helper.dart
index f777014..78c963d 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/code_emitter_helper.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/code_emitter_helper.dart
@@ -15,6 +15,8 @@
Compiler get compiler => emitter.compiler;
+ DiagnosticReporter get reporter => compiler.reporter;
+
String get n => emitter.n;
String get _ => emitter._;
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
index c71eaa2..62f5e81 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
@@ -26,7 +26,11 @@
import '../../deferred_load.dart' show OutputUnit;
-import '../../diagnostics/messages.dart' show MessageKind;
+import '../../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
+
+import '../../diagnostics/messages.dart' show
+ MessageKind;
import '../../diagnostics/spannable.dart' show
NO_LOCATION_SPANNABLE;
@@ -192,6 +196,8 @@
interceptorEmitter.emitter = this;
}
+ DiagnosticReporter get reporter => compiler.reporter;
+
List<jsAst.Node> cspPrecompiledFunctionFor(OutputUnit outputUnit) {
return _cspPrecompiledFunctions.putIfAbsent(
outputUnit,
@@ -415,7 +421,7 @@
return jsAst.js.expressionTemplateFor("$functionGettersMap[#]()");
default:
- compiler.internalError(NO_LOCATION_SPANNABLE,
+ reporter.internalError(NO_LOCATION_SPANNABLE,
"Unhandled Builtin: $builtin");
return null;
}
@@ -554,7 +560,7 @@
} else if (element.isTypedef) {
return element.name;
}
- throw compiler.internalError(element,
+ throw reporter.internalError(element,
'Do not know how to reflect on this $element.');
}
@@ -592,7 +598,7 @@
void assembleClass(Class cls, ClassBuilder enclosingBuilder,
Fragment fragment) {
ClassElement classElement = cls.element;
- compiler.withCurrentElement(classElement, () {
+ reporter.withCurrentElement(classElement, () {
if (compiler.hasIncrementalSupport) {
ClassBuilder cachedBuilder =
cachedClassBuilders.putIfAbsent(classElement, () {
@@ -645,7 +651,7 @@
// [fields] is `null`.
if (fields != null) {
for (Element element in fields) {
- compiler.withCurrentElement(element, () {
+ reporter.withCurrentElement(element, () {
ConstantValue constant = handler.getInitialValueFor(element);
parts.add(buildInitialization(element, constantReference(constant)));
});
@@ -659,7 +665,7 @@
(OutputUnit fieldsOutputUnit, Iterable<VariableElement> fields) {
if (fieldsOutputUnit == outputUnit) return; // Skip the main unit.
for (Element element in fields) {
- compiler.withCurrentElement(element, () {
+ reporter.withCurrentElement(element, () {
parts.add(buildInitialization(element, jsAst.number(0)));
});
}
@@ -900,8 +906,8 @@
#finishedClasses = map();
if (#needsLazyInitializer) {
- // [staticName] is only provided in non-minified mode. If missing, we
- // fall back to [fieldName]. Likewise, [prototype] is optional and
+ // [staticName] is only provided in non-minified mode. If missing, we
+ // fall back to [fieldName]. Likewise, [prototype] is optional and
// defaults to the isolateProperties object.
$lazyInitializerName = function (fieldName, getterName, lazyValue,
staticName, prototype) {
@@ -1332,12 +1338,12 @@
Elements.sortedByPosition(elements.where((e) => !e.isLibrary));
pendingStatics.forEach((element) =>
- compiler.reportInfo(
+ reporter.reportInfo(
element, MessageKind.GENERIC, {'text': 'Pending statics.'}));
}
if (pendingStatics != null && !pendingStatics.isEmpty) {
- compiler.internalError(pendingStatics.first,
+ reporter.internalError(pendingStatics.first,
'Pending statics (see above).');
}
}
@@ -1812,7 +1818,7 @@
if (backend.requiresPreamble &&
!backend.htmlLibraryIsLoaded) {
- compiler.reportHintMessage(
+ reporter.reportHintMessage(
NO_LOCATION_SPANNABLE, MessageKind.PREAMBLE);
}
// Return the total program size.
@@ -1846,7 +1852,7 @@
}
}
if (owner == null) {
- compiler.internalError(element, 'Owner is null.');
+ reporter.internalError(element, 'Owner is null.');
}
return elementDescriptors
.putIfAbsent(fragment, () => new Map<Element, ClassBuilder>())
diff --git a/pkg/compiler/lib/src/js_emitter/js_emitter.dart b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
index 1472e53..4289e7c 100644
--- a/pkg/compiler/lib/src/js_emitter/js_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
@@ -20,6 +20,9 @@
import '../dart_types.dart' show
TypedefType;
+import '../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
+
import '../diagnostics/spannable.dart' show
NO_LOCATION_SPANNABLE;
diff --git a/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart
index d68c38b..2c2f303 100644
--- a/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart
@@ -26,6 +26,9 @@
import '../js_emitter.dart' as emitterTask show
Emitter;
+import '../../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
+
import '../../diagnostics/spannable.dart' show
NO_LOCATION_SPANNABLE;
@@ -41,6 +44,8 @@
this.namer = namer,
_emitter = new ModelEmitter(compiler, namer, nativeEmitter);
+ DiagnosticReporter get reporter => _compiler.reporter;
+
@override
String get patchVersion => "lazy";
@@ -181,7 +186,7 @@
throw new UnsupportedError('createDartClosureFromNameOfStaticFunction');
default:
- _compiler.internalError(NO_LOCATION_SPANNABLE,
+ reporter.internalError(NO_LOCATION_SPANNABLE,
"Unhandled Builtin: $builtin");
return null;
}
diff --git a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
index af55455..e0a9b03 100644
--- a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
+++ b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
@@ -145,6 +145,7 @@
JavaScriptBackend get _backend => _compiler.backend;
TypeVariableHandler get _typeVariableHandler => _backend.typeVariableHandler;
+ DiagnosticReporter get reporter => _compiler.reporter;
bool _mustEmitMetadataFor(Element element) {
return _backend.mustRetainMetadata &&
@@ -159,13 +160,13 @@
/// mirrors_patch to implement DeclarationMirror.metadata.
jsAst.Fun buildMetadataFunction(Element element) {
if (!_mustEmitMetadataFor(element)) return null;
- return _compiler.withCurrentElement(element, () {
+ return reporter.withCurrentElement(element, () {
List<jsAst.Expression> metadata = <jsAst.Expression>[];
for (MetadataAnnotation annotation in element.metadata) {
ConstantValue constant =
_backend.constants.getConstantValueForMetadata(annotation);
if (constant == null) {
- _compiler.internalError(annotation, 'Annotation value is null.');
+ reporter.internalError(annotation, 'Annotation value is null.');
} else {
metadata.add(_emitter.constantReference(constant));
}
@@ -195,7 +196,7 @@
ConstantValue constant =
_backend.constants.getConstantValueForMetadata(annotation);
if (constant == null) {
- _compiler.internalError(annotation, 'Annotation value is null.');
+ reporter.internalError(annotation, 'Annotation value is null.');
return null;
}
return _addGlobalMetadata(_emitter.constantReference(constant));
@@ -255,7 +256,7 @@
if (representation is jsAst.LiteralString) {
// We don't want the representation to be a string, since we use
// strings as indicator for non-initialized types in the lazy emitter.
- _compiler.internalError(
+ reporter.internalError(
NO_LOCATION_SPANNABLE, 'reified types should not be strings.');
}
@@ -281,7 +282,7 @@
}
List<jsAst.DeferredNumber> computeMetadata(FunctionElement element) {
- return _compiler.withCurrentElement(element, () {
+ return reporter.withCurrentElement(element, () {
if (!_mustEmitMetadataFor(element)) return const <jsAst.DeferredNumber>[];
List<jsAst.DeferredNumber> metadata = <jsAst.DeferredNumber>[];
for (MetadataAnnotation annotation in element.metadata) {
diff --git a/pkg/compiler/lib/src/js_emitter/native_emitter.dart b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
index 0d90d2f..df8778df 100644
--- a/pkg/compiler/lib/src/js_emitter/native_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
@@ -268,7 +268,7 @@
// parameter that was not provided for this stub.
for (jsAst.Parameter stubParameter in stubParameters) {
if (stubParameter.name == name) {
- DartType type = parameter.type.unalias(compiler);
+ DartType type = parameter.type.unalias(compiler.resolution);
if (type is FunctionType) {
// The parameter type is a function type either directly or through
// typedef(s).
diff --git a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
index f632f90..0d95278 100644
--- a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
@@ -15,6 +15,7 @@
Emitter get emitter => backend.emitter.emitter;
CodeEmitterTask get emitterTask => backend.emitter;
+ DiagnosticReporter get reporter => compiler.reporter;
bool needsSuperGetter(FunctionElement element) =>
compiler.codegenWorld.methodsNeedingSuperGetter.contains(element);
@@ -190,10 +191,10 @@
if (member.enclosingElement.isClosure) {
ClosureClassElement cls = member.enclosingElement;
if (cls.supertype.element == backend.boundClosureClass) {
- compiler.internalError(cls.methodElement, 'Bound closure1.');
+ reporter.internalError(cls.methodElement, 'Bound closure1.');
}
if (cls.methodElement.isInstanceMember) {
- compiler.internalError(cls.methodElement, 'Bound closure2.');
+ reporter.internalError(cls.methodElement, 'Bound closure2.');
}
}
diff --git a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
index 80ad3f1..233835b 100644
--- a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
@@ -228,7 +228,7 @@
generateSubstitution,
generated);
}
- FunctionType callType = callFunction.computeType(compiler);
+ FunctionType callType = callFunction.computeType(compiler.resolution);
generateFunctionTypeSignature(callFunction, callType);
}
}
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
index 45ccabe..ea0537a 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
@@ -27,6 +27,9 @@
import '../js_emitter.dart' as emitterTask show
Emitter;
+import '../../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
+
import '../../diagnostics/spannable.dart' show
NO_LOCATION_SPANNABLE;
@@ -44,6 +47,8 @@
_emitter = new ModelEmitter(
compiler, namer, nativeEmitter, shouldGenerateSourceMap);
+ DiagnosticReporter get reporter => _compiler.reporter;
+
@override
String get patchVersion => "startup";
@@ -184,7 +189,7 @@
return js.js.expressionTemplateFor("$functionAccess(#)");
default:
- _compiler.internalError(NO_LOCATION_SPANNABLE,
+ reporter.internalError(NO_LOCATION_SPANNABLE,
"Unhandled Builtin: $builtin");
return null;
}
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
index 8c9f247..ec8ac00 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
@@ -31,6 +31,9 @@
Namer,
ConstantEmitter;
+import '../../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
+
import '../../diagnostics/spannable.dart' show
NO_LOCATION_SPANNABLE;
@@ -100,6 +103,8 @@
constantListGenerator);
}
+ DiagnosticReporter get reporter => compiler.reporter;
+
js.Expression constantListGenerator(js.Expression array) {
// TODO(floitsch): remove hard-coded name.
return js.js('makeConstList(#)', [array]);
@@ -211,7 +216,7 @@
if (backend.requiresPreamble &&
!backend.htmlLibraryIsLoaded) {
- compiler.reportHintMessage(
+ reporter.reportHintMessage(
NO_LOCATION_SPANNABLE, MessageKind.PREAMBLE);
}
diff --git a/pkg/compiler/lib/src/js_emitter/type_test_registry.dart b/pkg/compiler/lib/src/js_emitter/type_test_registry.dart
index ac333cc..f329cbf 100644
--- a/pkg/compiler/lib/src/js_emitter/type_test_registry.dart
+++ b/pkg/compiler/lib/src/js_emitter/type_test_registry.dart
@@ -129,7 +129,7 @@
backend.generatedCode.keys.where((element) {
return canBeReflectedAsFunction(element) && canBeReified(element);
}).forEach((FunctionElement function) {
- DartType type = function.computeType(compiler);
+ DartType type = function.type;
for (ClassElement cls in backend.rti.getReferencedClasses(type)) {
while (cls != null) {
rtiNeededClasses.add(cls);
diff --git a/pkg/compiler/lib/src/library_loader.dart b/pkg/compiler/lib/src/library_loader.dart
index 08aaf90..241516b 100644
--- a/pkg/compiler/lib/src/library_loader.dart
+++ b/pkg/compiler/lib/src/library_loader.dart
@@ -358,7 +358,7 @@
currentHandler = new LibraryDependencyHandler(this);
return createLibrary(currentHandler, null, resolvedUri)
.then((LibraryElement library) {
- return compiler.withCurrentElement(library, () {
+ return reporter.withCurrentElement(library, () {
return measure(() {
currentHandler.computeExports();
LoadedLibraries loadedLibraries =
@@ -388,14 +388,14 @@
Uri base = library.entryCompilationUnit.script.readableUri;
return Future.forEach(library.tags, (LibraryTag tag) {
- return compiler.withCurrentElement(library, () {
+ return reporter.withCurrentElement(library, () {
Uri computeUri(LibraryDependency node) {
String tagUriString = node.uri.dartString.slowToString();
try {
return Uri.parse(tagUriString);
} on FormatException {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node.uri,
MessageKind.INVALID_URI, {'uri': tagUriString});
return null;
@@ -411,7 +411,7 @@
// TODO(johnniwinther): Create imports during parsing.
ImportElementX import =
new ImportElementX(library.entryCompilationUnit, tag, uri);
- tagState.checkTag(TagState.IMPORT_OR_EXPORT, import.node, compiler);
+ tagState.checkTag(TagState.IMPORT_OR_EXPORT, import.node, reporter);
if (import.uri == Uris.dart_core) {
importsDartCore = true;
}
@@ -426,11 +426,11 @@
// TODO(johnniwinther): Create exports during parsing.
ExportElementX export =
new ExportElementX(library.entryCompilationUnit, tag, uri);
- tagState.checkTag(TagState.IMPORT_OR_EXPORT, export.node, compiler);
+ tagState.checkTag(TagState.IMPORT_OR_EXPORT, export.node, reporter);
library.addExportDeclaration(export);
libraryDependencies.addLast(export);
} else if (tag.isLibraryName) {
- tagState.checkTag(TagState.LIBRARY, tag, compiler);
+ tagState.checkTag(TagState.LIBRARY, tag, reporter);
if (library.libraryTag == null) {
// Use the first if there are multiple (which is reported as an
// error in [TagState.checkTag]).
@@ -440,16 +440,16 @@
Part part = tag;
StringNode uri = part.uri;
Uri resolvedUri = base.resolve(uri.dartString.slowToString());
- tagState.checkTag(TagState.PART, part, compiler);
+ tagState.checkTag(TagState.PART, part, reporter);
return scanPart(part, resolvedUri, library);
} else {
- compiler.internalError(tag, "Unhandled library tag.");
+ reporter.internalError(tag, "Unhandled library tag.");
}
});
}).then((_) {
return compiler.onLibraryScanned(library, handler);
}).then((_) {
- return compiler.withCurrentElement(library, () {
+ return reporter.withCurrentElement(library, () {
checkDuplicatedLibraryName(library);
// Import dart:core if not already imported.
@@ -466,7 +466,7 @@
}).then((_) {
return Future.forEach(libraryDependencies.toList(),
(LibraryDependencyElementX libraryDependency) {
- return compiler.withCurrentElement(library, () {
+ return reporter.withCurrentElement(library, () {
return registerLibraryFromImportExport(
handler, library, libraryDependency);
});
@@ -481,8 +481,8 @@
libraryResourceUriMap.putIfAbsent(resourceUri, () => library);
if (!identical(existing, library)) {
if (library.hasLibraryName) {
- compiler.withCurrentElement(library, () {
- compiler.reportWarningMessage(
+ reporter.withCurrentElement(library, () {
+ reporter.reportWarningMessage(
library,
MessageKind.DUPLICATED_LIBRARY_RESOURCE,
{'libraryName': library.libraryName,
@@ -491,7 +491,7 @@
'canonicalUri2': existing.canonicalUri});
});
} else {
- compiler.reportHintMessage(
+ reporter.reportHintMessage(
library,
MessageKind.DUPLICATED_RESOURCE,
{'resourceUri': resourceUri,
@@ -502,14 +502,14 @@
String name = library.libraryOrScriptName;
existing = libraryNames.putIfAbsent(name, () => library);
if (!identical(existing, library)) {
- compiler.withCurrentElement(library, () {
- compiler.reportWarningMessage(
+ reporter.withCurrentElement(library, () {
+ reporter.reportWarningMessage(
library,
MessageKind.DUPLICATED_LIBRARY_NAME,
{'libraryName': name});
});
- compiler.withCurrentElement(existing, () {
- compiler.reportWarningMessage(
+ reporter.withCurrentElement(existing, () {
+ reporter.reportWarningMessage(
existing,
MessageKind.DUPLICATED_LIBRARY_NAME,
{'libraryName': name});
@@ -526,17 +526,17 @@
if (!resolvedUri.isAbsolute) throw new ArgumentError(resolvedUri);
Uri readableUri = compiler.translateResolvedUri(library, resolvedUri, part);
if (readableUri == null) return new Future.value();
- return compiler.withCurrentElement(library, () {
+ return reporter.withCurrentElement(library, () {
return compiler.readScript(part, readableUri).
then((Script sourceScript) {
if (sourceScript == null) return;
CompilationUnitElementX unit =
new CompilationUnitElementX(sourceScript, library);
- compiler.withCurrentElement(unit, () {
+ reporter.withCurrentElement(unit, () {
compiler.scanner.scan(unit);
if (unit.partTag == null && !sourceScript.isSynthesized) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
unit, MessageKind.MISSING_PART_OF_TAG);
}
});
@@ -559,7 +559,7 @@
return createLibrary(handler, library, resolvedUri, libraryDependency)
.then((LibraryElement loadedLibrary) {
if (loadedLibrary == null) return;
- compiler.withCurrentElement(library, () {
+ reporter.withCurrentElement(library, () {
libraryDependency.libraryDependency = loadedLibrary;
handler.registerDependency(
library, libraryDependency, loadedLibrary);
@@ -612,13 +612,13 @@
readableUri = resolvedUri;
readScript = compiler.synthesizeScript;
}
- return compiler.withCurrentElement(importingLibrary, () {
+ return reporter.withCurrentElement(importingLibrary, () {
return readScript(node, readableUri).then((Script script) {
if (script == null) return null;
LibraryElement element =
createLibrarySync(handler, script, resolvedUri);
return processLibraryTags(handler, element).then((_) {
- compiler.withCurrentElement(element, () {
+ reporter.withCurrentElement(element, () {
handler.registerLibraryExports(element);
});
return element;
@@ -632,7 +632,7 @@
Script script,
Uri resolvedUri) {
LibraryElement element = new LibraryElementX(script, resolvedUri);
- return compiler.withCurrentElement(element, () {
+ return reporter.withCurrentElement(element, () {
if (handler != null) {
handler.registerNewLibrary(element);
libraryCanonicalUriMap[resolvedUri] = element;
@@ -679,7 +679,7 @@
/// If [value] is less than [tagState] complain. Regardless, update
/// [tagState] using transition function for state machine.
- void checkTag(int value, LibraryTag tag, DiagnosticListener listener) {
+ void checkTag(int value, LibraryTag tag, DiagnosticReporter reporter) {
if (tagState > value) {
MessageKind kind;
switch (value) {
@@ -697,14 +697,14 @@
} else if (tag.isExport) {
kind = MessageKind.EXPORT_BEFORE_PARTS;
} else {
- listener.internalError(tag, "Expected import or export.");
+ reporter.internalError(tag, "Expected import or export.");
}
break;
default:
- listener.internalError(tag, "Unexpected order of library tags.");
+ reporter.internalError(tag, "Unexpected order of library tags.");
}
- listener.reportErrorMessage(tag, kind);
+ reporter.reportErrorMessage(tag, kind);
}
tagState = NEXT[value];
if (value == LIBRARY) {
@@ -725,7 +725,8 @@
/**
* Imports the library into the [importingLibrary].
*/
- void importLibrary(Compiler compiler, LibraryElementX importingLibrary) {
+ void importLibrary(DiagnosticReporter reporter,
+ LibraryElementX importingLibrary) {
assert(invariant(importingLibrary,
importedLibrary.exportsHandled,
message: 'Exports not handled on $importedLibrary'));
@@ -745,22 +746,22 @@
} else {
prefixElement = existingElement;
}
- importingLibrary.addToScope(prefixElement, compiler);
+ importingLibrary.addToScope(prefixElement, reporter);
importedLibrary.forEachExport((Element element) {
if (combinatorFilter.exclude(element)) return;
- prefixElement.addImport(element, import, compiler);
+ prefixElement.addImport(element, import, reporter);
});
import.prefix = prefixElement;
if (prefixElement.isDeferred) {
prefixElement.addImport(
new DeferredLoaderGetterElementX(prefixElement),
- import, compiler);
+ import, reporter);
}
} else {
importedLibrary.forEachExport((Element element) {
- compiler.withCurrentElement(importingLibrary, () {
+ reporter.withCurrentElement(importingLibrary, () {
if (combinatorFilter.exclude(element)) return;
- importingLibrary.addImport(element, import, compiler);
+ importingLibrary.addImport(element, import, reporter);
});
});
}
@@ -885,7 +886,7 @@
///
/// Additionally, check that all names in the show/hide combinators are in the
/// export scope of [exportedLibraryElement].
- void registerHandledExports(DiagnosticListener listener,
+ void registerHandledExports(DiagnosticReporter reporter,
LibraryElement exportedLibraryElement,
ExportElementX export,
CombinatorFilter filter) {
@@ -898,9 +899,11 @@
pendingExportMap[exportedElement] = exports.prepend(export);
}
});
- listener.withCurrentElement(library, () {
- checkLibraryDependency(listener, export.node, exportedLibraryElement);
- });
+ if (!reporter.options.suppressHints) {
+ reporter.withCurrentElement(library, () {
+ checkLibraryDependency(reporter, export.node, exportedLibraryElement);
+ });
+ }
}
/**
@@ -913,9 +916,9 @@
/**
* Registers the imports of the node library.
*/
- void registerImports(Compiler compiler) {
+ void registerImports(DiagnosticReporter reporter) {
for (ImportLink link in imports) {
- link.importLibrary(compiler, library);
+ link.importLibrary(reporter, library);
}
}
@@ -933,8 +936,10 @@
* Adds [element] to the export scope for this node. If the [element] name
* is a duplicate, an error element is inserted into the export scope.
*/
- Element addElementToExportScope(Compiler compiler, Element element,
- Link<ExportElement> exports) {
+ Element addElementToExportScope(
+ DiagnosticReporter reporter,
+ Element element,
+ Link<ExportElement> exports) {
String name = element.name;
DiagnosticMessage error;
List<DiagnosticMessage> infos = <DiagnosticMessage>[];
@@ -945,15 +950,15 @@
assert(invariant(library, !duplicateExports.isEmpty,
message: "No export for $duplicate from ${duplicate.library} "
"in $library."));
- compiler.withCurrentElement(library, () {
+ reporter.withCurrentElement(library, () {
for (ExportElement export in duplicateExports) {
if (error == null) {
- error = compiler.createMessage(
+ error = reporter.createMessage(
export,
MessageKind.DUPLICATE_EXPORT,
{'name': name});
} else {
- infos.add(compiler.createMessage(
+ infos.add(reporter.createMessage(
export,
MessageKind.DUPLICATE_EXPORT_CONT,
{'name': name}));
@@ -968,7 +973,7 @@
assert(invariant(library, !duplicateExports.isEmpty,
message: "No export for $duplicate from ${duplicate.library} "
"in $library."));
- infos.add(compiler.createMessage(
+ infos.add(reporter.createMessage(
duplicate,
MessageKind.DUPLICATE_EXPORT_DECL,
{'name': name, 'uriString': duplicateExports.head.uri}));
@@ -1001,7 +1006,7 @@
exporters[element] = exports;
}
if (error != null) {
- compiler.reportError(error, infos);
+ reporter.reportError(error, infos);
}
return element;
}
@@ -1040,37 +1045,52 @@
/// Check that all names in the show/hide combinators of imports and exports
/// are in the export scope of the imported/exported libraries.
- void checkCombinators(DiagnosticListener listener) {
- listener.withCurrentElement(library, () {
+ void checkCombinators(DiagnosticReporter reporter) {
+ reporter.withCurrentElement(library, () {
for (ImportLink importLink in imports) {
checkLibraryDependency(
- listener, importLink.import.node, importLink.importedLibrary);
+ reporter, importLink.import.node, importLink.importedLibrary);
}
});
for (ExportLink exportLink in dependencies) {
- listener.withCurrentElement(exportLink.exportNode.library, () {
- checkLibraryDependency(listener, exportLink.export.node, library);
+ reporter.withCurrentElement(exportLink.exportNode.library, () {
+ checkLibraryDependency(reporter, exportLink.export.node, library);
});
}
}
/// Check that all names in the show/hide combinators of [tag] are in the
/// export scope of [library].
- void checkLibraryDependency(DiagnosticListener listener,
- LibraryDependency tag,
- LibraryElement library) {
+ void checkLibraryDependency(
+ DiagnosticReporter reporter,
+ LibraryDependency tag,
+ LibraryElement library) {
if (tag == null || tag.combinators == null) return;
for (Combinator combinator in tag.combinators) {
for (Identifier identifier in combinator.identifiers) {
String name = identifier.source;
Element element = library.findExported(name);
if (element == null) {
- listener.reportHintMessage(
- identifier,
- combinator.isHide
- ? MessageKind.EMPTY_HIDE : MessageKind.EMPTY_SHOW,
- {'uri': library.canonicalUri,
- 'name': name});
+ if (combinator.isHide) {
+ if (library.isPackageLibrary &&
+ !reporter.options.showPackageWarnings) {
+ // Only report hide hint on packages if we show warnings on these:
+ // The hide may be non-empty in some versions of the package, in
+ // which case you shouldn't remove the combinator.
+ continue;
+ }
+ reporter.reportHintMessage(
+ identifier,
+ MessageKind.EMPTY_HIDE,
+ {'uri': library.canonicalUri,
+ 'name': name});
+ } else {
+ reporter.reportHintMessage(
+ identifier,
+ MessageKind.EMPTY_SHOW,
+ {'uri': library.canonicalUri,
+ 'name': name});
+ }
}
}
}
@@ -1102,6 +1122,8 @@
Compiler get compiler => task.compiler;
+ DiagnosticReporter get reporter => task.reporter;
+
/// The libraries loaded with this handler.
Iterable<LibraryElement> get loadedLibraries => nodeMap.keys;
@@ -1130,7 +1152,7 @@
tasks.forEach((LibraryDependencyNode node,
Map<Element, Link<ExportElement>> pendingExports) {
pendingExports.forEach((Element element, Link<ExportElement> exports) {
- element = node.addElementToExportScope(compiler, element, exports);
+ element = node.addElementToExportScope(reporter, element, exports);
if (node.propagateElement(element)) {
changed = true;
}
@@ -1147,12 +1169,14 @@
// Setup import scopes.
nodeMap.forEach((LibraryElement library, LibraryDependencyNode node) {
- node.registerImports(compiler);
+ node.registerImports(reporter);
});
- nodeMap.forEach((LibraryElement library, LibraryDependencyNode node) {
- node.checkCombinators(compiler);
- });
+ if (!reporter.options.suppressHints) {
+ nodeMap.forEach((LibraryElement library, LibraryDependencyNode node) {
+ node.checkCombinators(reporter);
+ });
+ }
}
/// Registers that [library] depends on [loadedLibrary] through
@@ -1168,7 +1192,7 @@
CombinatorFilter combinatorFilter =
new CombinatorFilter.fromTag(libraryDependency.node);
exportingNode.registerHandledExports(
- compiler, loadedLibrary, libraryDependency, combinatorFilter);
+ reporter, loadedLibrary, libraryDependency, combinatorFilter);
return;
}
LibraryDependencyNode exportedNode = nodeMap[loadedLibrary];
diff --git a/pkg/compiler/lib/src/mirrors/dart2js_instance_mirrors.dart b/pkg/compiler/lib/src/mirrors/dart2js_instance_mirrors.dart
index 9a2cbe2..55d8789 100644
--- a/pkg/compiler/lib/src/mirrors/dart2js_instance_mirrors.dart
+++ b/pkg/compiler/lib/src/mirrors/dart2js_instance_mirrors.dart
@@ -56,7 +56,7 @@
} else if (value.isConstructedObject) {
return new Dart2JsConstructedConstantMirror(mirrorSystem, constant, value);
}
- mirrorSystem.compiler.internalError(NO_LOCATION_SPANNABLE,
+ mirrorSystem.compiler.reporter.internalError(NO_LOCATION_SPANNABLE,
"Unexpected constant value $value");
return null;
}
diff --git a/pkg/compiler/lib/src/mirrors/dart2js_library_mirror.dart b/pkg/compiler/lib/src/mirrors/dart2js_library_mirror.dart
index 2d43e7d..feaf549 100644
--- a/pkg/compiler/lib/src/mirrors/dart2js_library_mirror.dart
+++ b/pkg/compiler/lib/src/mirrors/dart2js_library_mirror.dart
@@ -126,7 +126,7 @@
SourceLocation get location {
return new Dart2JsSourceLocation(
_sourceLibrary._element.entryCompilationUnit.script,
- _sourceLibrary.mirrorSystem.compiler.spanFromNode(_node));
+ _sourceLibrary.mirrorSystem.compiler.reporter.spanFromSpannable(_node));
}
List<CombinatorMirror> get combinators {
diff --git a/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart b/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart
index 3834728..247e3f5 100644
--- a/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart
+++ b/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart
@@ -135,7 +135,7 @@
}
return members;
}
- mirrorSystem.compiler.internalError(element,
+ mirrorSystem.compiler.reporter.internalError(element,
"Unexpected member type $element ${element.kind}.");
return null;
}
@@ -208,8 +208,8 @@
span = new SourceSpan(script.resourceUri, 0, 0);
} else {
Token endToken = getEndToken();
- span = mirrorSystem.compiler.spanFromTokens(
- beginToken, endToken, script.resourceUri);
+ span = new SourceSpan.fromTokens(
+ script.resourceUri, beginToken, endToken);
}
return new Dart2JsSourceLocation(script, span);
}
@@ -230,7 +230,7 @@
for (MetadataAnnotation metadata in _element.metadata) {
_appendCommentTokens(
mirrorSystem.compiler.commentMap[metadata.beginToken]);
- metadata.ensureResolved(mirrorSystem.compiler);
+ metadata.ensureResolved(mirrorSystem.compiler.resolution);
_metadata.add(_convertConstantToInstanceMirror(
mirrorSystem, metadata.constant,
mirrorSystem.compiler.constants.getConstantValue(
@@ -348,7 +348,7 @@
return new Dart2JsTypedefMirror(this, type);
}
}
- compiler.internalError(type.element,
+ compiler.reporter.internalError(type.element,
"Unexpected type $type of kind ${type.kind}.");
return null;
}
@@ -359,7 +359,7 @@
} else if (element.isTypedef) {
return new Dart2JsTypedefDeclarationMirror(this, element.thisType);
}
- compiler.internalError(element, "Unexpected element $element.");
+ compiler.reporter.internalError(element, "Unexpected element $element.");
return null;
}
}
diff --git a/pkg/compiler/lib/src/mirrors_used.dart b/pkg/compiler/lib/src/mirrors_used.dart
index 2110d75..8a72eff 100644
--- a/pkg/compiler/lib/src/mirrors_used.dart
+++ b/pkg/compiler/lib/src/mirrors_used.dart
@@ -21,6 +21,8 @@
DartType,
InterfaceType,
TypeKind;
+import 'diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import 'diagnostics/messages.dart' show
MessageKind;
import 'diagnostics/spannable.dart' show
@@ -174,6 +176,8 @@
cachedStrings = new Map<ConstantValue, List<String>>(),
cachedElements = new Map<ConstantValue, List<Element>>();
+ DiagnosticReporter get reporter => compiler.reporter;
+
/// Collect and merge all @MirrorsUsed annotations. As a side-effect, also
/// compute which libraries have the annotation (which is used by
/// [MirrorUsageAnalyzerTask.hasMirrorUsage]).
@@ -201,7 +205,7 @@
for (LibraryElement library in compiler.libraryLoader.libraries) {
if (library.isInternalLibrary) continue;
for (ImportElement import in library.imports) {
- compiler.withCurrentElement(library, () {
+ reporter.withCurrentElement(library, () {
List<MirrorUsage> usages =
mirrorsUsedOnLibraryTag(library, import);
if (usages != null) {
@@ -261,7 +265,7 @@
}
List<MirrorUsage> result = <MirrorUsage>[];
for (MetadataAnnotation metadata in import.metadata) {
- metadata.ensureResolved(compiler);
+ metadata.ensureResolved(compiler.resolution);
ConstantValue value =
compiler.constants.getConstantValue(metadata.constant);
Element element = value.getType(compiler.coreTypes).element;
@@ -382,6 +386,8 @@
Compiler get compiler => analyzer.compiler;
+ DiagnosticReporter get reporter => analyzer.reporter;
+
/// Convert a constant to a list of [String] and [Type] values. If the
/// constant is a single [String], it is assumed to be a comma-separated list
/// of qualified names. If the constant is a [Type] t, the result is [:[t]:].
@@ -409,7 +415,7 @@
MessageKind kind = onlyStrings
? MessageKind.MIRRORS_EXPECTED_STRING
: MessageKind.MIRRORS_EXPECTED_STRING_OR_TYPE;
- compiler.reportHintMessage(
+ reporter.reportHintMessage(
node, kind, {'name': node, 'type': apiTypeOf(entry)});
}
}
@@ -427,7 +433,7 @@
MessageKind kind = onlyStrings
? MessageKind.MIRRORS_EXPECTED_STRING_OR_LIST
: MessageKind.MIRRORS_EXPECTED_STRING_TYPE_OR_LIST;
- compiler.reportHintMessage(
+ reporter.reportHintMessage(
node, kind, {'name': node, 'type': apiTypeOf(constant)});
return null;
}
@@ -440,7 +446,7 @@
if (type.isInterfaceType && library.isInternalLibrary) {
InterfaceType interface = type;
ClassElement cls = type.element;
- cls.ensureResolved(compiler);
+ cls.ensureResolved(compiler.resolution);
for (DartType supertype in cls.allSupertypes) {
if (supertype.isInterfaceType
&& !supertype.element.library.isInternalLibrary) {
@@ -511,7 +517,7 @@
List<String> identifiers = expression.split('.');
Element element = enclosingLibrary.find(identifiers[0]);
if (element == null) {
- compiler.reportHintMessage(
+ reporter.reportHintMessage(
spannable,
MessageKind.MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY,
{'name': expression});
@@ -530,12 +536,12 @@
if (e == null) {
if (current.isLibrary) {
LibraryElement library = current;
- compiler.reportHintMessage(
+ reporter.reportHintMessage(
spannable, MessageKind.MIRRORS_CANNOT_RESOLVE_IN_LIBRARY,
{'name': identifiers[0],
'library': library.libraryOrScriptName});
} else {
- compiler.reportHintMessage(
+ reporter.reportHintMessage(
spannable, MessageKind.MIRRORS_CANNOT_FIND_IN_ELEMENT,
{'name': identifier, 'element': current.name});
}
@@ -553,7 +559,7 @@
ScopeContainerElement scope = element;
if (element.isClass) {
ClassElement cls = element;
- cls.ensureResolved(compiler);
+ cls.ensureResolved(compiler.resolution);
}
return scope.localLookup(name);
}
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart
index dfb2c60..c742a7d 100644
--- a/pkg/compiler/lib/src/native/behavior.dart
+++ b/pkg/compiler/lib/src/native/behavior.dart
@@ -196,7 +196,7 @@
/// latter is used for the type strings of the form '' and 'var'.
/// [validTags] can be used to restrict which tags are accepted.
static void processSpecString(
- DiagnosticListener listener,
+ DiagnosticReporter reporter,
Spannable spannable,
String specString,
{Iterable<String> validTags,
@@ -214,7 +214,7 @@
void reportError(String message) {
seenError = true;
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
spannable, MessageKind.GENERIC, {'text': message});
}
@@ -424,7 +424,12 @@
return sideEffects;
}
- static NativeBehavior ofJsCall(Send jsCall, Compiler compiler, resolver) {
+ static NativeBehavior ofJsCall(
+ Send jsCall,
+ DiagnosticReporter reporter,
+ Parsing parsing,
+ CoreTypes coreTypes,
+ ForeignResolver resolver) {
// The first argument of a JS-call is a string encoding various attributes
// of the code.
//
@@ -435,7 +440,7 @@
var argNodes = jsCall.arguments;
if (argNodes.isEmpty || argNodes.tail.isEmpty) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
jsCall,
MessageKind.GENERIC,
{'text': "JS expression takes two or more arguments."});
@@ -444,7 +449,7 @@
var specArgument = argNodes.head;
if (specArgument is !StringNode || specArgument.isInterpolation) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
specArgument, MessageKind.GENERIC,
{'text': "JS first argument must be a string literal."});
return behavior;
@@ -452,7 +457,7 @@
var codeArgument = argNodes.tail.head;
if (codeArgument is !StringNode || codeArgument.isInterpolation) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
codeArgument, MessageKind.GENERIC,
{'text': "JS second argument must be a string literal."});
return behavior;
@@ -466,7 +471,7 @@
dynamic resolveType(String typeString) {
return _parseType(
typeString,
- compiler,
+ parsing,
(name) => resolver.resolveTypeFromString(specArgument, name),
specArgument);
}
@@ -492,7 +497,9 @@
behavior.useGvn = useGvn;
}
- processSpecString(compiler, specArgument,
+ processSpecString(
+ reporter,
+ specArgument,
specString,
setSideEffects: setSideEffects,
setThrows: setThrows,
@@ -501,8 +508,8 @@
resolveType: resolveType,
typesReturned: behavior.typesReturned,
typesInstantiated: behavior.typesInstantiated,
- objectType: compiler.objectClass.computeType(compiler),
- nullType: compiler.nullClass.computeType(compiler));
+ objectType: coreTypes.objectType,
+ nullType: coreTypes.nullType);
if (!sideEffectsAreEncodedInSpecString) {
new SideEffectsVisitor(behavior.sideEffects)
@@ -519,8 +526,10 @@
static void _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal(
NativeBehavior behavior,
Send jsBuiltinOrEmbeddedGlobalCall,
- Compiler compiler,
- ResolverVisitor resolver,
+ DiagnosticReporter reporter,
+ Parsing parsing,
+ CoreTypes coreTypes,
+ ForeignResolver resolver,
{bool isBuiltin,
List<String> validTags}) {
// The first argument of a JS-embedded global call is a string encoding
@@ -533,7 +542,7 @@
Link<Node> argNodes = jsBuiltinOrEmbeddedGlobalCall.arguments;
if (argNodes.isEmpty) {
- compiler.internalError(jsBuiltinOrEmbeddedGlobalCall,
+ reporter.internalError(jsBuiltinOrEmbeddedGlobalCall,
"JS $builtinOrGlobal expression has no type.");
}
@@ -541,13 +550,13 @@
// This is, because we want to allow non-literals (like references to
// enums) as names.
if (argNodes.tail.isEmpty) {
- compiler.internalError(jsBuiltinOrEmbeddedGlobalCall,
+ reporter.internalError(jsBuiltinOrEmbeddedGlobalCall,
'JS $builtinOrGlobal is missing name.');
}
if (!isBuiltin) {
if (!argNodes.tail.tail.isEmpty) {
- compiler.internalError(argNodes.tail.tail.head,
+ reporter.internalError(argNodes.tail.tail.head,
'JS embedded global has more than 2 arguments');
}
}
@@ -556,7 +565,7 @@
if (specLiteral == null) {
// TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It
// is not very satisfactory because it does not work for void, dynamic.
- compiler.internalError(argNodes.head, "Unexpected first argument.");
+ reporter.internalError(argNodes.head, "Unexpected first argument.");
}
String specString = specLiteral.dartString.slowToString();
@@ -564,7 +573,7 @@
dynamic resolveType(String typeString) {
return _parseType(
typeString,
- compiler,
+ parsing,
(name) => resolver.resolveTypeFromString(specLiteral, name),
jsBuiltinOrEmbeddedGlobalCall);
}
@@ -573,32 +582,46 @@
behavior.sideEffects.setTo(newEffects);
}
- processSpecString(compiler, jsBuiltinOrEmbeddedGlobalCall,
- specString,
- validTags: validTags,
- resolveType: resolveType,
- setSideEffects: setSideEffects,
- typesReturned: behavior.typesReturned,
- typesInstantiated: behavior.typesInstantiated,
- objectType: compiler.objectClass.computeType(compiler),
- nullType: compiler.nullClass.computeType(compiler));
+ processSpecString(
+ reporter,
+ jsBuiltinOrEmbeddedGlobalCall,
+ specString,
+ validTags: validTags,
+ resolveType: resolveType,
+ setSideEffects: setSideEffects,
+ typesReturned: behavior.typesReturned,
+ typesInstantiated: behavior.typesInstantiated,
+ objectType: coreTypes.objectType,
+ nullType: coreTypes.nullType);
}
- static NativeBehavior ofJsBuiltinCall(Send jsBuiltinCall,
- Compiler compiler,
- ResolverVisitor resolver) {
+ static NativeBehavior ofJsBuiltinCall(
+ Send jsBuiltinCall,
+ DiagnosticReporter reporter,
+ Parsing parsing,
+ CoreTypes coreTypes,
+ ForeignResolver resolver) {
NativeBehavior behavior = new NativeBehavior();
behavior.sideEffects.setTo(new SideEffects());
_fillNativeBehaviorOfBuiltinOrEmbeddedGlobal(
- behavior, jsBuiltinCall, compiler, resolver, isBuiltin: true);
+ behavior,
+ jsBuiltinCall,
+ reporter,
+ parsing,
+ coreTypes,
+ resolver,
+ isBuiltin: true);
return behavior;
}
- static NativeBehavior ofJsEmbeddedGlobalCall(Send jsEmbeddedGlobalCall,
- Compiler compiler,
- ResolverVisitor resolver) {
+ static NativeBehavior ofJsEmbeddedGlobalCall(
+ Send jsEmbeddedGlobalCall,
+ DiagnosticReporter reporter,
+ Parsing parsing,
+ CoreTypes coreTypes,
+ ForeignResolver resolver) {
NativeBehavior behavior = new NativeBehavior();
// TODO(sra): Allow the use site to override these defaults.
// Embedded globals are usually pre-computed data structures or JavaScript
@@ -607,29 +630,34 @@
behavior.throwBehavior = NativeThrowBehavior.NEVER;
_fillNativeBehaviorOfBuiltinOrEmbeddedGlobal(
- behavior, jsEmbeddedGlobalCall, compiler, resolver,
+ behavior,
+ jsEmbeddedGlobalCall,
+ reporter,
+ parsing,
+ coreTypes,
+ resolver,
isBuiltin: false,
validTags: const ['returns', 'creates']);
return behavior;
}
- static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) {
- FunctionType type = method.computeType(compiler);
+ static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) {
+ FunctionType type = method.computeType(compiler.resolution);
var behavior = new NativeBehavior();
behavior.typesReturned.add(type.returnType);
if (!type.returnType.isVoid) {
// Declared types are nullable.
- behavior.typesReturned.add(compiler.nullClass.computeType(compiler));
+ behavior.typesReturned.add(compiler.coreTypes.nullType);
}
- behavior._capture(type, compiler);
+ behavior._capture(type, compiler.resolution);
// TODO(sra): Optional arguments are currently missing from the
// DartType. This should be fixed so the following work-around can be
// removed.
method.functionSignature.forEachOptionalParameter(
(ParameterElement parameter) {
- behavior._escape(parameter.type, compiler);
+ behavior._escape(parameter.type, compiler.resolution);
});
behavior._overrideWithAnnotations(method, compiler);
@@ -637,20 +665,22 @@
}
static NativeBehavior ofFieldLoad(MemberElement field, Compiler compiler) {
- DartType type = field.computeType(compiler);
+ Resolution resolution = compiler.resolution;
+ DartType type = field.computeType(resolution);
var behavior = new NativeBehavior();
behavior.typesReturned.add(type);
// Declared types are nullable.
- behavior.typesReturned.add(compiler.nullClass.computeType(compiler));
- behavior._capture(type, compiler);
+ behavior.typesReturned.add(resolution.coreTypes.nullType);
+ behavior._capture(type, resolution);
behavior._overrideWithAnnotations(field, compiler);
return behavior;
}
static NativeBehavior ofFieldStore(MemberElement field, Compiler compiler) {
- DartType type = field.computeType(compiler);
+ Resolution resolution = compiler.resolution;
+ DartType type = field.computeType(resolution);
var behavior = new NativeBehavior();
- behavior._escape(type, compiler);
+ behavior._escape(type, resolution);
// We don't override the default behaviour - the annotations apply to
// loading the field.
return behavior;
@@ -664,7 +694,7 @@
if (e == null) return null;
if (e is! ClassElement) return null;
ClassElement cls = e;
- cls.ensureResolved(compiler);
+ cls.ensureResolved(compiler.resolution);
return cls.thisType;
}
@@ -689,9 +719,10 @@
*/
static _collect(Element element, Compiler compiler, Element annotationClass,
lookup(str)) {
+ DiagnosticReporter reporter = compiler.reporter;
var types = null;
for (MetadataAnnotation annotation in element.implementation.metadata) {
- annotation.ensureResolved(compiler);
+ annotation.ensureResolved(compiler.resolution);
ConstantValue value =
compiler.constants.getConstantValue(annotation.constant);
if (!value.isConstructedObject) continue;
@@ -701,14 +732,13 @@
Iterable<ConstantValue> fields = constructedObject.fields.values;
// TODO(sra): Better validation of the constant.
if (fields.length != 1 || !fields.single.isString) {
- PartialMetadataAnnotation partial = annotation;
- compiler.internalError(annotation,
- 'Annotations needs one string: ${partial.parseNode(compiler)}');
+ reporter.internalError(annotation,
+ 'Annotations needs one string: ${annotation.node}');
}
StringConstantValue specStringConstant = fields.single;
String specString = specStringConstant.toDartString().slowToString();
for (final typeString in specString.split('|')) {
- var type = _parseType(typeString, compiler, lookup, annotation);
+ var type = _parseType(typeString, compiler.parsing, lookup, annotation);
if (types == null) types = [];
types.add(type);
}
@@ -718,15 +748,15 @@
/// Models the behavior of having intances of [type] escape from Dart code
/// into native code.
- void _escape(DartType type, Compiler compiler) {
- type = type.unalias(compiler);
+ void _escape(DartType type, Resolution resolution) {
+ type = type.unalias(resolution);
if (type is FunctionType) {
FunctionType functionType = type;
// A function might be called from native code, passing us novel
// parameters.
- _escape(functionType.returnType, compiler);
+ _escape(functionType.returnType, resolution);
for (DartType parameter in functionType.parameterTypes) {
- _capture(parameter, compiler);
+ _capture(parameter, resolution);
}
}
}
@@ -734,21 +764,24 @@
/// Models the behavior of Dart code receiving instances and methods of [type]
/// from native code. We usually start the analysis by capturing a native
/// method that has been used.
- void _capture(DartType type, Compiler compiler) {
- type = type.unalias(compiler);
+ void _capture(DartType type, Resolution resolution) {
+ type = type.unalias(resolution);
if (type is FunctionType) {
FunctionType functionType = type;
- _capture(functionType.returnType, compiler);
+ _capture(functionType.returnType, resolution);
for (DartType parameter in functionType.parameterTypes) {
- _escape(parameter, compiler);
+ _escape(parameter, resolution);
}
} else {
typesInstantiated.add(type);
}
}
- static dynamic _parseType(String typeString, Compiler compiler,
+ static dynamic _parseType(
+ String typeString,
+ Parsing parsing,
lookup(name), locationNodeOrElement) {
+ DiagnosticReporter reporter = parsing.reporter;
if (typeString == '=Object') return SpecialType.JsObject;
if (typeString == 'dynamic') {
return const DynamicType();
@@ -758,8 +791,8 @@
int index = typeString.indexOf('<');
if (index < 1) {
- compiler.reportErrorMessage(
- _errorNode(locationNodeOrElement, compiler),
+ reporter.reportErrorMessage(
+ _errorNode(locationNodeOrElement, parsing),
MessageKind.GENERIC,
{'text': "Type '$typeString' not found."});
return const DynamicType();
@@ -769,15 +802,15 @@
// TODO(sra): Parse type parameters.
return type;
}
- compiler.reportErrorMessage(
- _errorNode(locationNodeOrElement, compiler),
+ reporter.reportErrorMessage(
+ _errorNode(locationNodeOrElement, parsing),
MessageKind.GENERIC,
{'text': "Type '$typeString' not found."});
return const DynamicType();
}
- static _errorNode(locationNodeOrElement, compiler) {
+ static _errorNode(locationNodeOrElement, Parsing parsing) {
if (locationNodeOrElement is Node) return locationNodeOrElement;
- return locationNodeOrElement.parseNode(compiler);
+ return locationNodeOrElement.parseNode(parsing);
}
}
diff --git a/pkg/compiler/lib/src/native/enqueue.dart b/pkg/compiler/lib/src/native/enqueue.dart
index 25a4b26..6b39359 100644
--- a/pkg/compiler/lib/src/native/enqueue.dart
+++ b/pkg/compiler/lib/src/native/enqueue.dart
@@ -34,42 +34,6 @@
/// Returns whether native classes are being used.
bool hasInstantiatedNativeClasses() => false;
- /**
- * Handles JS-calls, which can be an instantiation point for types.
- *
- * For example, the following code instantiates and returns native classes
- * that are `_DOMWindowImpl` or a subtype.
- *
- * JS('_DOMWindowImpl', 'window')
- *
- */
- // TODO(sra): The entry from codegen will not have a resolver.
- void registerJsCall(Send node, ResolverVisitor resolver) {}
-
- /**
- * Handles JS-embedded global calls, which can be an instantiation point for
- * types.
- *
- * For example, the following code instantiates and returns a String class
- *
- * JS_EMBEDDED_GLOBAL('String', 'foo')
- *
- */
- // TODO(sra): The entry from codegen will not have a resolver.
- void registerJsEmbeddedGlobalCall(Send node, ResolverVisitor resolver) {}
-
- /**
- * Handles JS-compiler builtin calls, which can be an instantiation point for
- * types.
- *
- * For example, the following code instantiates and returns a String class
- *
- * JS_BUILTIN('String', 'int2string', 0)
- *
- */
- // TODO(sra): The entry from codegen will not have a resolver.
- void registerJsBuiltinCall(Send node, ResolverVisitor resolver) {}
-
/// Emits a summary information using the [log] function.
void logSummary(log(message)) {}
@@ -131,6 +95,9 @@
processedLibraries = compiler.cacheStrategy.newSet();
JavaScriptBackend get backend => compiler.backend;
+ Resolution get resolution => compiler.resolution;
+
+ DiagnosticReporter get reporter => compiler.reporter;
void processNativeClasses(Iterable<LibraryElement> libraries) {
if (compiler.hasIncrementalSupport) {
@@ -163,7 +130,7 @@
nativeClasses.add(classElement);
unusedClasses.add(classElement);
// Resolve class to ensure the class has valid inheritance info.
- classElement.ensureResolved(compiler);
+ classElement.ensureResolved(resolution);
}
void processSubclassesOfNativeClasses(Iterable<LibraryElement> libraries) {
@@ -202,7 +169,7 @@
void walkPotentialSubclasses(ClassElement element) {
if (nativeClassesAndSubclasses.contains(element)) return;
- element.ensureResolved(compiler);
+ element.ensureResolved(resolution);
ClassElement nativeSuperclass = nativeSuperclassOf(element);
if (nativeSuperclass != null) {
nativeClassesAndSubclasses.add(element);
@@ -278,7 +245,7 @@
return id.value;
}
- return compiler.withCurrentElement(classElement, () {
+ return reporter.withCurrentElement(classElement, () {
return scanForExtendsName(classElement.position);
});
}
@@ -303,7 +270,7 @@
ClassElement find(name) {
Element e = backend.findHelper(name);
if (e == null || e is! ClassElement) {
- compiler.internalError(NO_LOCATION_SPANNABLE,
+ reporter.internalError(NO_LOCATION_SPANNABLE,
"Could not find implementation class '${name}'.");
}
return e;
@@ -319,7 +286,7 @@
String name = null;
ClassElement annotationClass = annotationJsNameClass;
for (MetadataAnnotation annotation in element.implementation.metadata) {
- annotation.ensureResolved(compiler);
+ annotation.ensureResolved(resolution);
ConstantValue value =
compiler.constants.getConstantValue(annotation.constant);
if (!value.isConstructedObject) continue;
@@ -329,18 +296,16 @@
Iterable<ConstantValue> fields = constructedObject.fields.values;
// TODO(sra): Better validation of the constant.
if (fields.length != 1 || fields.single is! StringConstantValue) {
- PartialMetadataAnnotation partial = annotation;
- compiler.internalError(annotation,
- 'Annotations needs one string: ${partial.parseNode(compiler)}');
+ reporter.internalError(annotation,
+ 'Annotations needs one string: ${annotation.node}');
}
StringConstantValue specStringConstant = fields.single;
String specString = specStringConstant.toDartString().slowToString();
if (name == null) {
name = specString;
} else {
- PartialMetadataAnnotation partial = annotation;
- compiler.internalError(annotation,
- 'Too many JSName annotations: ${partial.parseNode(compiler)}');
+ reporter.internalError(annotation,
+ 'Too many JSName annotations: ${annotation.node}');
}
}
return name;
@@ -372,21 +337,17 @@
registeredClasses.add(classElement);
// TODO(ahe): Is this really a global dependency?
- classElement.ensureResolved(compiler);
+ classElement.ensureResolved(resolution);
compiler.backend.registerInstantiatedType(
classElement.rawType, world, compiler.globalDependencies);
- // Also parse the node to know all its methods because otherwise it will
- // only be parsed if there is a call to one of its constructors.
- classElement.parseNode(compiler);
-
if (firstTime) {
queue.add(onFirstNativeClass);
}
}
registerElement(Element element) {
- compiler.withCurrentElement(element, () {
+ reporter.withCurrentElement(element, () {
if (element.isFunction || element.isGetter || element.isSetter) {
handleMethodAnnotations(element);
if (element.isNative) {
@@ -446,7 +407,7 @@
if (isIdentifier(name)) {
List<String> nativeNames = nativeTagsOfClassRaw(element.enclosingClass);
if (nativeNames.length != 1) {
- compiler.internalError(element,
+ reporter.internalError(element,
'Unable to determine a native name for the enclosing class, '
'options: $nativeNames');
}
@@ -461,8 +422,8 @@
bool isNativeMethod(FunctionElementX element) {
if (!element.library.canUseNative) return false;
// Native method?
- return compiler.withCurrentElement(element, () {
- Node node = element.parseNode(compiler);
+ return reporter.withCurrentElement(element, () {
+ Node node = element.parseNode(resolution.parsing);
if (node is! FunctionExpression) return false;
FunctionExpression functionExpression = node;
node = functionExpression.body;
@@ -489,26 +450,6 @@
registerNativeBehavior(NativeBehavior.ofFieldStore(field, compiler), field);
}
- void registerJsCall(Send node, ResolverVisitor resolver) {
- NativeBehavior behavior = NativeBehavior.ofJsCall(node, compiler, resolver);
- registerNativeBehavior(behavior, node);
- nativeBehaviors[node] = behavior;
- }
-
- void registerJsEmbeddedGlobalCall(Send node, ResolverVisitor resolver) {
- NativeBehavior behavior =
- NativeBehavior.ofJsEmbeddedGlobalCall(node, compiler, resolver);
- registerNativeBehavior(behavior, node);
- nativeBehaviors[node] = behavior;
- }
-
- void registerJsBuiltinCall(Send node, ResolverVisitor resolver) {
- NativeBehavior behavior =
- NativeBehavior.ofJsBuiltinCall(node, compiler, resolver);
- registerNativeBehavior(behavior, node);
- nativeBehaviors[node] = behavior;
- }
-
NativeBehavior getNativeBehaviorOf(Send node) => nativeBehaviors[node];
processNativeBehavior(NativeBehavior behavior, cause) {
@@ -556,7 +497,7 @@
// Give an info so that library developers can compile with -v to find why
// all the native classes are included.
if (unusedClasses.isEmpty && !allUsedBefore) {
- compiler.log('All native types marked as used due to $cause.');
+ reporter.log('All native types marked as used due to $cause.');
}
}
@@ -609,7 +550,7 @@
ClassElement owner = tagOwner[tag];
if (owner != null) {
if (owner != classElement) {
- compiler.internalError(
+ reporter.internalError(
classElement, "Tag '$tag' already in use by '${owner.name}'");
}
} else {
@@ -622,6 +563,56 @@
log('Resolved ${registeredClasses.length} native elements used, '
'${unusedClasses.length} native elements dead.');
}
+
+ /**
+ * Handles JS-calls, which can be an instantiation point for types.
+ *
+ * For example, the following code instantiates and returns native classes
+ * that are `_DOMWindowImpl` or a subtype.
+ *
+ * JS('_DOMWindowImpl', 'window')
+ *
+ */
+ void registerJsCall(Send node, ForeignResolver resolver) {
+ NativeBehavior behavior = NativeBehavior.ofJsCall(
+ node, reporter, compiler.parsing, compiler.coreTypes, resolver);
+ registerNativeBehavior(behavior, node);
+ nativeBehaviors[node] = behavior;
+ }
+
+
+ /**
+ * Handles JS-embedded global calls, which can be an instantiation point for
+ * types.
+ *
+ * For example, the following code instantiates and returns a String class
+ *
+ * JS_EMBEDDED_GLOBAL('String', 'foo')
+ *
+ */
+ void registerJsEmbeddedGlobalCall(Send node, ForeignResolver resolver) {
+ NativeBehavior behavior = NativeBehavior.ofJsEmbeddedGlobalCall(
+ node, reporter, compiler.parsing, compiler.coreTypes, resolver);
+ registerNativeBehavior(behavior, node);
+ nativeBehaviors[node] = behavior;
+ }
+
+
+ /**
+ * Handles JS-compiler builtin calls, which can be an instantiation point for
+ * types.
+ *
+ * For example, the following code instantiates and returns a String class
+ *
+ * JS_BUILTIN('String', 'int2string', 0)
+ *
+ */
+ void registerJsBuiltinCall(Send node, ForeignResolver resolver) {
+ NativeBehavior behavior = NativeBehavior.ofJsBuiltinCall(
+ node, reporter, compiler.parsing, compiler.coreTypes, resolver);
+ registerNativeBehavior(behavior, node);
+ nativeBehaviors[node] = behavior;
+ }
}
diff --git a/pkg/compiler/lib/src/native/native.dart b/pkg/compiler/lib/src/native/native.dart
index fe1659e..c6bd3f1 100644
--- a/pkg/compiler/lib/src/native/native.dart
+++ b/pkg/compiler/lib/src/native/native.dart
@@ -6,13 +6,21 @@
import 'dart:collection' show Queue;
+import '../common/backend_api.dart' show
+ ForeignResolver;
import '../common/registry.dart' show
Registry;
+import '../common/resolution.dart' show
+ Parsing,
+ Resolution;
import '../compiler.dart' show
Compiler;
import '../constants/values.dart';
+import '../core_types.dart' show
+ CoreTypes;
import '../dart_types.dart';
-import '../diagnostics/diagnostic_listener.dart';
+import '../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import '../diagnostics/messages.dart' show
MessageKind;
import '../diagnostics/spannable.dart' show
@@ -38,8 +46,6 @@
ElementListener;
import '../parser/partial_elements.dart' show
PartialMetadataAnnotation;
-import '../resolution/members.dart' show
- ResolverVisitor;
import '../ssa/ssa.dart';
import '../tokens/token.dart' show
BeginGroupToken,
diff --git a/pkg/compiler/lib/src/native/ssa.dart b/pkg/compiler/lib/src/native/ssa.dart
index e622559..a93338b 100644
--- a/pkg/compiler/lib/src/native/ssa.dart
+++ b/pkg/compiler/lib/src/native/ssa.dart
@@ -11,6 +11,7 @@
FunctionElement element = builder.work.element;
NativeEmitter nativeEmitter = builder.nativeEmitter;
JavaScriptBackend backend = builder.backend;
+ DiagnosticReporter reporter = compiler.reporter;
HInstruction convertDartClosure(ParameterElement parameter,
FunctionType type) {
@@ -40,7 +41,7 @@
LiteralString jsCode = nativeBody.asLiteralString();
String str = jsCode.dartString.slowToString();
if (nativeRedirectionRegExp.hasMatch(str)) {
- compiler.internalError(
+ reporter.internalError(
nativeBody, "Deprecated syntax, use @JSName('name') instead.");
}
hasBody = true;
@@ -60,7 +61,7 @@
inputs.add(builder.localsHandler.readThis());
}
parameters.forEachParameter((ParameterElement parameter) {
- DartType type = parameter.type.unalias(compiler);
+ DartType type = parameter.type.unalias(compiler.resolution);
HInstruction input = builder.localsHandler.readLocal(parameter);
if (type is FunctionType) {
// The parameter type is a function type either directly or through
@@ -80,7 +81,7 @@
} else if (element.kind == ElementKind.SETTER) {
nativeMethodCall = '$receiver$nativeMethodName = $foreignParameters';
} else {
- builder.compiler.internalError(element,
+ builder.reporter.internalError(element,
'Unexpected kind: "${element.kind}".');
}
@@ -98,7 +99,7 @@
.addSuccessor(builder.graph.exit);
} else {
if (parameters.parameterCount != 0) {
- compiler.internalError(nativeBody,
+ reporter.internalError(nativeBody,
'native "..." syntax is restricted to '
'functions with zero parameters.');
}
diff --git a/pkg/compiler/lib/src/ordered_typeset.dart b/pkg/compiler/lib/src/ordered_typeset.dart
index 48f3228..290b94f 100644
--- a/pkg/compiler/lib/src/ordered_typeset.dart
+++ b/pkg/compiler/lib/src/ordered_typeset.dart
@@ -7,6 +7,8 @@
import 'compiler.dart' show
Compiler;
import 'dart_types.dart';
+import 'diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import 'diagnostics/invariant.dart' show
invariant;
import 'diagnostics/messages.dart' show
@@ -163,23 +165,25 @@
if (type.element != compiler.objectClass) {
allSupertypes.addLast(compiler.objectClass.rawType);
}
- _addAtDepth(compiler, type, maxDepth + 1);
+ DiagnosticReporter reporter = compiler.reporter;
+ _addAtDepth(reporter, type, maxDepth + 1);
} else {
if (type.element != compiler.objectClass) {
allSupertypes.addLast(type);
}
- _addAtDepth(compiler, type, type.element.hierarchyDepth);
+ DiagnosticReporter reporter = compiler.reporter;
+ _addAtDepth(reporter, type, type.element.hierarchyDepth);
}
}
- void _addAtDepth(Compiler compiler, InterfaceType type, int depth) {
+ void _addAtDepth(DiagnosticReporter reporter, InterfaceType type, int depth) {
LinkEntry<DartType> prev = null;
LinkEntry<DartType> link = map[depth];
while (link != null) {
DartType existingType = link.head;
if (existingType == type) return;
if (existingType.element == type.element) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
cls,
MessageKind.MULTI_INHERITANCE,
{'thisType': cls.thisType,
diff --git a/pkg/compiler/lib/src/parser/diet_parser_task.dart b/pkg/compiler/lib/src/parser/diet_parser_task.dart
index ee22ae9..ee65817 100644
--- a/pkg/compiler/lib/src/parser/diet_parser_task.dart
+++ b/pkg/compiler/lib/src/parser/diet_parser_task.dart
@@ -30,7 +30,7 @@
measure(() {
Function idGenerator = compiler.getNextFreeClassId;
ElementListener listener =
- new ElementListener(compiler, compilationUnit, idGenerator);
+ new ElementListener(compiler.reporter, compilationUnit, idGenerator);
PartialParser parser = new PartialParser(listener);
try {
parser.parseUnit(tokens);
diff --git a/pkg/compiler/lib/src/parser/element_listener.dart b/pkg/compiler/lib/src/parser/element_listener.dart
index 95af9a4..4b97999 100644
--- a/pkg/compiler/lib/src/parser/element_listener.dart
+++ b/pkg/compiler/lib/src/parser/element_listener.dart
@@ -63,7 +63,7 @@
*/
class ElementListener extends Listener {
final IdGenerator idGenerator;
- final DiagnosticListener listener;
+ final DiagnosticReporter reporter;
final CompilationUnitElementX compilationUnitElement;
final StringValidator stringValidator;
Link<StringQuoting> interpolationScope;
@@ -85,11 +85,11 @@
bool suppressParseErrors = false;
ElementListener(
- DiagnosticListener listener,
+ DiagnosticReporter reporter,
this.compilationUnitElement,
this.idGenerator)
- : this.listener = listener,
- stringValidator = new StringValidator(listener),
+ : this.reporter = reporter,
+ stringValidator = new StringValidator(reporter),
interpolationScope = const Link<StringQuoting>();
bool get currentMemberHasParseError {
@@ -110,7 +110,7 @@
StringNode node = popNode();
// TODO(lrn): Handle interpolations in script tags.
if (node.isInterpolation) {
- listener.internalError(node,
+ reporter.internalError(node,
"String interpolation not supported in library tags.");
return null;
}
@@ -201,7 +201,7 @@
}
void addPartOfTag(PartOf tag) {
- compilationUnitElement.setPartOf(tag, listener);
+ compilationUnitElement.setPartOf(tag, reporter);
}
void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
@@ -594,7 +594,7 @@
void pushElement(Element element) {
popMetadata(element);
- compilationUnitElement.addMember(element, listener);
+ compilationUnitElement.addMember(element, reporter);
}
List<MetadataAnnotation> popMetadata(ElementX element) {
@@ -614,7 +614,7 @@
}
LibraryElementX implementationLibrary =
compilationUnitElement.implementationLibrary;
- implementationLibrary.addTag(tag, listener);
+ implementationLibrary.addTag(tag, reporter);
}
void pushNode(Node node) {
@@ -748,6 +748,6 @@
if (!memberErrors.isEmpty) {
memberErrors = memberErrors.tail.prepend(true);
}
- listener.reportErrorMessage(spannable, errorCode, arguments);
+ reporter.reportErrorMessage(spannable, errorCode, arguments);
}
}
diff --git a/pkg/compiler/lib/src/parser/member_listener.dart b/pkg/compiler/lib/src/parser/member_listener.dart
index cd6de0e..4982d90 100644
--- a/pkg/compiler/lib/src/parser/member_listener.dart
+++ b/pkg/compiler/lib/src/parser/member_listener.dart
@@ -5,7 +5,7 @@
library dart2js.parser.member_listener;
import '../diagnostics/diagnostic_listener.dart' show
- DiagnosticListener;
+ DiagnosticReporter;
import '../diagnostics/messages.dart' show
MessageKind;
import '../elements/elements.dart' show
@@ -34,7 +34,7 @@
class MemberListener extends NodeListener {
final ClassElementX enclosingClass;
- MemberListener(DiagnosticListener listener,
+ MemberListener(DiagnosticReporter listener,
ClassElementX enclosingElement)
: this.enclosingClass = enclosingElement,
super(listener, enclosingElement.compilationUnit);
@@ -72,7 +72,7 @@
return Elements.constructOperatorName(operator.source, isUnary);
} else {
if (receiver == null || receiver.source != enclosingClass.name) {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
send.receiver,
MessageKind.INVALID_CONSTRUCTOR_NAME,
{'name': enclosingClass.name});
@@ -113,7 +113,7 @@
Identifier singleIdentifierName = method.name.asIdentifier();
if (singleIdentifierName != null && singleIdentifierName.source == name) {
if (name != enclosingClass.name) {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
singleIdentifierName,
MessageKind.INVALID_UNNAMED_CONSTRUCTOR_NAME,
{'name': enclosingClass.name});
@@ -160,7 +160,7 @@
void addMember(ElementX memberElement) {
addMetadata(memberElement);
- enclosingClass.addMember(memberElement, listener);
+ enclosingClass.addMember(memberElement, reporter);
}
void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
diff --git a/pkg/compiler/lib/src/parser/node_listener.dart b/pkg/compiler/lib/src/parser/node_listener.dart
index d079b70..1344c5d 100644
--- a/pkg/compiler/lib/src/parser/node_listener.dart
+++ b/pkg/compiler/lib/src/parser/node_listener.dart
@@ -31,9 +31,9 @@
class NodeListener extends ElementListener {
NodeListener(
- DiagnosticListener listener,
+ DiagnosticReporter reporter,
CompilationUnitElement element)
- : super(listener, element, null);
+ : super(reporter, element, null);
void addLibraryTag(LibraryTag tag) {
pushNode(tag);
@@ -199,7 +199,7 @@
}
void handleOnError(Token token, var errorInformation) {
- listener.internalError(token, "'${token.value}': ${errorInformation}");
+ reporter.internalError(token, "'${token.value}': ${errorInformation}");
}
Token expectedFunctionBody(Token token) {
@@ -270,13 +270,13 @@
pushNode(new Send(receiver, new Operator(token), arguments));
}
if (identical(tokenString, '===')) {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
token,
MessageKind.UNSUPPORTED_EQ_EQ_EQ,
{'lhs': receiver, 'rhs': argument});
}
if (identical(tokenString, '!==')) {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
token,
MessageKind.UNSUPPORTED_BANG_EQ_EQ,
{'lhs': receiver, 'rhs': argument});
@@ -451,7 +451,7 @@
void endRethrowStatement(Token throwToken, Token endToken) {
pushNode(new Rethrow(throwToken, endToken));
if (identical(throwToken.stringValue, 'throw')) {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
throwToken, MessageKind.UNSUPPORTED_THROW_WITHOUT_EXP);
}
}
@@ -814,11 +814,11 @@
}
void log(message) {
- listener.log(message);
+ reporter.log(message);
}
void internalError({Token token, Node node}) {
- // TODO(ahe): This should call listener.internalError.
+ // TODO(ahe): This should call reporter.internalError.
Spannable spannable = (token == null) ? node : token;
throw new SpannableAssertionFailure(spannable, 'Internal error in parser.');
}
diff --git a/pkg/compiler/lib/src/parser/parser_task.dart b/pkg/compiler/lib/src/parser/parser_task.dart
index a0e900a4..24429ad 100644
--- a/pkg/compiler/lib/src/parser/parser_task.dart
+++ b/pkg/compiler/lib/src/parser/parser_task.dart
@@ -29,12 +29,12 @@
String get name => 'Parser';
Node parse(ElementX element) {
- return measure(() => element.parseNode(compiler));
+ return measure(() => element.parseNode(compiler.parsing));
}
Node parseCompilationUnit(Token token) {
return measure(() {
- NodeListener listener = new NodeListener(compiler, null);
+ NodeListener listener = new NodeListener(reporter, null);
Parser parser = new Parser(listener);
try {
parser.parseUnit(token);
diff --git a/pkg/compiler/lib/src/parser/partial_elements.dart b/pkg/compiler/lib/src/parser/partial_elements.dart
index 17412f7..b0a1b79 100644
--- a/pkg/compiler/lib/src/parser/partial_elements.dart
+++ b/pkg/compiler/lib/src/parser/partial_elements.dart
@@ -4,10 +4,12 @@
library dart2js.parser.partial_elements;
-import '../compiler.dart' show
- Compiler;
+import '../common/resolution.dart' show
+ Parsing,
+ Resolution;
import '../dart_types.dart' show DynamicType;
-import '../diagnostics/diagnostic_listener.dart';
+import '../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import '../diagnostics/invariant.dart' show
invariant;
import '../diagnostics/messages.dart';
@@ -104,7 +106,7 @@
return cachedNode;
}
- FunctionExpression parseNode(DiagnosticListener listener) {
+ FunctionExpression parseNode(Parsing parsing) {
if (cachedNode != null) return cachedNode;
parseFunction(Parser p) {
if (isClassMember && modifiers.isFactory) {
@@ -113,7 +115,7 @@
p.parseFunction(beginToken, getOrSet);
}
}
- cachedNode = parse(listener, this, declarationSite, parseFunction);
+ cachedNode = parse(parsing, this, declarationSite, parseFunction);
return cachedNode;
}
@@ -268,11 +270,12 @@
super.hasParseError = hasParseError;
}
- VariableDefinitions parseNode(Element element, DiagnosticListener listener) {
+ VariableDefinitions parseNode(Element element, Parsing parsing) {
if (definitions != null) return definitions;
- listener.withCurrentElement(element, () {
+ DiagnosticReporter reporter = parsing.reporter;
+ reporter.withCurrentElement(element, () {
definitions = parse(
- listener, element, declarationSite,
+ parsing, element, declarationSite,
(Parser parser) => parser.parseMember(beginToken));
if (!hasParseError &&
@@ -281,7 +284,7 @@
!definitions.modifiers.isConst &&
definitions.type == null &&
!definitions.isErroneous) {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
definitions,
MessageKind.GENERIC,
{ 'text': 'A field declaration must start with var, final, '
@@ -291,17 +294,15 @@
return definitions;
}
- computeType(Element element, Compiler compiler) {
+ computeType(Element element, Resolution resolution) {
if (type != null) return type;
// TODO(johnniwinther): Compute this in the resolver.
- compiler.withCurrentElement(element, () {
- VariableDefinitions node = parseNode(element, compiler);
- if (node.type != null) {
- type = compiler.resolver.resolveTypeAnnotation(element, node.type);
- } else {
- type = const DynamicType();
- }
- });
+ VariableDefinitions node = parseNode(element, resolution.parsing);
+ if (node.type != null) {
+ type = resolution.resolveTypeAnnotation(element, node.type);
+ } else {
+ type = const DynamicType();
+ }
assert(type != null);
return type;
}
@@ -321,10 +322,10 @@
Token get token => beginToken;
- Node parseNode(DiagnosticListener listener) {
+ Node parseNode(Parsing parsing) {
if (cachedNode != null) return cachedNode;
cachedNode = parse(
- listener, this, declarationSite,
+ parsing, this, declarationSite,
(p) => p.parseTopLevelDeclaration(token));
return cachedNode;
}
@@ -363,9 +364,9 @@
throw new UnsupportedError("endToken=");
}
- Node parseNode(DiagnosticListener listener) {
+ Node parseNode(Parsing parsing) {
if (cachedNode != null) return cachedNode;
- var metadata = parse(listener,
+ var metadata = parse(parsing,
annotatedElement,
declarationSite,
(p) => p.parseMetadata(beginToken));
@@ -419,11 +420,12 @@
return cachedNode;
}
- ClassNode parseNode(Compiler compiler) {
+ ClassNode parseNode(Parsing parsing) {
if (cachedNode != null) return cachedNode;
- compiler.withCurrentElement(this, () {
- compiler.parser.measure(() {
- MemberListener listener = new MemberListener(compiler, this);
+ DiagnosticReporter reporter = parsing.reporter;
+ reporter.withCurrentElement(this, () {
+ parsing.measure(() {
+ MemberListener listener = new MemberListener(reporter, this);
Parser parser = new ClassElementParser(listener);
try {
Token token = parser.parseTopLevelDeclaration(beginToken);
@@ -450,13 +452,9 @@
hasParseError = true;
}
});
- compiler.patchParser.measure(() {
- if (isPatched) {
- // TODO(lrn): Perhaps extract functionality so it doesn't
- // need compiler.
- compiler.patchParser.parsePatchClassNode(patch);
- }
- });
+ if (isPatched) {
+ parsing.parsePatchClass(patch);
+ }
});
return cachedNode;
}
@@ -477,23 +475,28 @@
}
Node parse(
- DiagnosticListener diagnosticListener,
+ Parsing parsing,
ElementX element,
PartialElement partial,
doParse(Parser parser)) {
- CompilationUnitElement unit = element.compilationUnit;
- NodeListener listener = new NodeListener(diagnosticListener, unit);
- listener.memberErrors = listener.memberErrors.prepend(false);
- try {
- if (partial.hasParseError) {
- listener.suppressParseErrors = true;
- }
- doParse(new Parser(listener));
- } on ParserError catch (e) {
- partial.hasParseError = true;
- return new ErrorNode(element.position, e.reason);
- }
- Node node = listener.popNode();
- assert(listener.nodes.isEmpty);
- return node;
+ DiagnosticReporter reporter = parsing.reporter;
+ return parsing.measure(() {
+ return reporter.withCurrentElement(element, () {
+ CompilationUnitElement unit = element.compilationUnit;
+ NodeListener listener = new NodeListener(reporter, unit);
+ listener.memberErrors = listener.memberErrors.prepend(false);
+ try {
+ if (partial.hasParseError) {
+ listener.suppressParseErrors = true;
+ }
+ doParse(new Parser(listener));
+ } on ParserError catch (e) {
+ partial.hasParseError = true;
+ return new ErrorNode(element.position, e.reason);
+ }
+ Node node = listener.popNode();
+ assert(listener.nodes.isEmpty);
+ return node;
+ });
+ });
}
diff --git a/pkg/compiler/lib/src/patch_parser.dart b/pkg/compiler/lib/src/patch_parser.dart
index 8eb9f85..fb5096b 100644
--- a/pkg/compiler/lib/src/patch_parser.dart
+++ b/pkg/compiler/lib/src/patch_parser.dart
@@ -122,6 +122,8 @@
Compiler;
import 'common/tasks.dart' show
CompilerTask;
+import 'dart_types.dart' show
+ DartType;
import 'diagnostics/diagnostic_listener.dart';
import 'diagnostics/messages.dart' show
MessageKind;
@@ -154,7 +156,6 @@
import 'tokens/token.dart' show
StringToken,
Token;
-import 'util/util.dart';
class PatchParserTask extends CompilerTask {
final String name = "Patching Parser";
@@ -171,9 +172,9 @@
return compiler.readScript(originLibrary, patchUri)
.then((Script script) {
var patchLibrary = new LibraryElementX(script, null, originLibrary);
- return compiler.withCurrentElement(patchLibrary, () {
+ return reporter.withCurrentElement(patchLibrary, () {
loader.registerNewLibrary(patchLibrary);
- compiler.withCurrentElement(patchLibrary.entryCompilationUnit, () {
+ reporter.withCurrentElement(patchLibrary.entryCompilationUnit, () {
// This patches the elements of the patch library into [library].
// Injected elements are added directly under the compilation unit.
// Patch elements are stored on the patched functions or classes.
@@ -198,7 +199,7 @@
} on ParserError catch (e) {
// No need to recover from a parser error in platform libraries, user
// will never see this if the libraries are tested correctly.
- compiler.internalError(
+ reporter.internalError(
compilationUnit, "Parser error in patch file: $e");
}
});
@@ -209,7 +210,7 @@
// of calling its [parseNode] method.
if (cls.cachedNode != null) return;
- measure(() => compiler.withCurrentElement(cls, () {
+ measure(() => reporter.withCurrentElement(cls, () {
MemberListener listener = new PatchMemberListener(compiler, cls);
Parser parser = new PatchClassElementParser(listener);
try {
@@ -218,7 +219,7 @@
} on ParserError catch (e) {
// No need to recover from a parser error in platform libraries, user
// will never see this if the libraries are tested correctly.
- compiler.internalError(
+ reporter.internalError(
cls, "Parser error in patch file: $e");
}
cls.cachedNode = listener.popNode();
@@ -232,7 +233,7 @@
PatchMemberListener(Compiler compiler, ClassElement enclosingClass)
: this.compiler = compiler,
- super(compiler, enclosingClass);
+ super(compiler.reporter, enclosingClass);
@override
void addMember(Element patch) {
@@ -242,13 +243,13 @@
if (patchVersion != null) {
if (patchVersion.isActive(compiler.patchVersion)) {
Element origin = enclosingClass.origin.localLookup(patch.name);
- patchElement(compiler, origin, patch);
- enclosingClass.addMember(patch, listener);
+ patchElement(compiler, reporter, origin, patch);
+ enclosingClass.addMember(patch, reporter);
} else {
// Skip this element.
}
} else {
- enclosingClass.addMember(patch, listener);
+ enclosingClass.addMember(patch, reporter);
}
}
}
@@ -273,7 +274,7 @@
CompilationUnitElement patchElement,
int idGenerator())
: this.compiler = compiler,
- super(compiler, patchElement, idGenerator);
+ super(compiler.reporter, patchElement, idGenerator);
@override
void pushElement(Element patch) {
@@ -285,22 +286,23 @@
LibraryElement originLibrary = compilationUnitElement.library;
assert(originLibrary.isPatched);
Element origin = originLibrary.localLookup(patch.name);
- patchElement(listener, origin, patch);
- compilationUnitElement.addMember(patch, listener);
+ patchElement(compiler, reporter, origin, patch);
+ compilationUnitElement.addMember(patch, reporter);
} else {
// Skip this element.
}
} else {
- compilationUnitElement.addMember(patch, listener);
+ compilationUnitElement.addMember(patch, reporter);
}
}
}
void patchElement(Compiler compiler,
+ DiagnosticReporter reporter,
Element origin,
Element patch) {
if (origin == null) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
patch, MessageKind.PATCH_NON_EXISTING, {'name': patch.name});
return;
}
@@ -309,50 +311,52 @@
origin.isFunction ||
origin.isAbstractField)) {
// TODO(ahe): Remove this error when the parser rejects all bad modifiers.
- compiler.reportErrorMessage(origin, MessageKind.PATCH_NONPATCHABLE);
+ reporter.reportErrorMessage(origin, MessageKind.PATCH_NONPATCHABLE);
return;
}
if (patch.isClass) {
- tryPatchClass(compiler, origin, patch);
+ tryPatchClass(compiler, reporter, origin, patch);
} else if (patch.isGetter) {
- tryPatchGetter(compiler, origin, patch);
+ tryPatchGetter(reporter, origin, patch);
} else if (patch.isSetter) {
- tryPatchSetter(compiler, origin, patch);
+ tryPatchSetter(reporter, origin, patch);
} else if (patch.isConstructor) {
- tryPatchConstructor(compiler, origin, patch);
+ tryPatchConstructor(reporter, origin, patch);
} else if(patch.isFunction) {
- tryPatchFunction(compiler, origin, patch);
+ tryPatchFunction(reporter, origin, patch);
} else {
// TODO(ahe): Remove this error when the parser rejects all bad modifiers.
- compiler.reportErrorMessage(patch, MessageKind.PATCH_NONPATCHABLE);
+ reporter.reportErrorMessage(patch, MessageKind.PATCH_NONPATCHABLE);
}
}
void tryPatchClass(Compiler compiler,
+ DiagnosticReporter reporter,
Element origin,
ClassElement patch) {
if (!origin.isClass) {
- compiler.reportError(
- compiler.createMessage(
+ reporter.reportError(
+ reporter.createMessage(
origin,
MessageKind.PATCH_NON_CLASS,
{'className': patch.name}),
<DiagnosticMessage>[
- compiler.createMessage(
+ reporter.createMessage(
patch,
MessageKind.PATCH_POINT_TO_CLASS,
{'className': patch.name}),
]);
return;
}
- patchClass(compiler, origin, patch);
+ patchClass(compiler, reporter, origin, patch);
}
void patchClass(Compiler compiler,
+ DiagnosticReporter reporter,
ClassElementX origin,
ClassElementX patch) {
if (origin.isPatched) {
- compiler.internalError(origin,
+ reporter.internalError(origin,
"Patching the same class more than once.");
}
origin.applyPatch(patch);
@@ -399,7 +403,7 @@
// TODO(johnniwinther): Perform this check in
// [Compiler.onLibrariesLoaded].
compiler.enqueuer.resolution.addDeferredAction(element, () {
- annotation.ensureResolved(compiler);
+ annotation.ensureResolved(compiler.resolution);
handler.validate(
compiler, element, annotation,
compiler.constants.getConstantValue(annotation.constant));
@@ -446,9 +450,10 @@
Element element,
MetadataAnnotation annotation,
ConstantValue constant) {
- if (constant.getType(compiler.coreTypes).element !=
- compiler.nativeAnnotationClass) {
- compiler.internalError(annotation, 'Invalid @Native(...) annotation.');
+ DartType annotationType = constant.getType(compiler.coreTypes);
+ if (annotationType.element != compiler.nativeAnnotationClass) {
+ DiagnosticReporter reporter = compiler.reporter;
+ reporter.internalError(annotation, 'Invalid @Native(...) annotation.');
}
}
}
@@ -484,25 +489,26 @@
Element element,
MetadataAnnotation annotation,
ConstantValue constant) {
- if (constant.getType(compiler.coreTypes).element !=
- compiler.patchAnnotationClass) {
- compiler.internalError(annotation, 'Invalid patch annotation.');
+ DartType annotationType = constant.getType(compiler.coreTypes);
+ if (annotationType.element != compiler.patchAnnotationClass) {
+ DiagnosticReporter reporter = compiler.reporter;
+ reporter.internalError(annotation, 'Invalid patch annotation.');
}
}
}
-void tryPatchGetter(DiagnosticListener listener,
+void tryPatchGetter(DiagnosticReporter reporter,
Element origin,
FunctionElement patch) {
if (!origin.isAbstractField) {
- listener.reportError(
- listener.createMessage(
+ reporter.reportError(
+ reporter.createMessage(
origin,
MessageKind.PATCH_NON_GETTER,
{'name': origin.name}),
<DiagnosticMessage>[
- listener.createMessage(
+ reporter.createMessage(
patch,
MessageKind.PATCH_POINT_TO_GETTER,
{'getterName': patch.name}),
@@ -511,13 +517,13 @@
}
AbstractFieldElement originField = origin;
if (originField.getter == null) {
- listener.reportError(
- listener.createMessage(
+ reporter.reportError(
+ reporter.createMessage(
origin,
MessageKind.PATCH_NO_GETTER,
{'getterName': patch.name}),
<DiagnosticMessage>[
- listener.createMessage(
+ reporter.createMessage(
patch,
MessageKind.PATCH_POINT_TO_GETTER,
{'getterName': patch.name}),
@@ -525,20 +531,20 @@
return;
}
GetterElementX getter = originField.getter;
- patchFunction(listener, getter, patch);
+ patchFunction(reporter, getter, patch);
}
-void tryPatchSetter(DiagnosticListener listener,
+void tryPatchSetter(DiagnosticReporter reporter,
Element origin,
FunctionElement patch) {
if (!origin.isAbstractField) {
- listener.reportError(
- listener.createMessage(
+ reporter.reportError(
+ reporter.createMessage(
origin,
MessageKind.PATCH_NON_SETTER,
{'name': origin.name}),
<DiagnosticMessage>[
- listener.createMessage(
+ reporter.createMessage(
patch,
MessageKind.PATCH_POINT_TO_SETTER,
{'setterName': patch.name}),
@@ -547,13 +553,13 @@
}
AbstractFieldElement originField = origin;
if (originField.setter == null) {
- listener.reportError(
- listener.createMessage(
+ reporter.reportError(
+ reporter.createMessage(
origin,
MessageKind.PATCH_NO_SETTER,
{'setterName': patch.name}),
<DiagnosticMessage>[
- listener.createMessage(
+ reporter.createMessage(
patch,
MessageKind.PATCH_POINT_TO_SETTER,
{'setterName': patch.name}),
@@ -561,57 +567,57 @@
return;
}
SetterElementX setter = originField.setter;
- patchFunction(listener, setter, patch);
+ patchFunction(reporter, setter, patch);
}
-void tryPatchConstructor(DiagnosticListener listener,
+void tryPatchConstructor(DiagnosticReporter reporter,
Element origin,
FunctionElement patch) {
if (!origin.isConstructor) {
- listener.reportError(
- listener.createMessage(
+ reporter.reportError(
+ reporter.createMessage(
origin,
MessageKind.PATCH_NON_CONSTRUCTOR,
{'constructorName': patch.name}),
<DiagnosticMessage>[
- listener.createMessage(
+ reporter.createMessage(
patch,
MessageKind.PATCH_POINT_TO_CONSTRUCTOR,
{'constructorName': patch.name}),
]);
return;
}
- patchFunction(listener, origin, patch);
+ patchFunction(reporter, origin, patch);
}
-void tryPatchFunction(DiagnosticListener listener,
+void tryPatchFunction(DiagnosticReporter reporter,
Element origin,
FunctionElement patch) {
if (!origin.isFunction) {
- listener.reportError(
- listener.createMessage(
+ reporter.reportError(
+ reporter.createMessage(
origin,
MessageKind.PATCH_NON_FUNCTION,
{'functionName': patch.name}),
<DiagnosticMessage>[
- listener.createMessage(
+ reporter.createMessage(
patch,
MessageKind.PATCH_POINT_TO_FUNCTION,
{'functionName': patch.name}),
]);
return;
}
- patchFunction(listener, origin, patch);
+ patchFunction(reporter, origin, patch);
}
-void patchFunction(DiagnosticListener listener,
+void patchFunction(DiagnosticReporter reporter,
BaseFunctionElementX origin,
BaseFunctionElementX patch) {
if (!origin.modifiers.isExternal) {
- listener.reportError(
- listener.createMessage(origin, MessageKind.PATCH_NON_EXTERNAL),
+ reporter.reportError(
+ reporter.createMessage(origin, MessageKind.PATCH_NON_EXTERNAL),
<DiagnosticMessage>[
- listener.createMessage(
+ reporter.createMessage(
patch,
MessageKind.PATCH_POINT_TO_FUNCTION,
{'functionName': patch.name}),
@@ -619,7 +625,7 @@
return;
}
if (origin.isPatched) {
- listener.internalError(origin,
+ reporter.internalError(origin,
"Trying to patch a function more than once.");
}
origin.applyPatch(patch);
diff --git a/pkg/compiler/lib/src/resolution/class_hierarchy.dart b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
index 383c671..9f1ce4b 100644
--- a/pkg/compiler/lib/src/resolution/class_hierarchy.dart
+++ b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
@@ -68,7 +68,7 @@
TypeVariable typeNode = nodeLink.head;
registry.useType(typeNode, typeVariable);
if (nameSet.contains(typeName)) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
typeNode,
MessageKind.DUPLICATE_TYPE_VARIABLE_NAME,
{'typeVariableName': typeName});
@@ -92,7 +92,7 @@
if (identical(element, variableElement)) {
// Only report an error on the checked type variable to avoid
// generating multiple errors for the same cyclicity.
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
typeNode.name,
MessageKind.CYCLIC_TYPE_VARIABLE,
{'typeVariableName': variableElement.name});
@@ -135,14 +135,14 @@
DartType visitClassNode(ClassNode node) {
if (element == null) {
- throw compiler.internalError(node, 'element is null');
+ throw reporter.internalError(node, 'element is null');
}
if (element.resolutionState != STATE_STARTED) {
- throw compiler.internalError(element,
+ throw reporter.internalError(element,
'cyclic resolution of class $element');
}
- element.computeType(compiler);
+ element.computeType(resolution);
scope = new TypeDeclarationScope(scope, element);
// TODO(ahe): It is not safe to call resolveTypeVariableBounds yet.
// As a side-effect, this may get us back here trying to
@@ -175,12 +175,12 @@
// Avoid making the superclass (usually Object) extend itself.
if (element != superElement) {
if (superElement == null) {
- compiler.internalError(node,
+ reporter.internalError(node,
"Cannot resolve default superclass for $element.");
} else {
- superElement.ensureResolved(compiler);
+ superElement.ensureResolved(resolution);
}
- element.supertype = superElement.computeType(compiler);
+ element.supertype = superElement.computeType(resolution);
}
}
@@ -198,17 +198,17 @@
Map arguments = {'constructorName': ''};
// TODO(ahe): Why is this a compile-time error? Or if it is an error,
// why do we bother to registerThrowNoSuchMethod below?
- compiler.reportErrorMessage(node, kind, arguments);
+ reporter.reportErrorMessage(node, kind, arguments);
superMember = new ErroneousElementX(
kind, arguments, '', element);
registry.registerThrowNoSuchMethod();
} else {
ConstructorElement superConstructor = superMember;
- superConstructor.computeType(compiler);
+ superConstructor.computeType(resolution);
if (!CallStructure.NO_ARGS.signatureApplies(
superConstructor.functionSignature)) {
MessageKind kind = MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT;
- compiler.reportErrorMessage(node, kind);
+ reporter.reportErrorMessage(node, kind);
superMember = new ErroneousElementX(kind, {}, '', element);
}
}
@@ -217,34 +217,35 @@
if (superMember.isErroneous) {
compiler.elementsWithCompileTimeErrors.add(constructor);
}
- element.setDefaultConstructor(constructor, compiler);
+ element.setDefaultConstructor(constructor, reporter);
}
- return element.computeType(compiler);
+ return element.computeType(resolution);
}
@override
DartType visitEnum(Enum node) {
if (element == null) {
- throw compiler.internalError(node, 'element is null');
+ throw reporter.internalError(node, 'element is null');
}
if (element.resolutionState != STATE_STARTED) {
- throw compiler.internalError(element,
+ throw reporter.internalError(element,
'cyclic resolution of class $element');
}
- InterfaceType enumType = element.computeType(compiler);
- element.supertype = compiler.objectClass.computeType(compiler);
+ InterfaceType enumType = element.computeType(resolution);
+ element.supertype = compiler.coreTypes.objectType;
element.interfaces = const Link<DartType>();
calculateAllSupertypes(element);
if (node.names.nodes.isEmpty) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node,
MessageKind.EMPTY_ENUM_DECLARATION,
{'enumName': element.name});
}
- EnumCreator creator = new EnumCreator(compiler, element);
+ EnumCreator creator =
+ new EnumCreator(reporter, compiler.coreTypes, element);
creator.createMembers();
return enumType;
}
@@ -254,21 +255,21 @@
DartType checkMixinType(TypeAnnotation mixinNode) {
DartType mixinType = resolveType(mixinNode);
if (isBlackListed(mixinType)) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
mixinNode,
MessageKind.CANNOT_MIXIN,
{'type': mixinType});
} else if (mixinType.isTypeVariable) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
mixinNode,
MessageKind.CLASS_NAME_EXPECTED);
} else if (mixinType.isMalformed) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
mixinNode,
MessageKind.CANNOT_MIXIN_MALFORMED,
{'className': element.name, 'malformedType': mixinType});
} else if (mixinType.isEnumType) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
mixinNode,
MessageKind.CANNOT_MIXIN_ENUM,
{'className': element.name, 'enumType': mixinType});
@@ -278,22 +279,22 @@
DartType visitNamedMixinApplication(NamedMixinApplication node) {
if (element == null) {
- throw compiler.internalError(node, 'element is null');
+ throw reporter.internalError(node, 'element is null');
}
if (element.resolutionState != STATE_STARTED) {
- throw compiler.internalError(element,
+ throw reporter.internalError(element,
'cyclic resolution of class $element');
}
if (identical(node.classKeyword.stringValue, 'typedef')) {
// TODO(aprelev@gmail.com): Remove this deprecation diagnostic
// together with corresponding TODO in parser.dart.
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
node.classKeyword,
MessageKind.DEPRECATED_TYPEDEF_MIXIN_SYNTAX);
}
- element.computeType(compiler);
+ element.computeType(resolution);
scope = new TypeDeclarationScope(scope, element);
resolveTypeVariableBounds(node.typeParameters);
@@ -306,7 +307,7 @@
link = link.tail;
}
doApplyMixinTo(element, supertype, checkMixinType(link.head));
- return element.computeType(compiler);
+ return element.computeType(resolution);
}
DartType applyMixin(DartType supertype, DartType mixinType, Node node) {
@@ -337,7 +338,7 @@
type.element.bound.subst(typeVariables, element.typeVariables);
}
// Setup this and raw type for the mixin application.
- mixinApplication.computeThisAndRawType(compiler, typeVariables);
+ mixinApplication.computeThisAndRawType(resolution, typeVariables);
// Substitute in synthetic type variables in super and mixin types.
supertype = supertype.subst(typeVariables, element.typeVariables);
mixinType = mixinType.subst(typeVariables, element.typeVariables);
@@ -354,7 +355,7 @@
bool isDefaultConstructor(FunctionElement constructor) {
if (constructor.name != '') return false;
- constructor.computeType(compiler);
+ constructor.computeType(resolution);
return constructor.functionSignature.parameterCount == 0;
}
@@ -363,14 +364,14 @@
FunctionElement constructor =
new SynthesizedConstructorElementX.notForDefault(
target.name, target, enclosing);
- constructor.computeType(compiler);
+ constructor.computeType(resolution);
return constructor;
}
void doApplyMixinTo(MixinApplicationElementX mixinApplication,
DartType supertype,
DartType mixinType) {
- Node node = mixinApplication.parseNode(compiler);
+ Node node = mixinApplication.parseNode(resolution.parsing);
if (mixinApplication.supertype != null) {
// [supertype] is not null if there was a cycle.
@@ -435,7 +436,7 @@
InterfaceType resolveMixinFor(MixinApplicationElement mixinApplication,
DartType mixinType) {
ClassElement mixin = mixinType.element;
- mixin.ensureResolved(compiler);
+ mixin.ensureResolved(resolution);
// Check for cycles in the mixin chain.
ClassElement previous = mixinApplication; // For better error messages.
@@ -443,7 +444,7 @@
while (current != null && current.isMixinApplication) {
MixinApplicationElement currentMixinApplication = current;
if (currentMixinApplication == mixinApplication) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
mixinApplication,
MessageKind.ILLEGAL_MIXIN_CYCLE,
{'mixinName1': current.name, 'mixinName2': previous.name});
@@ -467,24 +468,24 @@
DartType supertype = resolveType(superclass);
if (supertype != null) {
if (supertype.isMalformed) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
superclass,
MessageKind.CANNOT_EXTEND_MALFORMED,
{'className': element.name, 'malformedType': supertype});
return objectType;
} else if (supertype.isEnumType) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
superclass,
MessageKind.CANNOT_EXTEND_ENUM,
{'className': element.name, 'enumType': supertype});
return objectType;
} else if (!supertype.isInterfaceType) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
superclass.typeName,
MessageKind.CLASS_NAME_EXPECTED);
return objectType;
} else if (isBlackListed(supertype)) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
superclass,
MessageKind.CANNOT_EXTEND,
{'type': supertype});
@@ -501,40 +502,40 @@
DartType interfaceType = resolveType(link.head);
if (interfaceType != null) {
if (interfaceType.isMalformed) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
superclass,
MessageKind.CANNOT_IMPLEMENT_MALFORMED,
{'className': element.name, 'malformedType': interfaceType});
} else if (interfaceType.isEnumType) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
superclass,
MessageKind.CANNOT_IMPLEMENT_ENUM,
{'className': element.name, 'enumType': interfaceType});
} else if (!interfaceType.isInterfaceType) {
// TODO(johnniwinther): Handle dynamic.
TypeAnnotation typeAnnotation = link.head;
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
typeAnnotation.typeName, MessageKind.CLASS_NAME_EXPECTED);
} else {
if (interfaceType == element.supertype) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
superclass,
MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS,
{'type': interfaceType});
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
link.head,
MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS,
{'type': interfaceType});
}
if (result.contains(interfaceType)) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
link.head,
MessageKind.DUPLICATE_IMPLEMENTS,
{'type': interfaceType});
}
result = result.prepend(interfaceType);
if (isBlackListed(interfaceType)) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
link.head,
MessageKind.CANNOT_IMPLEMENT,
{'type': interfaceType});
@@ -581,12 +582,12 @@
interfaces = interfaces.tail) {
addAllSupertypes(allSupertypes, interfaces.head);
}
- allSupertypes.add(compiler, cls.computeType(compiler));
+ allSupertypes.add(compiler, cls.computeType(resolution));
cls.allSupertypesAndSelf = allSupertypes.toTypeSet();
} else {
assert(identical(cls, compiler.objectClass));
cls.allSupertypesAndSelf =
- new OrderedTypeSet.singleton(cls.computeType(compiler));
+ new OrderedTypeSet.singleton(cls.computeType(resolution));
}
}
@@ -635,7 +636,7 @@
void loadSupertype(ClassElement element, Node from) {
if (!element.isResolved) {
compiler.resolver.loadSupertypes(element, from);
- element.ensureResolved(compiler);
+ element.ensureResolved(resolution);
}
}
@@ -678,7 +679,7 @@
}
void visitIdentifier(Identifier node) {
- Element element = lookupInScope(compiler, node, context, node.source);
+ Element element = lookupInScope(reporter, node, context, node.source);
if (element != null && element.isClass) {
loadSupertype(element, node);
}
@@ -687,13 +688,13 @@
void visitSend(Send node) {
Identifier prefix = node.receiver.asIdentifier();
if (prefix == null) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver});
return;
}
- Element element = lookupInScope(compiler, prefix, context, prefix.source);
+ Element element = lookupInScope(reporter, prefix, context, prefix.source);
if (element == null || !identical(element.kind, ElementKind.PREFIX)) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver});
return;
}
@@ -701,7 +702,7 @@
Identifier selector = node.selector.asIdentifier();
var e = prefixElement.lookupLocalMember(selector.source);
if (e == null || !e.impliesType) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node.selector,
MessageKind.CANNOT_RESOLVE_TYPE,
{'typeName': node.selector});
diff --git a/pkg/compiler/lib/src/resolution/class_members.dart b/pkg/compiler/lib/src/resolution/class_members.dart
index 2bcf2dd..b8f8784 100644
--- a/pkg/compiler/lib/src/resolution/class_members.dart
+++ b/pkg/compiler/lib/src/resolution/class_members.dart
@@ -6,11 +6,14 @@
import '../common/names.dart' show
Identifiers;
+import '../common/resolution.dart' show
+ Resolution;
import '../compiler.dart' show
Compiler;
import '../dart_types.dart';
import '../diagnostics/diagnostic_listener.dart' show
- DiagnosticMessage;
+ DiagnosticMessage,
+ DiagnosticReporter;
import '../diagnostics/invariant.dart' show
invariant;
import '../diagnostics/messages.dart' show
@@ -47,6 +50,10 @@
message: "Members may only be computed on declarations."));
}
+ DiagnosticReporter get reporter => compiler.reporter;
+
+ Resolution get resolution => compiler.resolution;
+
void reportMessage(var marker, MessageKind kind, report()) {
Set<MessageKind> messages =
reportedMessages.putIfAbsent(marker,
@@ -194,7 +201,7 @@
Name name = new Name(element.name, library);
if (element.isField) {
- DartType type = element.computeType(compiler);
+ DartType type = element.computeType(resolution);
addDeclaredMember(name, type, new FunctionType.synthesized(type));
if (!element.isConst && !element.isFinal) {
addDeclaredMember(name.setter, type,
@@ -203,11 +210,11 @@
<DartType>[type]));
}
} else if (element.isGetter) {
- FunctionType functionType = element.computeType(compiler);
+ FunctionType functionType = element.computeType(resolution);
DartType type = functionType.returnType;
addDeclaredMember(name, type, functionType);
} else if (element.isSetter) {
- FunctionType functionType = element.computeType(compiler);
+ FunctionType functionType = element.computeType(resolution);
DartType type;
if (!functionType.parameterTypes.isEmpty) {
type = functionType.parameterTypes.first;
@@ -218,7 +225,7 @@
addDeclaredMember(name, type, functionType);
} else {
assert(invariant(element, element.isFunction));
- FunctionType type = element.computeType(compiler);
+ FunctionType type = element.computeType(resolution);
addDeclaredMember(name, type, type);
}
}
@@ -256,7 +263,7 @@
}
reportMessage(
interfaceMember.element, MessageKind.ABSTRACT_METHOD, () {
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
interfaceMember.element, kind,
{'class': cls.name, 'name': name.text});
});
@@ -268,7 +275,7 @@
Member inherited = interfaceMember.declarations.first;
reportMessage(
interfaceMember, MessageKind.UNIMPLEMENTED_METHOD, () {
- DiagnosticMessage warning = compiler.createMessage(
+ DiagnosticMessage warning = reporter.createMessage(
cls,
interfaceMember.declarations.length == 1
? singleKind : multipleKind,
@@ -278,14 +285,14 @@
'declarer': inherited.declarer});
List<DiagnosticMessage> infos = <DiagnosticMessage>[];
for (Member inherited in interfaceMember.declarations) {
- infos.add(compiler.createMessage(
+ infos.add(reporter.createMessage(
inherited.element,
inherited.isDeclaredByField ?
implicitlyDeclaredKind : explicitlyDeclaredKind,
{'class': inherited.declarer.name,
'name': name.text}));
}
- compiler.reportWarning(warning, infos);
+ reporter.reportWarning(warning, infos);
});
}
if (interfaceMember.isSetter) {
@@ -320,7 +327,7 @@
if (compiler.backend.isBackendLibrary(cls.library)) return;
reportMessage(compiler.functionClass, MessageKind.UNIMPLEMENTED_METHOD, () {
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
cls,
MessageKind.UNIMPLEMENTED_METHOD_ONE,
{'class': cls.name,
@@ -345,14 +352,14 @@
if (superMember != null && superMember.isStatic) {
reportMessage(superMember, MessageKind.INSTANCE_STATIC_SAME_NAME,
() {
- compiler.reportWarning(
- compiler.createMessage(
+ reporter.reportWarning(
+ reporter.createMessage(
declared.element,
MessageKind.INSTANCE_STATIC_SAME_NAME,
{'memberName': declared.name,
'className': superclass.name}),
<DiagnosticMessage>[
- compiler.createMessage(
+ reporter.createMessage(
superMember.element,
MessageKind.INSTANCE_STATIC_SAME_NAME_CONT),
]);
@@ -399,15 +406,15 @@
void reportError(MessageKind errorKind, MessageKind infoKind) {
reportMessage(
inherited.element, MessageKind.INVALID_OVERRIDE_METHOD, () {
- compiler.reportError(
- compiler.createMessage(
+ reporter.reportError(
+ reporter.createMessage(
declared.element,
errorKind,
{'name': declared.name.text,
'class': cls.thisType,
'inheritedClass': inherited.declarer}),
<DiagnosticMessage>[
- compiler.createMessage(
+ reporter.createMessage(
inherited.element,
infoKind,
{'name': declared.name.text,
@@ -435,8 +442,8 @@
MessageKind warningKind,
MessageKind infoKind) {
reportMessage(marker, MessageKind.INVALID_OVERRIDE_METHOD, () {
- compiler.reportWarning(
- compiler.createMessage(
+ reporter.reportWarning(
+ reporter.createMessage(
declared.element,
warningKind,
{'declaredType': declared.type,
@@ -445,7 +452,7 @@
'inheritedType': inherited.type,
'inheritedClass': inherited.declarer}),
<DiagnosticMessage>[
- compiler.createMessage(
+ reporter.createMessage(
inherited.element,
infoKind,
{'name': declared.name.text,
@@ -502,14 +509,14 @@
MessageKind errorMessage,
Element contextElement,
MessageKind contextMessage) {
- compiler.reportError(
- compiler.createMessage(
+ reporter.reportError(
+ reporter.createMessage(
errorneousElement,
errorMessage,
{'memberName': contextElement.name,
'className': contextElement.enclosingClass.name}),
<DiagnosticMessage>[
- compiler.createMessage(contextElement, contextMessage),
+ reporter.createMessage(contextElement, contextMessage),
]);
}
@@ -713,7 +720,7 @@
() => new Setlet<Member>()).add(inherited);
}
if (someAreGetters && !allAreGetters) {
- DiagnosticMessage warning = compiler.createMessage(
+ DiagnosticMessage warning = reporter.createMessage(
cls,
MessageKind.INHERIT_GETTER_AND_METHOD,
{'class': thisType, 'name': name.text });
@@ -732,12 +739,12 @@
kind = MessageKind.INHERITED_EXPLICIT_GETTER;
}
}
- infos.add(compiler.createMessage(
+ infos.add(reporter.createMessage(
inherited.element,
kind,
{'class': inherited.declarer, 'name': name.text}));
}
- compiler.reportWarning(warning, infos);
+ reporter.reportWarning(warning, infos);
interfaceMembers[name] = new ErroneousMember(inheritedMembers);
} else if (subtypesOfAllInherited.length == 1) {
// All signatures have the same type.
@@ -846,6 +853,7 @@
/// this class.
MembersCreator _prepareCreator(Compiler compiler) {
if (classMembers == null) {
+ ensureResolved(compiler.resolution);
classMembers = new Map<Name, Member>();
if (interfaceMembersAreClassMembers) {
diff --git a/pkg/compiler/lib/src/resolution/constructors.dart b/pkg/compiler/lib/src/resolution/constructors.dart
index 94dcc525..256be2d 100644
--- a/pkg/compiler/lib/src/resolution/constructors.dart
+++ b/pkg/compiler/lib/src/resolution/constructors.dart
@@ -11,7 +11,7 @@
import '../constants/expressions.dart';
import '../dart_types.dart';
import '../diagnostics/diagnostic_listener.dart' show
- DiagnosticListener,
+ DiagnosticReporter,
DiagnosticMessage;
import '../diagnostics/invariant.dart' show
invariant;
@@ -62,7 +62,7 @@
ResolutionRegistry get registry => visitor.registry;
- DiagnosticListener get listener => visitor.compiler;
+ DiagnosticReporter get reporter => visitor.reporter;
bool isFieldInitializer(SendSet node) {
if (node.selector.asIdentifier() == null) return false;
@@ -72,13 +72,13 @@
}
reportDuplicateInitializerError(Element field, Node init, Node existing) {
- listener.reportError(
- listener.createMessage(
+ reporter.reportError(
+ reporter.createMessage(
init,
MessageKind.DUPLICATE_INITIALIZER,
{'fieldName': field.name}),
<DiagnosticMessage>[
- listener.createMessage(
+ reporter.createMessage(
existing,
MessageKind.ALREADY_INITIALIZED,
{'fieldName': field.name}),
@@ -92,7 +92,7 @@
if (initialized.containsKey(field)) {
reportDuplicateInitializerError(field, init, initialized[field]);
} else if (field.isFinal) {
- field.parseNode(visitor.compiler);
+ field.parseNode(visitor.resolution.parsing);
Expression initializer = field.initializer;
if (initializer != null) {
reportDuplicateInitializerError(field, init, initializer);
@@ -111,23 +111,23 @@
if (isFieldInitializer(init)) {
target = constructor.enclosingClass.lookupLocalMember(name);
if (target == null) {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
selector, MessageKind.CANNOT_RESOLVE, {'name': name});
target = new ErroneousFieldElementX(
selector.asIdentifier(), constructor.enclosingClass);
} else if (target.kind != ElementKind.FIELD) {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
selector, MessageKind.NOT_A_FIELD, {'fieldName': name});
target = new ErroneousFieldElementX(
selector.asIdentifier(), constructor.enclosingClass);
} else if (!target.isInstanceMember) {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
selector, MessageKind.INIT_STATIC_FIELD, {'fieldName': name});
} else {
field = target;
}
} else {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER);
}
registry.useElement(init, target);
@@ -152,7 +152,7 @@
if (isSuperCall) {
// Calculate correct lookup target and constructor name.
if (identical(constructor.enclosingClass, visitor.compiler.objectClass)) {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT);
isValidAsConstant = false;
} else {
@@ -264,23 +264,23 @@
MessageKind kind = isImplicitSuperCall
? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT
: MessageKind.CANNOT_RESOLVE_CONSTRUCTOR;
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
diagnosticNode, kind, {'constructorName': fullConstructorName});
isValidAsConstant = false;
} else {
- lookedupConstructor.computeType(visitor.compiler);
+ lookedupConstructor.computeType(visitor.resolution);
if (!call.signatureApplies(lookedupConstructor.functionSignature)) {
MessageKind kind = isImplicitSuperCall
? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT
: MessageKind.NO_MATCHING_CONSTRUCTOR;
- listener.reportErrorMessage(diagnosticNode, kind);
+ reporter.reportErrorMessage(diagnosticNode, kind);
isValidAsConstant = false;
} else if (constructor.isConst
&& !lookedupConstructor.isConst) {
MessageKind kind = isImplicitSuperCall
? MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT
: MessageKind.CONST_CALLS_NON_CONST;
- listener.reportErrorMessage(diagnosticNode, kind);
+ reporter.reportErrorMessage(diagnosticNode, kind);
isValidAsConstant = false;
}
}
@@ -350,13 +350,13 @@
} else if (link.head.asSend() != null) {
final Send call = link.head.asSend();
if (call.argumentsNode == null) {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
link.head, MessageKind.INVALID_INITIALIZER);
continue;
}
if (Initializers.isSuperConstructorCall(call)) {
if (resolvedSuper) {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
call, MessageKind.DUPLICATE_SUPER_INITIALIZER);
}
ResolutionResult result = resolveSuperOrThisForSend(call);
@@ -373,12 +373,12 @@
// constructor is also const, we already reported an error in
// [resolveMethodElement].
if (functionNode.hasBody() && !constructor.isConst) {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
functionNode, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY);
}
// Check that there are no other initializers.
if (!initializers.tail.isEmpty) {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
call, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER);
} else {
constructor.isRedirectingGenerative = true;
@@ -388,7 +388,7 @@
signature.forEachParameter((ParameterElement parameter) {
if (parameter.isInitializingFormal) {
Node node = parameter.node;
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED);
isValidAsConstant = false;
}
@@ -409,12 +409,12 @@
}
return result.element;
} else {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
call, MessageKind.CONSTRUCTOR_CALL_EXPECTED);
return null;
}
} else {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
link.head, MessageKind.INVALID_INITIALIZER);
}
}
@@ -462,10 +462,10 @@
registry.registerThrowRuntimeError();
}
if (isError || inConstContext) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
diagnosticNode, kind, arguments);
} else {
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
diagnosticNode, kind, arguments);
}
ErroneousElement error = new ErroneousConstructorElementX(
@@ -481,7 +481,7 @@
Node diagnosticNode,
String constructorName) {
ClassElement cls = type.element;
- cls.ensureResolved(compiler);
+ cls.ensureResolved(resolution);
ConstructorElement constructor = findConstructor(
resolver.enclosingElement.library, cls, constructorName);
if (constructor == null) {
@@ -495,14 +495,14 @@
{'constructorName': fullConstructorName},
missingConstructor: true);
} else if (inConstContext && !constructor.isConst) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST);
return new ConstructorResult(
ConstructorResultKind.NON_CONSTANT, constructor, type);
} else {
if (constructor.isGenerativeConstructor) {
if (cls.isAbstract) {
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
diagnosticNode, MessageKind.ABSTRACT_CLASS_INSTANTIATION);
registry.registerAbstractClassInstantiation();
return new ConstructorResult(
@@ -587,7 +587,7 @@
Identifier name = node.selector.asIdentifier();
if (name == null) {
- compiler.internalError(node.selector, 'unexpected node');
+ reporter.internalError(node.selector, 'unexpected node');
}
if (receiver.type != null) {
@@ -606,7 +606,7 @@
Element member = prefix.lookupLocalMember(name.source);
return constructorResultForElement(node, name.source, member);
} else {
- return compiler.internalError(
+ return reporter.internalError(
node.receiver, 'unexpected receiver $receiver');
}
}
@@ -614,7 +614,7 @@
ConstructorResult visitIdentifier(Identifier node) {
String name = node.source;
Element element = resolver.reportLookupErrorIfAny(
- lookupInScope(compiler, node, resolver.scope, name), node, name);
+ lookupInScope(reporter, node, resolver.scope, name), node, name);
registry.useElement(node, element);
// TODO(johnniwinther): Change errors to warnings, cf. 11.11.1.
return constructorResultForElement(node, name, element);
@@ -629,7 +629,7 @@
ConstructorResult constructorResultForElement(
Node node, String name, Element element) {
- element = Elements.unwrap(element, compiler, node);
+ element = Elements.unwrap(element, reporter, node);
if (element == null) {
return reportAndCreateErroneousConstructorElement(
node,
@@ -641,13 +641,13 @@
return constructorResultForErroneous(node, element);
} else if (element.isClass) {
ClassElement cls = element;
- cls.computeType(compiler);
+ cls.computeType(resolution);
return constructorResultForType(node, cls.rawType);
} else if (element.isPrefix) {
return new ConstructorResult.forElement(element);
} else if (element.isTypedef) {
TypedefElement typdef = element;
- typdef.ensureResolved(compiler);
+ typdef.ensureResolved(resolution);
return constructorResultForType(node, typdef.rawType);
} else if (element.isTypeVariable) {
TypeVariableElement typeVariableElement = element;
@@ -699,7 +699,7 @@
MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE,
{'typeVariableName': name});
}
- return compiler.internalError(node, "Unexpected constructor type $type");
+ return reporter.internalError(node, "Unexpected constructor type $type");
}
}
diff --git a/pkg/compiler/lib/src/resolution/enum_creator.dart b/pkg/compiler/lib/src/resolution/enum_creator.dart
index 02c2c53..127833d 100644
--- a/pkg/compiler/lib/src/resolution/enum_creator.dart
+++ b/pkg/compiler/lib/src/resolution/enum_creator.dart
@@ -4,8 +4,11 @@
library dart2js.resolution.enum_creator;
-import '../compiler.dart';
+import '../core_types.dart' show
+ CoreTypes;
import '../dart_types.dart';
+import '../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import '../elements/elements.dart';
import '../elements/modelx.dart';
import '../tokens/keyword.dart' show
@@ -179,18 +182,19 @@
}
class EnumCreator {
- final Compiler compiler;
+ final DiagnosticReporter reporter;
+ final CoreTypes coreTypes;
final EnumClassElementX enumClass;
- EnumCreator(this.compiler, this.enumClass);
+ EnumCreator(this.reporter, this.coreTypes, this.enumClass);
void createMembers() {
Enum node = enumClass.node;
InterfaceType enumType = enumClass.thisType;
AstBuilder builder = new AstBuilder(enumClass.position.charOffset);
- InterfaceType intType = compiler.intClass.computeType(compiler);
- InterfaceType stringType = compiler.stringClass.computeType(compiler);
+ InterfaceType intType = coreTypes.intType;
+ InterfaceType stringType = coreTypes.stringType;
EnumFieldElementX addInstanceMember(String name, InterfaceType type) {
Identifier identifier = builder.identifier(name);
@@ -199,7 +203,7 @@
variableList.type = type;
EnumFieldElementX variable = new EnumFieldElementX(
identifier, enumClass, variableList, identifier);
- enumClass.addMember(variable, compiler);
+ enumClass.addMember(variable, reporter);
return variable;
}
@@ -229,8 +233,8 @@
requiredParameterCount: 1,
type: new FunctionType(constructor, const VoidType(),
<DartType>[intType]));
- constructor.functionSignatureCache = constructorSignature;
- enumClass.addMember(constructor, compiler);
+ constructor.functionSignature = constructorSignature;
+ enumClass.addMember(constructor, reporter);
List<FieldElement> enumValues = <FieldElement>[];
VariableList variableList =
@@ -262,14 +266,13 @@
EnumFieldElementX field = new EnumFieldElementX(
name, enumClass, variableList, definition, initializer);
enumValues.add(field);
- enumClass.addMember(field, compiler);
+ enumClass.addMember(field, reporter);
index++;
}
VariableList valuesVariableList =
new VariableList(builder.modifiers(isStatic: true, isConst: true));
- InterfaceType listType = compiler.listClass.computeType(compiler);
- valuesVariableList.type = listType.createInstantiation([enumType]);
+ valuesVariableList.type = coreTypes.listType(enumType);
Identifier valuesIdentifier = builder.identifier('values');
// TODO(johnniwinther): Add type argument.
@@ -282,7 +285,7 @@
valuesIdentifier, enumClass, valuesVariableList,
definition, initializer);
- enumClass.addMember(valuesVariable, compiler);
+ enumClass.addMember(valuesVariable, reporter);
// TODO(johnniwinther): Support return type. Note `String` might be prefixed
// or not imported within the current library.
@@ -301,8 +304,8 @@
enumClass, Modifiers.EMPTY, toStringNode);
FunctionSignatureX toStringSignature = new FunctionSignatureX(
type: new FunctionType(toString, stringType));
- toString.functionSignatureCache = toStringSignature;
- enumClass.addMember(toString, compiler);
+ toString.functionSignature = toStringSignature;
+ enumClass.addMember(toString, reporter);
enumClass.enumValues = enumValues;
}
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index 8546700..2237a60 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -15,7 +15,8 @@
import '../core_types.dart';
import '../dart_types.dart';
import '../diagnostics/diagnostic_listener.dart' show
- DiagnosticMessage;
+ DiagnosticMessage,
+ DiagnosticReporter;
import '../diagnostics/invariant.dart' show
invariant;
import '../diagnostics/messages.dart' show
@@ -125,12 +126,6 @@
int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION
| ElementCategory.IMPLIES_TYPE;
- /**
- * Record of argument nodes to JS_INTERCEPTOR_CONSTANT for deferred
- * processing.
- */
- Set<Node> argumentsToJsInterceptorConstant = null;
-
/// When visiting the type declaration of the variable in a [ForIn] loop,
/// the initializer of the variable is implicit and we should not emit an
/// error when verifying that all final variables are initialized.
@@ -210,7 +205,7 @@
Element reportLookupErrorIfAny(Element result, Node node, String name) {
if (!Elements.isUnresolved(result)) {
if (!inInstanceContext && result.isInstanceMember) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.NO_INSTANCE_AVAILABLE, {'name': name});
return new ErroneousElementX(MessageKind.NO_INSTANCE_AVAILABLE,
{'name': name},
@@ -222,7 +217,7 @@
name,
ambiguous.messageKind,
ambiguous.messageArguments,
- infos: ambiguous.computeInfos(enclosingElement, compiler),
+ infos: ambiguous.computeInfos(enclosingElement, reporter),
isError: true);
}
}
@@ -307,11 +302,11 @@
{List<DiagnosticMessage> infos: const <DiagnosticMessage>[],
bool isError: false}) {
if (isError) {
- compiler.reportError(
- compiler.createMessage(node, kind, arguments), infos);
+ reporter.reportError(
+ reporter.createMessage(node, kind, arguments), infos);
} else {
- compiler.reportWarning(
- compiler.createMessage(node, kind, arguments), infos);
+ reporter.reportWarning(
+ reporter.createMessage(node, kind, arguments), infos);
}
// TODO(ahe): Use [allowedCategory] to synthesize a more precise subclass
// of [ErroneousElementX]. For example, [ErroneousFieldElementX],
@@ -360,23 +355,23 @@
ResolutionResult visitIdentifier(Identifier node) {
if (node.isThis()) {
if (!inInstanceContext) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.NO_INSTANCE_AVAILABLE, {'name': node});
}
return const NoneResult();
} else if (node.isSuper()) {
if (!inInstanceContext) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.NO_SUPER_IN_STATIC);
}
if ((ElementCategory.SUPER & allowedCategory) == 0) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.INVALID_USE_OF_SUPER);
}
return const NoneResult();
} else {
String name = node.source;
- Element element = lookupInScope(compiler, node, scope, name);
+ Element element = lookupInScope(reporter, node, scope, name);
if (Elements.isUnresolved(element) && name == 'dynamic') {
// TODO(johnniwinther): Remove this hack when we can return more complex
// objects than [Element] from this method.
@@ -401,7 +396,7 @@
}
if (!Elements.isUnresolved(element) && element.isClass) {
ClassElement classElement = element;
- classElement.ensureResolved(compiler);
+ classElement.ensureResolved(resolution);
}
if (element != null) {
registry.useElement(node, element);
@@ -419,7 +414,7 @@
TypeResult visitTypeAnnotation(TypeAnnotation node) {
DartType type = resolveTypeAnnotation(node);
if (inCheckContext) {
- registry.registerIsCheck(type);
+ registry.registerCheckedModeCheck(type);
}
return new TypeResult(type);
}
@@ -437,7 +432,7 @@
}
FunctionElement resolveConstructorRedirection(FunctionElementX constructor) {
- FunctionExpression node = constructor.parseNode(compiler);
+ FunctionExpression node = constructor.parseNode(resolution.parsing);
// A synthetic constructor does not have a node.
if (node == null) return null;
@@ -457,7 +452,7 @@
Element enclosingElement = function.enclosingElement;
if (node.modifiers.isStatic &&
enclosingElement.kind != ElementKind.CLASS) {
- compiler.reportErrorMessage(node, MessageKind.ILLEGAL_STATIC);
+ reporter.reportErrorMessage(node, MessageKind.ILLEGAL_STATIC);
}
scope = new MethodScope(scope, function);
@@ -505,7 +500,7 @@
});
if (inCheckContext) {
functionParameters.forEachParameter((ParameterElement element) {
- registry.registerIsCheck(element.type);
+ registry.registerCheckedModeCheck(element.type);
});
}
}
@@ -513,7 +508,7 @@
ResolutionResult visitAssert(Assert node) {
if (!compiler.enableAssertMessage) {
if (node.hasMessage) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.EXPERIMENTAL_ASSERT_MESSAGE);
}
}
@@ -608,7 +603,7 @@
{bool inFunctionDeclaration: false}) {
bool doAddToScope = inFunctionDeclaration;
if (!inFunctionDeclaration && node.name != null) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node.name,
MessageKind.NAMED_FUNCTION_EXPRESSION,
{'name': node.name});
@@ -624,7 +619,7 @@
name, node, ElementKind.FUNCTION, Modifiers.EMPTY,
enclosingElement);
ResolverTask.processAsyncMarker(compiler, function, registry);
- function.functionSignatureCache = SignatureResolver.analyze(
+ function.functionSignature = SignatureResolver.analyze(
compiler,
node.parameters,
node.returnType,
@@ -773,7 +768,7 @@
seenNamedArguments[source] = namedArgument;
}
} else if (!seenNamedArguments.isEmpty) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
argument, MessageKind.INVALID_ARGUMENT_AFTER_NAMED);
isValidAsConstant = false;
}
@@ -1195,7 +1190,7 @@
Node typeNode = node.arguments.head;
DartType type = resolveTypeAnnotation(typeNode);
- registry.registerAsCheck(type);
+ registry.registerAsCast(type);
registry.registerSendStructure(node, new AsStructure(type));
return const NoneResult();
}
@@ -1259,7 +1254,7 @@
knownExpressionType == coreTypes.doubleType;
break;
case UnaryOperatorKind.NOT:
- compiler.internalError(node,
+ reporter.internalError(node,
"Unexpected user definable unary operator: $operator");
}
if (isValidConstant) {
@@ -1477,7 +1472,7 @@
case BinaryOperatorKind.LOGICAL_AND:
case BinaryOperatorKind.LOGICAL_OR:
case BinaryOperatorKind.IF_NULL:
- compiler.internalError(
+ reporter.internalError(
node, "Unexpected binary operator '${operator}'.");
break;
}
@@ -1528,7 +1523,7 @@
case BinaryOperatorKind.LOGICAL_AND:
case BinaryOperatorKind.LOGICAL_OR:
case BinaryOperatorKind.IF_NULL:
- compiler.internalError(
+ reporter.internalError(
node, "Unexpected binary operator '${operator}'.");
break;
}
@@ -1593,7 +1588,7 @@
return const NoneResult();
} else {
// TODO(johnniwinther): Handle get of `this` when it is a [Send] node.
- compiler.internalError(
+ reporter.internalError(
node, "Unexpected node '$node'.");
}
return const NoneResult();
@@ -1620,7 +1615,7 @@
switch (semantics.kind) {
case AccessKind.SUPER_METHOD:
MethodElementX superMethod = semantics.element;
- superMethod.computeSignature(compiler);
+ superMethod.computeType(resolution);
if (!callStructure.signatureApplies(
superMethod.functionSignature)) {
registry.registerThrowNoSuchMethod();
@@ -1648,7 +1643,7 @@
// 'super' is not allowed.
break;
default:
- compiler.internalError(
+ reporter.internalError(
node, "Unexpected super property access $semantics.");
break;
}
@@ -1676,7 +1671,7 @@
// 'super' is not allowed.
break;
default:
- compiler.internalError(
+ reporter.internalError(
node, "Unexpected super property access $semantics.");
break;
}
@@ -1878,7 +1873,7 @@
ResolutionResult handleStaticMemberAccess(
Send node, Name memberName, ClassElement receiverClass) {
String name = memberName.text;
- receiverClass.ensureResolved(compiler);
+ receiverClass.ensureResolved(resolution);
if (node.isOperator) {
// When the resolved receiver is a class, we can have two cases:
// 1) a static send: C.foo, or
@@ -1912,7 +1907,7 @@
ResolutionResult handleStaticMemberUpdate(
Send node, Name memberName, ClassElement receiverClass) {
String name = memberName.text;
- receiverClass.ensureResolved(compiler);
+ receiverClass.ensureResolved(resolution);
MembersCreator.computeClassMembersByName(
compiler, receiverClass.declaration, name);
Element member = receiverClass.lookupLocalMember(name);
@@ -1957,7 +1952,6 @@
} else {
semantics = new StaticAccess.typeParameterTypeLiteral(element);
}
- registry.registerTypeVariableExpression(element);
registry.useElement(node, element);
registry.registerTypeLiteral(node, element.type);
@@ -2010,14 +2004,10 @@
MessageKind.ASSIGNING_TYPE, const {});
}
- if (node.isComplex) {
- // We read the type variable before trying write to it.
- registry.registerTypeVariableExpression(element);
- }
-
// TODO(23998): Remove this when all information goes through
// the [SendStructure].
registry.useElement(node, error);
+ // TODO(johnniwinther): Register only on read?
registry.registerTypeLiteral(node, element.type);
registry.registerThrowNoSuchMethod();
semantics = new StaticAccess.typeParameterTypeLiteral(element);
@@ -2058,7 +2048,7 @@
} else {
analyzeConstantDeferred(node, enforceConst: false);
- // TODO(johnniwinther): Avoid the need for a [Selector] here.
+ registry.setConstant(node, semantics.constant);
registry.registerSendStructure(node, new GetStructure(semantics));
return new ConstantResult(node, semantics.constant);
}
@@ -2109,7 +2099,7 @@
Send node,
Name name,
TypedefElement typdef) {
- typdef.ensureResolved(compiler);
+ typdef.ensureResolved(resolution);
DartType type = typdef.rawType;
ConstantExpression constant = new TypeConstantExpression(type);
AccessSemantics semantics = new ConstantAccess.typedefTypeLiteral(constant);
@@ -2122,7 +2112,7 @@
SendSet node,
Name name,
TypedefElement typdef) {
- typdef.ensureResolved(compiler);
+ typdef.ensureResolved(resolution);
DartType type = typdef.rawType;
ConstantExpression constant = new TypeConstantExpression(type);
AccessSemantics semantics = new ConstantAccess.typedefTypeLiteral(constant);
@@ -2159,7 +2149,7 @@
Send node,
Name name,
ClassElement cls) {
- cls.ensureResolved(compiler);
+ cls.ensureResolved(resolution);
DartType type = cls.rawType;
ConstantExpression constant = new TypeConstantExpression(type);
AccessSemantics semantics = new ConstantAccess.classTypeLiteral(constant);
@@ -2172,7 +2162,7 @@
SendSet node,
Name name,
ClassElement cls) {
- cls.ensureResolved(compiler);
+ cls.ensureResolved(resolution);
DartType type = cls.rawType;
ConstantExpression constant = new TypeConstantExpression(type);
AccessSemantics semantics = new ConstantAccess.classTypeLiteral(constant);
@@ -2186,7 +2176,7 @@
Send node,
Name name,
ClassElement cls) {
- cls.ensureResolved(compiler);
+ cls.ensureResolved(resolution);
if (sendIsMemberAccess) {
registry.useElement(node, cls);
return new PrefixResult(null, cls);
@@ -2524,7 +2514,7 @@
name.text,
element.messageKind,
element.messageArguments,
- infos: element.computeInfos(enclosingElement, compiler));
+ infos: element.computeInfos(enclosingElement, reporter));
registry.registerThrowNoSuchMethod();
// TODO(johnniwinther): Support ambiguous access as an [AccessSemantics].
@@ -2543,7 +2533,7 @@
name.text,
element.messageKind,
element.messageArguments,
- infos: element.computeInfos(enclosingElement, compiler));
+ infos: element.computeInfos(enclosingElement, reporter));
registry.registerThrowNoSuchMethod();
// TODO(johnniwinther): Support ambiguous access as an [AccessSemantics].
@@ -2576,7 +2566,7 @@
switch (semantics.kind) {
case AccessKind.LOCAL_FUNCTION:
LocalFunctionElementX function = semantics.element;
- function.computeSignature(compiler);
+ function.computeType(resolution);
if (!callStructure.signatureApplies(function.functionSignature)) {
registry.registerThrowNoSuchMethod();
registry.registerDynamicInvocation(
@@ -2593,7 +2583,7 @@
new UniverseSelector(selector, null));
break;
default:
- compiler.internalError(node,
+ reporter.internalError(node,
"Unexpected local access $semantics.");
break;
}
@@ -2639,7 +2629,7 @@
}
break;
default:
- compiler.internalError(node,
+ reporter.internalError(node,
"Unexpected local access $semantics.");
break;
}
@@ -2724,12 +2714,12 @@
}
// TODO(johnniwinther): Needed to provoke a parsing and with it discovery
// of parse errors to make [element] erroneous. Fix this!
- member.computeType(compiler);
+ member.computeType(resolution);
if (member == compiler.mirrorSystemGetNameFunction &&
!compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) {
- compiler.reportHintMessage(
+ reporter.reportHintMessage(
node.selector, MessageKind.STATIC_FUNCTION_BLOAT,
{'class': compiler.mirrorSystemClass.name,
'name': compiler.mirrorSystemGetNameFunction.name});
@@ -2749,7 +2739,7 @@
case AccessKind.STATIC_METHOD:
case AccessKind.TOPLEVEL_METHOD:
MethodElement method = semantics.element;
- method.computeType(compiler);
+ method.computeType(resolution);
if (!callStructure.signatureApplies(method.functionSignature)) {
registry.registerThrowNoSuchMethod();
registry.registerDynamicInvocation(
@@ -2757,7 +2747,7 @@
isIncompatibleInvoke = true;
} else {
registry.registerStaticUse(semantics.element);
- handleForeignCall(node, semantics.element, selector);
+ handleForeignCall(node, semantics.element, callStructure);
if (method == compiler.identicalFunction &&
argumentsResult.isValidAsConstant) {
result = new ConstantResult(node,
@@ -2787,7 +2777,7 @@
MessageKind.CANNOT_RESOLVE_GETTER, const {});
break;
default:
- compiler.internalError(node,
+ reporter.internalError(node,
"Unexpected statically resolved access $semantics.");
break;
}
@@ -2822,7 +2812,7 @@
MessageKind.CANNOT_RESOLVE_GETTER, const {});
break;
default:
- compiler.internalError(node,
+ reporter.internalError(node,
"Unexpected statically resolved access $semantics.");
break;
}
@@ -2907,7 +2897,7 @@
MemberElement member = element;
// TODO(johnniwinther): Needed to provoke a parsing and with it discovery
// of parse errors to make [element] erroneous. Fix this!
- member.computeType(compiler);
+ member.computeType(resolution);
registry.registerStaticUse(member);
if (member.isErroneous) {
// [member] has parse errors.
@@ -2985,7 +2975,7 @@
} else if (element.isStatic || element.isTopLevel) {
return handleStaticOrTopLevelAccess(node, name, element);
}
- return compiler.internalError(node, "Unexpected resolved send: $element");
+ return reporter.internalError(node, "Unexpected resolved send: $element");
}
/// Handle update to resolved [element].
@@ -3023,7 +3013,7 @@
} else if (element.isStatic || element.isTopLevel) {
return handleStaticOrTopLevelUpdate(node, name, element);
}
- return compiler.internalError(node, "Unexpected resolved send: $element");
+ return reporter.internalError(node, "Unexpected resolved send: $element");
}
/// Handle an unqualified [Send], that is where the `node.receiver` is null,
@@ -3041,7 +3031,7 @@
}
// `name` or `name()`
Name name = new Name(text, enclosingElement.library);
- Element element = lookupInScope(compiler, node, scope, text);
+ Element element = lookupInScope(reporter, node, scope, text);
if (element == null) {
if (text == 'dynamic') {
// `dynamic` or `dynamic()` where 'dynamic' is not declared in the
@@ -3066,7 +3056,7 @@
Identifier selector = node.selector.asIdentifier();
String text = selector.source;
Name name = new Name(text, enclosingElement.library);
- Element element = lookupInScope(compiler, node, scope, text);
+ Element element = lookupInScope(reporter, node, scope, text);
if (element == null) {
if (text == 'dynamic') {
// `dynamic = b`, `dynamic++`, or `dynamic += b` where 'dynamic' is not
@@ -3110,34 +3100,22 @@
}
// TODO(johnniwinther): Move this to the backend resolution callbacks.
- void handleForeignCall(Send node, Element target, Selector selector) {
+ void handleForeignCall(Send node,
+ Element target,
+ CallStructure callStructure) {
if (target != null && compiler.backend.isForeign(target)) {
- if (selector.name == 'JS') {
- registry.registerJsCall(node, this);
- } else if (selector.name == 'JS_EMBEDDED_GLOBAL') {
- registry.registerJsEmbeddedGlobalCall(node, this);
- } else if (selector.name == 'JS_BUILTIN') {
- registry.registerJsBuiltinCall(node, this);
- } else if (selector.name == 'JS_INTERCEPTOR_CONSTANT') {
- if (!node.argumentsNode.isEmpty) {
- Node argument = node.argumentsNode.nodes.head;
- if (argumentsToJsInterceptorConstant == null) {
- argumentsToJsInterceptorConstant = new Set<Node>();
- }
- argumentsToJsInterceptorConstant.add(argument);
- }
- }
+ registry.registerForeignCall(node, target, callStructure, this);
}
}
/// Callback for native enqueuer to parse a type. Returns [:null:] on error.
DartType resolveTypeFromString(Node node, String typeName) {
- Element element = lookupInScope(compiler, node, scope, typeName);
+ Element element = lookupInScope(reporter, node, scope, typeName);
if (element == null) return null;
if (element is! ClassElement) return null;
ClassElement cls = element;
- cls.ensureResolved(compiler);
- return cls.computeType(compiler);
+ cls.ensureResolved(resolution);
+ return cls.computeType(resolution);
}
/// Handle index operations like `a[b] = c`, `a[b] += c`, and `a[b]++`.
@@ -3354,7 +3332,7 @@
registry.registerStaticInvocation(semantics.setter);
switch (semantics.kind) {
case AccessKind.SUPER_FINAL_FIELD:
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
node,
MessageKind.ASSIGNING_FINAL_FIELD_IN_SUPER,
{'name': name,
@@ -3365,7 +3343,7 @@
registry.registerSuperNoSuchMethod();
break;
case AccessKind.SUPER_METHOD:
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
node, MessageKind.ASSIGNING_METHOD_IN_SUPER,
{'name': name,
'superclassName': semantics.setter.enclosingClass.name});
@@ -3567,7 +3545,7 @@
String name = node.slowNameString;
registry.registerConstSymbol(name);
if (!validateSymbol(node, name, reportError: false)) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node,
MessageKind.UNSUPPORTED_LITERAL_SYMBOL,
{'value': name});
@@ -3600,7 +3578,7 @@
ResolutionResult visitRethrow(Rethrow node) {
if (!inCatchBlock) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.THROW_WITHOUT_EXPRESSION);
}
return const NoneResult();
@@ -3613,11 +3591,11 @@
// It is a compile-time error if a return statement of the form
// `return e;` appears in a generative constructor. (Dart Language
// Specification 13.12.)
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
expression,
MessageKind.CANNOT_RETURN_FROM_CONSTRUCTOR);
} else if (!node.isArrowBody && currentAsyncMarker.isYielding) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node,
MessageKind.RETURN_IN_GENERATOR,
{'modifier': currentAsyncMarker});
@@ -3628,8 +3606,8 @@
}
ResolutionResult visitYield(Yield node) {
- compiler.streamClass.ensureResolved(compiler);
- compiler.iterableClass.ensureResolved(compiler);
+ compiler.streamClass.ensureResolved(resolution);
+ compiler.iterableClass.ensureResolved(resolution);
visit(node.expression);
return const NoneResult();
}
@@ -3637,9 +3615,9 @@
ResolutionResult visitRedirectingFactoryBody(RedirectingFactoryBody node) {
final isSymbolConstructor = enclosingElement == compiler.symbolConstructor;
if (!enclosingElement.isFactoryConstructor) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.FACTORY_REDIRECTION_IN_NON_FACTORY);
- compiler.reportHintMessage(
+ reporter.reportHintMessage(
enclosingElement, MessageKind.MISSING_FACTORY_KEYWORD);
}
ConstructorElementX constructor = enclosingElement;
@@ -3663,12 +3641,12 @@
} else {
if (isConstConstructor &&
!redirectionTarget.isConst) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.CONSTRUCTOR_IS_NOT_CONST);
isValidAsConstant = false;
}
if (redirectionTarget == constructor) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.CYCLIC_REDIRECTING_FACTORY);
// TODO(johnniwinther): Create constant constructor for this case and
// let evaluation detect the cyclicity.
@@ -3680,12 +3658,12 @@
// redirecting constructor.
ClassElement targetClass = redirectionTarget.enclosingClass;
InterfaceType type = registry.getType(node);
- FunctionType targetType = redirectionTarget.computeType(compiler)
+ FunctionType targetType = redirectionTarget.computeType(resolution)
.subst(type.typeArguments, targetClass.typeVariables);
- FunctionType constructorType = constructor.computeType(compiler);
+ FunctionType constructorType = constructor.computeType(resolution);
bool isSubtype = compiler.types.isSubtype(targetType, constructorType);
if (!isSubtype) {
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
node,
MessageKind.NOT_ASSIGNABLE,
{'fromType': targetType, 'toType': constructorType});
@@ -3693,9 +3671,9 @@
isValidAsConstant = false;
}
- redirectionTarget.computeType(compiler);
+ redirectionTarget.computeType(resolution);
FunctionSignature targetSignature = redirectionTarget.functionSignature;
- constructor.computeType(compiler);
+ constructor.computeType(resolution);
FunctionSignature constructorSignature = constructor.functionSignature;
if (!targetSignature.isCompatibleWith(constructorSignature)) {
assert(!isSubtype);
@@ -3750,7 +3728,7 @@
}
ResolutionResult visitAwait(Await node) {
- compiler.futureClass.ensureResolved(compiler);
+ compiler.futureClass.ensureResolved(resolution);
visit(node.expression);
return const NoneResult();
}
@@ -3778,7 +3756,7 @@
}
}
assert(modifierNode != null);
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
modifierNode, MessageKind.EXTRANEOUS_MODIFIER,
{'modifier': modifier});
}
@@ -3845,7 +3823,7 @@
if (Elements.isUnresolved(constructor)) {
return new ResolutionResult.forElement(constructor);
}
- constructor.computeType(compiler);
+ constructor.computeType(resolution);
if (!callSelector.applies(constructor, compiler.world)) {
registry.registerThrowNoSuchMethod();
}
@@ -3855,7 +3833,7 @@
registry.registerStaticUse(constructor.declaration);
ClassElement cls = constructor.enclosingClass;
if (cls.isEnumClass && currentClass != cls) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node,
MessageKind.CANNOT_INSTANTIATE_ENUM,
{'enumName': cls.name});
@@ -3864,7 +3842,7 @@
InterfaceType type = registry.getType(node);
if (node.isConst && type.containsTypeVariables) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node.send.selector,
MessageKind.TYPE_VARIABLE_IN_CONSTANT);
isValidAsConstant = false;
@@ -3885,7 +3863,7 @@
ConstantValue name = compiler.constants.getConstantValue(constant);
if (!name.isString) {
DartType type = name.getType(coreTypes);
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
argumentNode,
MessageKind.STRING_EXPECTED,
{'type': type});
@@ -3899,7 +3877,7 @@
} else {
if (!compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(
enclosingElement)) {
- compiler.reportHintMessage(
+ reporter.reportHintMessage(
node.newToken, MessageKind.NON_CONST_BLOAT,
{'name': compiler.symbolClass.name});
}
@@ -3953,7 +3931,7 @@
if (cls == compiler.stringClass) continue;
Element equals = cls.lookupMember('==');
if (equals.enclosingClass != compiler.objectClass) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
spannable,
MessageKind.CONST_MAP_KEY_OVERRIDES_EQUALS,
{'type': keyType});
@@ -3975,27 +3953,6 @@
if (value.isMap) {
checkConstMapKeysDontOverrideEquals(node, value);
}
-
- // The type constant that is an argument to JS_INTERCEPTOR_CONSTANT names
- // a class that will be instantiated outside the program by attaching a
- // native class dispatch record referencing the interceptor.
- if (argumentsToJsInterceptorConstant != null &&
- argumentsToJsInterceptorConstant.contains(node)) {
- if (value.isType) {
- TypeConstantValue typeConstant = value;
- if (typeConstant.representedType is InterfaceType) {
- registry.registerInstantiatedType(typeConstant.representedType);
- } else {
- compiler.reportErrorMessage(
- node,
- MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
- }
- } else {
- compiler.reportErrorMessage(
- node,
- MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
- }
- }
}
void analyzeConstantDeferred(Node node, {bool enforceConst: true}) {
@@ -4008,14 +3965,14 @@
if (name.isEmpty) return true;
if (name.startsWith('_')) {
if (reportError) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.PRIVATE_IDENTIFIER, {'value': name});
}
return false;
}
if (!symbolValidationPattern.hasMatch(name)) {
if (reportError) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.INVALID_SYMBOL, {'value': name});
}
return false;
@@ -4046,7 +4003,7 @@
this, node, malformedIsError: malformedIsError,
deferredIsMalformed: deferredIsMalformed);
if (inCheckContext) {
- registry.registerIsCheck(type);
+ registry.registerCheckedModeCheck(type);
registry.registerRequiredType(type, enclosingElement);
}
return type;
@@ -4062,13 +4019,13 @@
Link<Node> nodes = arguments.nodes;
if (nodes.isEmpty) {
// The syntax [: <>[] :] is not allowed.
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
arguments, MessageKind.MISSING_TYPE_ARGUMENT);
isValidAsConstant = false;
} else {
typeArgument = resolveTypeAnnotation(nodes.head);
for (nodes = nodes.tail; !nodes.isEmpty; nodes = nodes.tail) {
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
nodes.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT);
resolveTypeAnnotation(nodes.head);
}
@@ -4077,7 +4034,7 @@
DartType listType;
if (typeArgument != null) {
if (node.isConst && typeArgument.containsTypeVariables) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
arguments.nodes.head,
MessageKind.TYPE_VARIABLE_IN_CONSTANT);
isValidAsConstant = false;
@@ -4086,8 +4043,11 @@
} else {
listType = coreTypes.listType();
}
- registry.setType(node, listType);
- registry.registerInstantiatedType(listType);
+ registry.registerLiteralList(
+ node,
+ listType,
+ isConstant: node.isConst,
+ isEmpty: node.elements.isEmpty);
registry.registerRequiredType(listType, enclosingElement);
if (node.isConst) {
List<ConstantExpression> constantExpressions = <ConstantExpression>[];
@@ -4172,7 +4132,7 @@
if (node.target == null) {
target = statementScope.currentBreakTarget();
if (target == null) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.NO_BREAK_TARGET);
return const NoneResult();
}
@@ -4181,13 +4141,13 @@
String labelName = node.target.source;
LabelDefinition label = statementScope.lookupLabel(labelName);
if (label == null) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node.target, MessageKind.UNBOUND_LABEL, {'labelName': labelName});
return const NoneResult();
}
target = label.target;
if (!target.statement.isValidBreakTarget()) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node.target, MessageKind.INVALID_BREAK);
return const NoneResult();
}
@@ -4203,7 +4163,7 @@
if (node.target == null) {
target = statementScope.currentContinueTarget();
if (target == null) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.NO_CONTINUE_TARGET);
return const NoneResult();
}
@@ -4212,13 +4172,13 @@
String labelName = node.target.source;
LabelDefinition label = statementScope.lookupLabel(labelName);
if (label == null) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node.target, MessageKind.UNBOUND_LABEL, {'labelName': labelName});
return const NoneResult();
}
target = label.target;
if (!target.statement.isValidContinueTarget()) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node.target, MessageKind.INVALID_CONTINUE);
}
label.setContinueTarget();
@@ -4289,26 +4249,26 @@
loopVariable = registry.getDefinition(send);
Identifier identifier = send.selector.asIdentifier();
if (identifier == null) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
send.selector, MessageKind.INVALID_FOR_IN);
} else {
loopVariableSelector = new Selector.setter(
new Name(identifier.source, library));
}
if (send.receiver != null) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
send.receiver, MessageKind.INVALID_FOR_IN);
}
} else if (variableDefinitions != null) {
Link<Node> nodes = variableDefinitions.definitions.nodes;
if (!nodes.tail.isEmpty) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
nodes.tail.head, MessageKind.INVALID_FOR_IN);
}
Node first = nodes.head;
Identifier identifier = first.asIdentifier();
if (identifier == null) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
first, MessageKind.INVALID_FOR_IN);
} else {
loopVariableSelector = new Selector.setter(
@@ -4316,7 +4276,7 @@
loopVariable = registry.getDefinition(identifier);
}
} else {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
declaration, MessageKind.INVALID_FOR_IN);
}
if (loopVariableSelector != null) {
@@ -4353,7 +4313,7 @@
if (element.isTarget) {
registry.defineLabel(element.label, element);
} else {
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
element.label,
MessageKind.UNUSED_LABEL,
{'labelName': labelName});
@@ -4376,19 +4336,19 @@
Link<Node> nodes = arguments.nodes;
if (nodes.isEmpty) {
// The syntax [: <>{} :] is not allowed.
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
arguments, MessageKind.MISSING_TYPE_ARGUMENT);
isValidAsConstant = false;
} else {
keyTypeArgument = resolveTypeAnnotation(nodes.head);
nodes = nodes.tail;
if (nodes.isEmpty) {
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
arguments, MessageKind.MISSING_TYPE_ARGUMENT);
} else {
valueTypeArgument = resolveTypeAnnotation(nodes.head);
for (nodes = nodes.tail; !nodes.isEmpty; nodes = nodes.tail) {
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
nodes.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT);
resolveTypeAnnotation(nodes.head);
}
@@ -4402,12 +4362,16 @@
mapType = coreTypes.mapType();
}
if (node.isConst && mapType.containsTypeVariables) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
arguments,
MessageKind.TYPE_VARIABLE_IN_CONSTANT);
isValidAsConstant = false;
}
- registry.registerMapLiteral(node, mapType, node.isConst);
+ registry.registerMapLiteral(
+ node,
+ mapType,
+ isConstant: node.isConst,
+ isEmpty: node.entries.isEmpty);
registry.registerRequiredType(mapType, enclosingElement);
if (node.isConst) {
@@ -4500,16 +4464,16 @@
// We only report the bad type on the first class element. All others
// get a "type differs" error.
if (caseType.element == compiler.doubleClass) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node,
MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS,
{'type': "double"});
} else if (caseType.element == compiler.functionClass) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.SWITCH_CASE_FORBIDDEN,
{'type': "Function"});
} else if (value.isObject && overridesEquals(caseType)) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
firstCase.expression,
MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS,
{'type': caseType});
@@ -4517,16 +4481,16 @@
} else {
if (caseType != firstCaseType) {
if (error == null) {
- error = compiler.createMessage(
+ error = reporter.createMessage(
node,
MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL,
{'type': firstCaseType});
- infos.add(compiler.createMessage(
+ infos.add(reporter.createMessage(
firstCase.expression,
MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE,
{'type': firstCaseType}));
}
- infos.add(compiler.createMessage(
+ infos.add(reporter.createMessage(
caseMatch.expression,
MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE,
{'type': caseType}));
@@ -4535,7 +4499,7 @@
}
}
if (error != null) {
- compiler.reportError(error, infos);
+ reporter.reportError(error, infos);
}
}
@@ -4559,13 +4523,13 @@
LabelDefinition existingElement = continueLabels[labelName];
if (existingElement != null) {
// It's an error if the same label occurs twice in the same switch.
- compiler.reportError(
- compiler.createMessage(
+ reporter.reportError(
+ reporter.createMessage(
label,
MessageKind.DUPLICATE_LABEL,
{'labelName': labelName}),
<DiagnosticMessage>[
- compiler.createMessage(
+ reporter.createMessage(
existingElement.label,
MessageKind.EXISTING_LABEL,
{'labelName': labelName}),
@@ -4574,13 +4538,13 @@
// It's only a warning if it shadows another label.
existingElement = statementScope.lookupLabel(labelName);
if (existingElement != null) {
- compiler.reportWarning(
- compiler.createMessage(
+ reporter.reportWarning(
+ reporter.createMessage(
label,
MessageKind.DUPLICATE_LABEL,
{'labelName': labelName}),
<DiagnosticMessage>[
- compiler.createMessage(
+ reporter.createMessage(
existingElement.label,
MessageKind.EXISTING_LABEL,
{'labelName': labelName}),
@@ -4596,7 +4560,7 @@
cases = cases.tail;
// Test that only the last case, if any, is a default case.
if (switchCase.defaultKeyword != null && !cases.isEmpty) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
switchCase, MessageKind.INVALID_CASE_DEFAULT);
}
}
@@ -4642,7 +4606,7 @@
visit(node.tryBlock);
if (node.catchBlocks.isEmpty && node.finallyBlock == null) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node.getEndToken().next, MessageKind.NO_CATCH_NOR_FINALLY);
}
visit(node.catchBlocks);
@@ -4659,7 +4623,7 @@
if (node.formals != null) {
Link<Node> formalsToProcess = node.formals.nodes;
if (formalsToProcess.isEmpty) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.EMPTY_CATCH_DECLARATION);
} else {
exceptionDefinition = formalsToProcess.head.asVariableDefinitions();
@@ -4669,7 +4633,7 @@
formalsToProcess = formalsToProcess.tail;
if (!formalsToProcess.isEmpty) {
for (Node extra in formalsToProcess) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
extra, MessageKind.EXTRA_CATCH_DECLARATION);
}
}
@@ -4686,17 +4650,17 @@
// sequence of optional parameters.
NodeList nodeList = link.head.asNodeList();
if (nodeList != null) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
nodeList, MessageKind.OPTIONAL_PARAMETER_IN_CATCH);
} else {
VariableDefinitions declaration = link.head;
for (Node modifier in declaration.modifiers.nodes) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
modifier, MessageKind.PARAMETER_WITH_MODIFIER_IN_CATCH);
}
TypeAnnotation type = declaration.type;
if (type != null) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
type, MessageKind.PARAMETER_WITH_TYPE_IN_CATCH);
}
}
@@ -4730,7 +4694,7 @@
}
/// Looks up [name] in [scope] and unwraps the result.
-Element lookupInScope(Compiler compiler, Node node,
+Element lookupInScope(DiagnosticReporter reporter, Node node,
Scope scope, String name) {
- return Elements.unwrap(scope.lookup(name), compiler, node);
+ return Elements.unwrap(scope.lookup(name), reporter, node);
}
diff --git a/pkg/compiler/lib/src/resolution/registry.dart b/pkg/compiler/lib/src/resolution/registry.dart
index de12ef0..51aa37c 100644
--- a/pkg/compiler/lib/src/resolution/registry.dart
+++ b/pkg/compiler/lib/src/resolution/registry.dart
@@ -5,7 +5,13 @@
library dart2js.resolution.registry;
import '../common/backend_api.dart' show
- Backend;
+ Backend,
+ ForeignResolver;
+import '../common/resolution.dart' show
+ Feature,
+ ListLiteralUse,
+ MapLiteralUse,
+ ResolutionWorldImpact;
import '../common/registry.dart' show
Registry;
import '../compiler.dart' show
@@ -15,12 +21,14 @@
import '../diagnostics/invariant.dart' show
invariant;
import '../enqueue.dart' show
- ResolutionEnqueuer,
- WorldImpact;
+ ResolutionEnqueuer;
import '../elements/elements.dart';
+import '../helpers/helpers.dart';
import '../tree/tree.dart';
import '../util/util.dart' show
Setlet;
+import '../universe/call_structure.dart' show
+ CallStructure;
import '../universe/selector.dart' show
Selector;
import '../universe/universe.dart' show
@@ -34,11 +42,7 @@
import 'tree_elements.dart' show
TreeElementMapping;
-/// [ResolutionRegistry] collects all resolution information. It stores node
-/// related information in a [TreeElements] mapping and registers calls with
-/// [Backend], [World] and [Enqueuer].
-// TODO(johnniwinther): Split this into an interface and implementation class.
-
+// TODO(johnniwinther): Remove this.
class EagerRegistry implements Registry {
final Compiler compiler;
final TreeElementMapping mapping;
@@ -97,19 +101,35 @@
String toString() => 'EagerRegistry for ${mapping.analyzedElement}';
}
-class ResolutionWorldImpact implements WorldImpact {
+class _ResolutionWorldImpact implements ResolutionWorldImpact {
final Registry registry;
+ // TODO(johnniwinther): Do we benefit from lazy initialization of the
+ // [Setlet]s?
Setlet<UniverseSelector> _dynamicInvocations;
Setlet<UniverseSelector> _dynamicGetters;
Setlet<UniverseSelector> _dynamicSetters;
Setlet<InterfaceType> _instantiatedTypes;
Setlet<Element> _staticUses;
- Setlet<DartType> _checkedTypes;
+ Setlet<DartType> _isChecks;
+ Setlet<DartType> _asCasts;
+ Setlet<DartType> _checkedModeChecks;
Setlet<MethodElement> _closurizedFunctions;
+ Setlet<LocalFunctionElement> _closures;
+ Setlet<Feature> _features;
+ // TODO(johnniwinther): This seems to be a union of other sets.
+ Setlet<DartType> _requiredTypes;
+ Setlet<MapLiteralUse> _mapLiterals;
+ Setlet<ListLiteralUse> _listLiterals;
+ Setlet<DartType> _typeLiterals;
+ Setlet<String> _constSymbolNames;
- ResolutionWorldImpact(Compiler compiler, TreeElementMapping mapping)
+ _ResolutionWorldImpact(Compiler compiler, TreeElementMapping mapping)
: this.registry = new EagerRegistry(compiler, mapping);
+ void registerDependency(Element element) {
+ registry.registerDependency(element);
+ }
+
void registerDynamicGetter(UniverseSelector selector) {
if (_dynamicGetters == null) {
_dynamicGetters = new Setlet<UniverseSelector>();
@@ -150,10 +170,6 @@
}
void registerInstantiatedType(InterfaceType type) {
- // TODO(johnniwinther): Enable this when registration doesn't require a
- // [Registry].
- throw new UnsupportedError(
- 'Lazy registration of instantiated not supported.');
if (_instantiatedTypes == null) {
_instantiatedTypes = new Setlet<InterfaceType>();
}
@@ -166,6 +182,58 @@
? _instantiatedTypes : const <InterfaceType>[];
}
+ void registerTypeLiteral(DartType type) {
+ if (_typeLiterals == null) {
+ _typeLiterals = new Setlet<DartType>();
+ }
+ _typeLiterals.add(type);
+ }
+
+ @override
+ Iterable<DartType> get typeLiterals {
+ return _typeLiterals != null
+ ? _typeLiterals : const <DartType>[];
+ }
+
+ void registerRequiredType(DartType type) {
+ if (_requiredTypes == null) {
+ _requiredTypes = new Setlet<DartType>();
+ }
+ _requiredTypes.add(type);
+ }
+
+ @override
+ Iterable<DartType> get requiredTypes {
+ return _requiredTypes != null
+ ? _requiredTypes : const <DartType>[];
+ }
+
+ void registerMapLiteral(MapLiteralUse mapLiteralUse) {
+ if (_mapLiterals == null) {
+ _mapLiterals = new Setlet<MapLiteralUse>();
+ }
+ _mapLiterals.add(mapLiteralUse);
+ }
+
+ @override
+ Iterable<MapLiteralUse> get mapLiterals {
+ return _mapLiterals != null
+ ? _mapLiterals : const <MapLiteralUse>[];
+ }
+
+ void registerListLiteral(ListLiteralUse listLiteralUse) {
+ if (_listLiterals == null) {
+ _listLiterals = new Setlet<ListLiteralUse>();
+ }
+ _listLiterals.add(listLiteralUse);
+ }
+
+ @override
+ Iterable<ListLiteralUse> get listLiterals {
+ return _listLiterals != null
+ ? _listLiterals : const <ListLiteralUse>[];
+ }
+
void registerStaticUse(Element element) {
if (_staticUses == null) {
_staticUses = new Setlet<Element>();
@@ -178,17 +246,43 @@
return _staticUses != null ? _staticUses : const <Element>[];
}
- void registerCheckedType(DartType type) {
- if (_checkedTypes == null) {
- _checkedTypes = new Setlet<DartType>();
+ void registerIsCheck(DartType type) {
+ if (_isChecks == null) {
+ _isChecks = new Setlet<DartType>();
}
- _checkedTypes.add(type);
+ _isChecks.add(type);
}
@override
- Iterable<DartType> get checkedTypes {
- return _checkedTypes != null
- ? _checkedTypes : const <DartType>[];
+ Iterable<DartType> get isChecks {
+ return _isChecks != null
+ ? _isChecks : const <DartType>[];
+ }
+
+ void registerAsCast(DartType type) {
+ if (_asCasts == null) {
+ _asCasts = new Setlet<DartType>();
+ }
+ _asCasts.add(type);
+ }
+
+ @override
+ Iterable<DartType> get asCasts {
+ return _asCasts != null
+ ? _asCasts : const <DartType>[];
+ }
+
+ void registerCheckedModeCheckedType(DartType type) {
+ if (_checkedModeChecks == null) {
+ _checkedModeChecks = new Setlet<DartType>();
+ }
+ _checkedModeChecks.add(type);
+ }
+
+ @override
+ Iterable<DartType> get checkedModeChecks {
+ return _checkedModeChecks != null
+ ? _checkedModeChecks : const <DartType>[];
}
void registerClosurizedFunction(MethodElement element) {
@@ -203,17 +297,61 @@
return _closurizedFunctions != null
? _closurizedFunctions : const <MethodElement>[];
}
+
+ void registerClosure(LocalFunctionElement element) {
+ if (_closures == null) {
+ _closures = new Setlet<LocalFunctionElement>();
+ }
+ _closures.add(element);
+ }
+
+ @override
+ Iterable<LocalFunctionElement> get closures {
+ return _closures != null
+ ? _closures : const <LocalFunctionElement>[];
+ }
+
+ void registerConstSymbolName(String name) {
+ if (_constSymbolNames == null) {
+ _constSymbolNames = new Setlet<String>();
+ }
+ _constSymbolNames.add(name);
+ }
+
+ @override
+ Iterable<String> get constSymbolNames {
+ return _constSymbolNames != null
+ ? _constSymbolNames : const <String>[];
+ }
+
+ void registerFeature(Feature feature) {
+ if (_features == null) {
+ _features = new Setlet<Feature>();
+ }
+ _features.add(feature);
+ }
+
+ @override
+ Iterable<Feature> get features {
+ return _features != null ? _features : const <Feature>[];
+ }
+
+ String toString() => '$registry';
}
+/// [ResolutionRegistry] collects all resolution information. It stores node
+/// related information in a [TreeElements] mapping and registers calls with
+/// [Backend], [World] and [Enqueuer].
+// TODO(johnniwinther): Split this into an interface and implementation class.
class ResolutionRegistry implements Registry {
final Compiler compiler;
final TreeElementMapping mapping;
- final ResolutionWorldImpact worldImpact;
+ final _ResolutionWorldImpact worldImpact;
ResolutionRegistry(Compiler compiler, TreeElementMapping mapping)
: this.compiler = compiler,
this.mapping = mapping,
- this.worldImpact = new ResolutionWorldImpact(compiler, mapping);
+ this.worldImpact = new _ResolutionWorldImpact(compiler, mapping);
bool get isForResolution => true;
@@ -398,59 +536,61 @@
}
void registerImplicitSuperCall(FunctionElement superConstructor) {
- universe.registerImplicitSuperCall(this, superConstructor);
+ registerDependency(superConstructor);
}
// TODO(johnniwinther): Remove this.
// Use [registerInstantiatedType] of `rawType` instead.
@deprecated
void registerInstantiatedClass(ClassElement element) {
- element.ensureResolved(compiler);
+ element.ensureResolved(compiler.resolution);
registerInstantiatedType(element.rawType);
}
void registerLazyField() {
- backend.resolutionCallbacks.onLazyField(this);
+ worldImpact.registerFeature(Feature.LAZY_FIELD);
}
- void registerMetadataConstant(MetadataAnnotation metadata,
- Element annotatedElement) {
- backend.registerMetadataConstant(metadata, annotatedElement, this);
+ void registerMetadataConstant(MetadataAnnotation metadata) {
+ backend.registerMetadataConstant(metadata, metadata.annotatedElement, this);
}
void registerThrowRuntimeError() {
- backend.resolutionCallbacks.onThrowRuntimeError(this);
+ worldImpact.registerFeature(Feature.THROW_RUNTIME_ERROR);
}
void registerCompileTimeError(ErroneousElement error) {
- backend.resolutionCallbacks.onCompileTimeError(this, error);
+ worldImpact.registerFeature(Feature.COMPILE_TIME_ERROR);
}
void registerTypeVariableBoundCheck() {
- backend.resolutionCallbacks.onTypeVariableBoundCheck(this);
+ worldImpact.registerFeature(Feature.TYPE_VARIABLE_BOUNDS_CHECK);
}
void registerThrowNoSuchMethod() {
- backend.resolutionCallbacks.onThrowNoSuchMethod(this);
+ worldImpact.registerFeature(Feature.THROW_NO_SUCH_METHOD);
}
- void registerIsCheck(DartType type) {
- worldImpact.registerCheckedType(type);
- backend.resolutionCallbacks.onIsCheck(type, this);
+ /// Register a checked mode check against [type].
+ void registerCheckedModeCheck(DartType type) {
+ worldImpact.registerCheckedModeCheckedType(type);
mapping.addRequiredType(type);
}
- void registerAsCheck(DartType type) {
- registerIsCheck(type);
- backend.resolutionCallbacks.onAsCheck(type, this);
+ /// Register an is-test or is-not-test of [type].
+ void registerIsCheck(DartType type) {
+ worldImpact.registerIsCheck(type);
+ mapping.addRequiredType(type);
+ }
+
+ /// Register an as-cast of [type].
+ void registerAsCast(DartType type) {
+ worldImpact.registerAsCast(type);
mapping.addRequiredType(type);
}
void registerClosure(LocalFunctionElement element) {
- if (element.computeType(compiler).containsTypeVariables) {
- backend.registerClosureWithFreeTypeVariables(element, world, this);
- }
- world.registerClosure(element);
+ worldImpact.registerClosure(element);
}
void registerSuperUse(Node node) {
@@ -462,40 +602,39 @@
}
void registerSuperNoSuchMethod() {
- backend.resolutionCallbacks.onSuperNoSuchMethod(this);
- }
-
- void registerTypeVariableExpression(TypeVariableElement element) {
- backend.resolutionCallbacks.onTypeVariableExpression(this, element);
+ worldImpact.registerFeature(Feature.SUPER_NO_SUCH_METHOD);
}
void registerTypeLiteral(Send node, DartType type) {
mapping.setType(node, type);
- backend.resolutionCallbacks.onTypeLiteral(type, this);
- backend.registerInstantiatedType(compiler.coreTypes.typeType, world, this);
+ worldImpact.registerTypeLiteral(type);
}
- void registerMapLiteral(Node node, DartType type, bool isConstant) {
+ void registerLiteralList(Node node,
+ InterfaceType type,
+ {bool isConstant,
+ bool isEmpty}) {
setType(node, type);
- backend.resolutionCallbacks.onMapLiteral(this, type, isConstant);
+ worldImpact.registerListLiteral(
+ new ListLiteralUse(type, isConstant: isConstant, isEmpty: isEmpty));
}
- // TODO(johnniwinther): Remove the [ResolverVisitor] dependency. Its only
- // needed to lookup types in the current scope.
- void registerJsCall(Node node, ResolverVisitor visitor) {
- world.registerJsCall(node, visitor);
+ void registerMapLiteral(Node node,
+ InterfaceType type,
+ {bool isConstant,
+ bool isEmpty}) {
+ setType(node, type);
+ worldImpact.registerMapLiteral(
+ new MapLiteralUse(type, isConstant: isConstant, isEmpty: isEmpty));
}
- // TODO(johnniwinther): Remove the [ResolverVisitor] dependency. Its only
- // needed to lookup types in the current scope.
- void registerJsEmbeddedGlobalCall(Node node, ResolverVisitor visitor) {
- world.registerJsEmbeddedGlobalCall(node, visitor);
- }
-
- // TODO(johnniwinther): Remove the [ResolverVisitor] dependency. Its only
- // needed to lookup types in the current scope.
- void registerJsBuiltinCall(Node node, ResolverVisitor visitor) {
- world.registerJsBuiltinCall(node, visitor);
+ void registerForeignCall(Node node,
+ Element element,
+ CallStructure callStructure,
+ ResolverVisitor visitor) {
+ backend.registerForeignCall(
+ node, element, callStructure,
+ new ForeignResolutionResolver(visitor, this));
}
void registerGetOfStaticFunction(FunctionElement element) {
@@ -513,49 +652,49 @@
}
void registerConstSymbol(String name) {
- backend.registerConstSymbol(name, this);
+ worldImpact.registerConstSymbolName(name);
}
void registerSymbolConstructor() {
- backend.resolutionCallbacks.onSymbolConstructor(this);
+ worldImpact.registerFeature(Feature.SYMBOL_CONSTRUCTOR);
}
void registerInstantiatedType(InterfaceType type) {
- backend.registerInstantiatedType(type, world, this);
+ worldImpact.registerInstantiatedType(type);
mapping.addRequiredType(type);
}
void registerAbstractClassInstantiation() {
- backend.resolutionCallbacks.onAbstractClassInstantiation(this);
+ worldImpact.registerFeature(Feature.ABSTRACT_CLASS_INSTANTIATION);
}
void registerNewSymbol() {
- backend.registerNewSymbol(this);
+ worldImpact.registerFeature(Feature.NEW_SYMBOL);
}
void registerRequiredType(DartType type, Element enclosingElement) {
- backend.registerRequiredType(type, enclosingElement);
+ worldImpact.registerRequiredType(type);
mapping.addRequiredType(type);
}
void registerStringInterpolation() {
- backend.resolutionCallbacks.onStringInterpolation(this);
+ worldImpact.registerFeature(Feature.STRING_INTERPOLATION);
}
void registerFallThroughError() {
- backend.resolutionCallbacks.onFallThroughError(this);
+ worldImpact.registerFeature(Feature.FALL_THROUGH_ERROR);
}
void registerCatchStatement() {
- backend.resolutionCallbacks.onCatchStatement(this);
+ worldImpact.registerFeature(Feature.CATCH_STATEMENT);
}
void registerStackTraceInCatch() {
- backend.resolutionCallbacks.onStackTraceInCatch(this);
+ worldImpact.registerFeature(Feature.STACK_TRACE_IN_CATCH);
}
void registerSyncForIn(Node node) {
- backend.resolutionCallbacks.onSyncForIn(this);
+ worldImpact.registerFeature(Feature.SYNC_FOR_IN);
}
ClassElement defaultSuperclass(ClassElement element) {
@@ -568,7 +707,7 @@
}
void registerThrowExpression() {
- backend.resolutionCallbacks.onThrowExpression(this);
+ worldImpact.registerFeature(Feature.THROW_EXPRESSION);
}
void registerDependency(Element element) {
@@ -586,11 +725,12 @@
}
void registerInstantiation(InterfaceType type) {
- backend.registerInstantiatedType(type, world, this);
+ registerInstantiatedType(type);
}
void registerAssert(bool hasMessage) {
- backend.resolutionCallbacks.onAssert(hasMessage, this);
+ worldImpact.registerFeature(
+ hasMessage ? Feature.ASSERT_WITH_MESSAGE : Feature.ASSERT);
}
void registerSendStructure(Send node, SendStructure sendStructure) {
@@ -604,18 +744,52 @@
}
void registerAsyncMarker(FunctionElement element) {
- backend.registerAsyncMarker(element, world, this);
+ switch (element.asyncMarker) {
+ case AsyncMarker.SYNC:
+ break;
+ case AsyncMarker.SYNC_STAR:
+ worldImpact.registerFeature(Feature.SYNC_STAR);
+ break;
+ case AsyncMarker.ASYNC:
+ worldImpact.registerFeature(Feature.ASYNC);
+ break;
+ case AsyncMarker.ASYNC_STAR:
+ worldImpact.registerFeature(Feature.ASYNC_STAR);
+ break;
+ }
}
void registerAsyncForIn(AsyncForIn node) {
- backend.resolutionCallbacks.onAsyncForIn(node, this);
+ worldImpact.registerFeature(Feature.ASYNC_FOR_IN);
}
void registerIncDecOperation() {
- backend.resolutionCallbacks.onIncDecOperation(this);
+ worldImpact.registerFeature(Feature.INC_DEC_OPERATION);
}
void registerTryStatement() {
mapping.containsTryStatement = true;
}
}
+
+class ForeignResolutionResolver implements ForeignResolver {
+ final ResolverVisitor visitor;
+ final ResolutionRegistry registry;
+
+ ForeignResolutionResolver(this.visitor, this.registry);
+
+ @override
+ ConstantExpression getConstant(Node node) {
+ return registry.getConstant(node);
+ }
+
+ @override
+ void registerInstantiatedType(InterfaceType type) {
+ registry.registerInstantiatedType(type);
+ }
+
+ @override
+ DartType resolveTypeFromString(Node node, String typeName) {
+ return visitor.resolveTypeFromString(node, typeName);
+ }
+}
diff --git a/pkg/compiler/lib/src/resolution/resolution.dart b/pkg/compiler/lib/src/resolution/resolution.dart
index 7256536..2f5a617 100644
--- a/pkg/compiler/lib/src/resolution/resolution.dart
+++ b/pkg/compiler/lib/src/resolution/resolution.dart
@@ -8,6 +8,10 @@
import '../common/names.dart' show
Identifiers;
+import '../common/resolution.dart' show
+ Parsing,
+ Resolution,
+ ResolutionWorldImpact;
import '../common/tasks.dart' show
CompilerTask,
DeferredAction;
@@ -19,7 +23,8 @@
ConstantValue;
import '../dart_types.dart';
import '../diagnostics/diagnostic_listener.dart' show
- DiagnosticMessage;
+ DiagnosticMessage,
+ DiagnosticReporter;
import '../diagnostics/invariant.dart' show
invariant;
import '../diagnostics/messages.dart' show
@@ -69,19 +74,23 @@
String get name => 'Resolver';
- WorldImpact resolve(Element element) {
+ Resolution get resolution => compiler.resolution;
+
+ Parsing get parsing => compiler.parsing;
+
+ ResolutionWorldImpact resolve(Element element) {
return measure(() {
if (Elements.isErroneous(element)) {
// TODO(johnniwinther): Add a predicate for this.
assert(invariant(element, element is! ErroneousElement,
message: "Element $element expected to have parse errors."));
_ensureTreeElements(element);
- return const WorldImpact();
+ return const ResolutionWorldImpact();
}
WorldImpact processMetadata([WorldImpact result]) {
for (MetadataAnnotation metadata in element.implementation.metadata) {
- metadata.ensureResolved(compiler);
+ metadata.ensureResolved(resolution);
}
return result;
}
@@ -99,8 +108,8 @@
}
if (element.isClass) {
ClassElement cls = element;
- cls.ensureResolved(compiler);
- return processMetadata(const WorldImpact());
+ cls.ensureResolved(resolution);
+ return processMetadata(const ResolutionWorldImpact());
} else if (element.isTypedef) {
TypedefElement typdef = element;
return processMetadata(resolveTypedef(typdef));
@@ -123,7 +132,7 @@
// Ensure that we follow redirections through implementation elements.
redirection = redirection.implementation;
if (seen.contains(redirection)) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE);
return;
}
@@ -135,6 +144,8 @@
static void processAsyncMarker(Compiler compiler,
BaseFunctionElementX element,
ResolutionRegistry registry) {
+ DiagnosticReporter reporter = compiler.reporter;
+ Resolution resolution = compiler.resolution;
FunctionExpression functionExpression = element.node;
AsyncModifier asyncModifier = functionExpression.asyncModifier;
if (asyncModifier != null) {
@@ -146,18 +157,18 @@
element.asyncMarker = AsyncMarker.SYNC_STAR;
}
if (element.isAbstract) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
asyncModifier,
MessageKind.ASYNC_MODIFIER_ON_ABSTRACT_METHOD,
{'modifier': element.asyncMarker});
} else if (element.isConstructor) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
asyncModifier,
MessageKind.ASYNC_MODIFIER_ON_CONSTRUCTOR,
{'modifier': element.asyncMarker});
} else {
if (element.isSetter) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
asyncModifier,
MessageKind.ASYNC_MODIFIER_ON_SETTER,
{'modifier': element.asyncMarker});
@@ -165,7 +176,7 @@
}
if (functionExpression.body.asReturn() != null &&
element.asyncMarker.isYielding) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
asyncModifier,
MessageKind.YIELDING_MODIFIER_ON_ARROW_BODY,
{'modifier': element.asyncMarker});
@@ -174,13 +185,13 @@
registry.registerAsyncMarker(element);
switch (element.asyncMarker) {
case AsyncMarker.ASYNC:
- compiler.futureClass.ensureResolved(compiler);
+ compiler.futureClass.ensureResolved(resolution);
break;
case AsyncMarker.ASYNC_STAR:
- compiler.streamClass.ensureResolved(compiler);
+ compiler.streamClass.ensureResolved(resolution);
break;
case AsyncMarker.SYNC_STAR:
- compiler.iterableClass.ensureResolved(compiler);
+ compiler.iterableClass.ensureResolved(resolution);
break;
}
}
@@ -197,22 +208,22 @@
WorldImpact resolveMethodElementImplementation(
FunctionElement element, FunctionExpression tree) {
- return compiler.withCurrentElement(element, () {
+ return reporter.withCurrentElement(element, () {
if (element.isExternal && tree.hasBody()) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
element,
MessageKind.EXTERNAL_WITH_BODY,
{'functionName': element.name});
}
if (element.isConstructor) {
if (tree.returnType != null) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
tree, MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE);
}
if (element.isConst &&
tree.hasBody() &&
!tree.isRedirectingFactory) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
tree, MessageKind.CONST_CONSTRUCTOR_HAS_BODY);
}
}
@@ -233,7 +244,7 @@
resolveRedirectingConstructor(resolver, tree, element, redirection);
}
} else if (tree.initializers != null) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
tree, MessageKind.FUNCTION_WITH_INITIALIZER);
}
@@ -264,7 +275,7 @@
if (Elements.isInstanceMethod(element) &&
element.name == Identifiers.noSuchMethod_ &&
_isNativeClassOrExtendsNativeClass(enclosingClass)) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
tree, MessageKind.NO_SUCH_METHOD_IN_NATIVE);
}
@@ -275,14 +286,14 @@
WorldImpact resolveMethodElement(FunctionElementX element) {
assert(invariant(element, element.isDeclaration));
- return compiler.withCurrentElement(element, () {
- if (compiler.enqueuer.resolution.hasBeenResolved(element)) {
+ return reporter.withCurrentElement(element, () {
+ if (compiler.enqueuer.resolution.hasBeenProcessed(element)) {
// TODO(karlklose): Remove the check for [isConstructor]. [elememts]
// should never be non-null, not even for constructors.
assert(invariant(element, element.isConstructor,
message: 'Non-constructor element $element '
'has already been analyzed.'));
- return const WorldImpact();
+ return const ResolutionWorldImpact();
}
if (element.isSynthesized) {
if (element.isGenerativeConstructor) {
@@ -293,7 +304,7 @@
// Ensure the signature of the synthesized element is
// resolved. This is the only place where the resolver is
// seeing this element.
- element.computeSignature(compiler);
+ element.computeType(resolution);
if (!target.isErroneous) {
registry.registerStaticUse(target);
registry.registerImplicitSuperCall(target);
@@ -302,11 +313,11 @@
} else {
assert(element.isDeferredLoaderGetter || element.isErroneous);
_ensureTreeElements(element);
- return const WorldImpact();
+ return const ResolutionWorldImpact();
}
} else {
- element.parseNode(compiler);
- element.computeType(compiler);
+ element.parseNode(resolution.parsing);
+ element.computeType(resolution);
FunctionElementX implementation = element;
if (element.isExternal) {
implementation = compiler.backend.resolveExternalFunction(element);
@@ -330,9 +341,9 @@
}
WorldImpact resolveField(FieldElementX element) {
- VariableDefinitions tree = element.parseNode(compiler);
+ VariableDefinitions tree = element.parseNode(parsing);
if(element.modifiers.isStatic && element.isTopLevel) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
element.modifiers.getStatic(),
MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC);
}
@@ -356,10 +367,10 @@
// [Compiler.analyzeSignaturesOnly] is set.
visitor.visit(initializer);
} else if (modifiers.isConst) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
element, MessageKind.CONST_WITHOUT_INITIALIZER);
} else if (modifiers.isFinal && !element.isInstanceMember) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
element, MessageKind.FINAL_WITHOUT_INITIALIZER);
} else {
registry.registerInstantiatedClass(compiler.nullClass);
@@ -383,7 +394,7 @@
}
// Perform various checks as side effect of "computing" the type.
- element.computeType(compiler);
+ element.computeType(resolution);
return registry.worldImpact;
}
@@ -391,7 +402,7 @@
DartType resolveTypeAnnotation(Element element, TypeAnnotation annotation) {
DartType type = resolveReturnType(element, annotation);
if (type.isVoid) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
annotation, MessageKind.VOID_NOT_ALLOWED);
}
return type;
@@ -426,7 +437,7 @@
Element nextTarget = target.immediateRedirectionTarget;
if (seen.contains(nextTarget)) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.CYCLIC_REDIRECTING_FACTORY);
targetType = target.enclosingClass.thisType;
break;
@@ -455,7 +466,7 @@
TreeElements treeElements = factory.treeElements;
assert(invariant(node, treeElements != null,
message: 'No TreeElements cached for $factory.'));
- FunctionExpression functionNode = factory.parseNode(compiler);
+ FunctionExpression functionNode = factory.parseNode(parsing);
RedirectingFactoryBody redirectionNode = functionNode.body;
DartType factoryType = treeElements.getType(redirectionNode);
if (!factoryType.isDynamic) {
@@ -473,10 +484,10 @@
* called by [resolveClass] and [ClassSupertypeResolver].
*/
void loadSupertypes(BaseClassElementX cls, Spannable from) {
- compiler.withCurrentElement(cls, () => measure(() {
+ reporter.withCurrentElement(cls, () => measure(() {
if (cls.supertypeLoadState == STATE_DONE) return;
if (cls.supertypeLoadState == STATE_STARTED) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
from,
MessageKind.CYCLIC_CLASS_HIERARCHY,
{'className': cls.name});
@@ -484,7 +495,7 @@
cls.hasIncompleteHierarchy = true;
cls.allSupertypesAndSelf =
compiler.objectClass.allSupertypesAndSelf.extendClass(
- cls.computeType(compiler));
+ cls.computeType(resolution));
cls.supertype = cls.allSupertypes.head;
assert(invariant(from, cls.supertype != null,
message: 'Missing supertype on cyclic class $cls.'));
@@ -492,9 +503,9 @@
return;
}
cls.supertypeLoadState = STATE_STARTED;
- compiler.withCurrentElement(cls, () {
+ reporter.withCurrentElement(cls, () {
// TODO(ahe): Cache the node in cls.
- cls.parseNode(compiler).accept(
+ cls.parseNode(parsing).accept(
new ClassSupertypeResolver(compiler, cls));
if (cls.supertypeLoadState != STATE_DONE) {
cls.supertypeLoadState = STATE_DONE;
@@ -519,7 +530,7 @@
// 'TypeDeclarationResolver'.
_resolveTypeDeclaration(TypeDeclarationElement element,
resolveTypeDeclaration()) {
- return compiler.withCurrentElement(element, () {
+ return reporter.withCurrentElement(element, () {
return measure(() {
TypeDeclarationElement previousResolvedTypeDeclaration =
currentlyResolvedTypeDeclaration;
@@ -528,7 +539,7 @@
if (previousResolvedTypeDeclaration == null) {
do {
while (!pendingClassesToBeResolved.isEmpty) {
- pendingClassesToBeResolved.removeFirst().ensureResolved(compiler);
+ pendingClassesToBeResolved.removeFirst().ensureResolved(resolution);
}
while (!pendingClassesToBePostProcessed.isEmpty) {
_postProcessClassElement(
@@ -553,7 +564,7 @@
* resolved.
*
* Warning: Do not call this method directly. Instead use
- * [:element.ensureResolved(compiler):].
+ * [:element.ensureResolved(resolution):].
*/
TreeElements resolveClass(BaseClassElementX element) {
return _resolveTypeDeclaration(element, () {
@@ -567,7 +578,7 @@
void ensureClassWillBeResolvedInternal(ClassElement element) {
if (currentlyResolvedTypeDeclaration == null) {
- element.ensureResolved(compiler);
+ element.ensureResolved(resolution);
} else {
pendingClassesToBeResolved.add(element);
}
@@ -576,10 +587,10 @@
void resolveClassInternal(BaseClassElementX element,
ResolutionRegistry registry) {
if (!element.isPatch) {
- compiler.withCurrentElement(element, () => measure(() {
+ reporter.withCurrentElement(element, () => measure(() {
assert(element.resolutionState == STATE_NOT_STARTED);
element.resolutionState = STATE_STARTED;
- Node tree = element.parseNode(compiler);
+ Node tree = element.parseNode(parsing);
loadSupertypes(element, tree);
ClassResolverVisitor visitor =
@@ -591,14 +602,14 @@
}));
if (element.isPatched) {
// Ensure handling patch after origin.
- element.patch.ensureResolved(compiler);
+ element.patch.ensureResolved(resolution);
}
} else { // Handle patch classes:
element.resolutionState = STATE_STARTED;
// Ensure handling origin before patch.
- element.origin.ensureResolved(compiler);
+ element.origin.ensureResolved(resolution);
// Ensure that the type is computed.
- element.computeType(compiler);
+ element.computeType(resolution);
// Copy class hierarchy from origin.
element.supertype = element.origin.supertype;
element.interfaces = element.origin.interfaces;
@@ -614,7 +625,7 @@
void _postProcessClassElement(BaseClassElementX element) {
for (MetadataAnnotation metadata in element.implementation.metadata) {
- metadata.ensureResolved(compiler);
+ metadata.ensureResolved(resolution);
ConstantValue value =
compiler.constants.getConstantValue(metadata.constant);
if (!element.isProxy && compiler.isProxyConstant(value)) {
@@ -629,9 +640,9 @@
// TODO(ahe): Avoid this eager resolution.
element.forEachMember((_, Element member) {
if (!member.isInstanceMember) {
- compiler.withCurrentElement(member, () {
+ reporter.withCurrentElement(member, () {
for (MetadataAnnotation metadata in member.implementation.metadata) {
- metadata.ensureResolved(compiler);
+ metadata.ensureResolved(resolution);
}
});
}
@@ -662,7 +673,7 @@
int illegalFlags = modifiers.flags & ~Modifiers.FLAG_ABSTRACT;
if (illegalFlags != 0) {
Modifiers illegalModifiers = new Modifiers.withFlags(null, illegalFlags);
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
modifiers,
MessageKind.ILLEGAL_MIXIN_APPLICATION_MODIFIERS,
{'modifiers': illegalModifiers});
@@ -676,7 +687,7 @@
// Check that we're not trying to use Object as a mixin.
if (mixin.superclass == null) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
mixinApplication,
MessageKind.ILLEGAL_MIXIN_OBJECT);
// Avoid reporting additional errors for the Object class.
@@ -690,7 +701,7 @@
// Check that the mixed in class has Object as its superclass.
if (!mixin.superclass.isObject) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
mixin, MessageKind.ILLEGAL_MIXIN_SUPERCLASS);
}
@@ -698,7 +709,7 @@
// make sure we aren't mixing in methods that use 'super'.
mixin.forEachLocalMember((AstElement member) {
if (member.isGenerativeConstructor && !member.isSynthesized) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
member, MessageKind.ILLEGAL_MIXIN_CONSTRUCTOR);
} else {
// Get the resolution tree and check that the resolved member
@@ -707,7 +718,7 @@
// mixin application has been performed.
// TODO(johnniwinther): Obtain the [TreeElements] for [member]
// differently.
- if (compiler.enqueuer.resolution.hasBeenResolved(member)) {
+ if (compiler.enqueuer.resolution.hasBeenProcessed(member)) {
checkMixinSuperUses(
member.resolvedAst.elements,
mixinApplication,
@@ -724,18 +735,18 @@
if (resolutionTree == null) return;
Iterable<Node> superUses = resolutionTree.superUses;
if (superUses.isEmpty) return;
- DiagnosticMessage error = compiler.createMessage(
+ DiagnosticMessage error = reporter.createMessage(
mixinApplication,
MessageKind.ILLEGAL_MIXIN_WITH_SUPER,
{'className': mixin.name});
// Show the user the problematic uses of 'super' in the mixin.
List<DiagnosticMessage> infos = <DiagnosticMessage>[];
for (Node use in superUses) {
- infos.add(compiler.createMessage(
+ infos.add(reporter.createMessage(
use,
MessageKind.ILLEGAL_MIXIN_SUPER_USE));
}
- compiler.reportError(error, infos);
+ reporter.reportError(error, infos);
}
void checkClassMembers(ClassElement cls) {
@@ -746,13 +757,13 @@
List<Element> constConstructors = <Element>[];
List<Element> nonFinalInstanceFields = <Element>[];
cls.forEachMember((holder, member) {
- compiler.withCurrentElement(member, () {
+ reporter.withCurrentElement(member, () {
// Perform various checks as side effect of "computing" the type.
- member.computeType(compiler);
+ member.computeType(resolution);
// Check modifiers.
if (member.isFunction && member.modifiers.isFinal) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
member, MessageKind.ILLEGAL_FINAL_METHOD_MODIFIER);
}
if (member.isConstructor) {
@@ -762,7 +773,7 @@
if (mismatchedFlagsBits != 0) {
final mismatchedFlags =
new Modifiers.withFlags(null, mismatchedFlagsBits);
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
member,
MessageKind.ILLEGAL_CONSTRUCTOR_MODIFIERS,
{'modifiers': mismatchedFlags});
@@ -773,7 +784,7 @@
}
if (member.isField) {
if (member.modifiers.isConst && !member.modifiers.isStatic) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
member, MessageKind.ILLEGAL_CONST_FIELD_MODIFIER);
}
if (!member.modifiers.isStatic && !member.modifiers.isFinal) {
@@ -787,24 +798,24 @@
if (!constConstructors.isEmpty && !nonFinalInstanceFields.isEmpty) {
Spannable span = constConstructors.length > 1
? cls : constConstructors[0];
- DiagnosticMessage error = compiler.createMessage(
+ DiagnosticMessage error = reporter.createMessage(
span,
MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS,
{'className': cls.name});
List<DiagnosticMessage> infos = <DiagnosticMessage>[];
if (constConstructors.length > 1) {
for (Element constructor in constConstructors) {
- infos.add(compiler.createMessage(
+ infos.add(reporter.createMessage(
constructor,
MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR));
}
}
for (Element field in nonFinalInstanceFields) {
- infos.add(compiler.createMessage(
+ infos.add(reporter.createMessage(
field,
MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD));
}
- compiler.reportError(error, infos);
+ reporter.reportError(error, infos);
}
}
@@ -818,11 +829,11 @@
ClassElement classElement = member.enclosingClass;
Element lookupElement = classElement.lookupLocalMember(member.name);
if (lookupElement == null) {
- compiler.internalError(member,
+ reporter.internalError(member,
"No abstract field for accessor");
} else if (!identical(lookupElement.kind, ElementKind.ABSTRACT_FIELD)) {
if (lookupElement.isErroneous || lookupElement.isAmbiguous) return;
- compiler.internalError(member,
+ reporter.internalError(member,
"Inaccessible abstract field for accessor");
}
AbstractFieldElement field = lookupElement;
@@ -836,11 +847,11 @@
if (!identical(getterFlags, setterFlags)) {
final mismatchedFlags =
new Modifiers.withFlags(null, getterFlags ^ setterFlags);
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
field.getter,
MessageKind.GETTER_MISMATCH,
{'modifiers': mismatchedFlags});
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
field.setter,
MessageKind.SETTER_MISMATCH,
{'modifiers': mismatchedFlags});
@@ -876,7 +887,7 @@
messageKind = MessageKind.TERNARY_OPERATOR_BAD_ARITY;
requiredParameterCount = 2;
} else {
- compiler.internalError(function,
+ reporter.internalError(function,
'Unexpected user defined operator $value');
}
checkArity(function, requiredParameterCount, messageKind, isMinus);
@@ -888,7 +899,7 @@
Element hashCodeImplementation =
cls.lookupLocalMember('hashCode');
if (hashCodeImplementation != null) return;
- compiler.reportHintMessage(
+ reporter.reportHintMessage(
operatorEquals, MessageKind.OVERRIDE_EQUALS_NOT_HASH_CODE,
{'class': cls.name});
}
@@ -929,19 +940,19 @@
errorNode = node.parameters.nodes.skip(requiredParameterCount).head;
}
}
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
errorNode, messageKind, {'operatorName': function.name});
}
if (signature.optionalParameterCount != 0) {
Node errorNode =
node.parameters.nodes.skip(signature.requiredParameterCount).head;
if (signature.optionalParametersAreNamed) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
errorNode,
MessageKind.OPERATOR_NAMED_PARAMETERS,
{'operatorName': function.name});
} else {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
errorNode,
MessageKind.OPERATOR_OPTIONAL_PARAMETERS,
{'operatorName': function.name});
@@ -953,14 +964,14 @@
MessageKind errorMessage,
Element contextElement,
MessageKind contextMessage) {
- compiler.reportError(
- compiler.createMessage(
+ reporter.reportError(
+ reporter.createMessage(
errorneousElement,
errorMessage,
{'memberName': contextElement.name,
'className': contextElement.enclosingClass.name}),
<DiagnosticMessage>[
- compiler.createMessage(contextElement, contextMessage),
+ reporter.createMessage(contextElement, contextMessage),
]);
}
@@ -968,14 +979,13 @@
FunctionSignature resolveSignature(FunctionElementX element) {
MessageKind defaultValuesError = null;
if (element.isFactoryConstructor) {
- FunctionExpression body = element.parseNode(compiler);
+ FunctionExpression body = element.parseNode(parsing);
if (body.isRedirectingFactory) {
defaultValuesError = MessageKind.REDIRECTING_FACTORY_WITH_DEFAULT;
}
}
- return compiler.withCurrentElement(element, () {
- FunctionExpression node =
- compiler.parser.measure(() => element.parseNode(compiler));
+ return reporter.withCurrentElement(element, () {
+ FunctionExpression node = element.parseNode(parsing);
return measure(() => SignatureResolver.analyze(
compiler, node.parameters, node.returnType, element,
new ResolutionRegistry(compiler, _ensureTreeElements(element)),
@@ -985,17 +995,16 @@
}
WorldImpact resolveTypedef(TypedefElementX element) {
- if (element.isResolved) return const WorldImpact();
+ if (element.isResolved) return const ResolutionWorldImpact();
compiler.world.allTypedefs.add(element);
return _resolveTypeDeclaration(element, () {
ResolutionRegistry registry = new ResolutionRegistry(
compiler, _ensureTreeElements(element));
- return compiler.withCurrentElement(element, () {
+ return reporter.withCurrentElement(element, () {
return measure(() {
assert(element.resolutionState == STATE_NOT_STARTED);
element.resolutionState = STATE_STARTED;
- Typedef node =
- compiler.parser.measure(() => element.parseNode(compiler));
+ Typedef node = element.parseNode(parsing);
TypedefResolverVisitor visitor =
new TypedefResolverVisitor(compiler, element, registry);
visitor.visit(node);
@@ -1007,17 +1016,17 @@
}
void resolveMetadataAnnotation(MetadataAnnotationX annotation) {
- compiler.withCurrentElement(annotation.annotatedElement, () => measure(() {
+ reporter.withCurrentElement(annotation.annotatedElement, () => measure(() {
assert(annotation.resolutionState == STATE_NOT_STARTED);
annotation.resolutionState = STATE_STARTED;
- Node node = annotation.parseNode(compiler);
+ Node node = annotation.parseNode(parsing);
Element annotatedElement = annotation.annotatedElement;
AnalyzableElement context = annotatedElement.analyzableElement;
ClassElement classElement = annotatedElement.enclosingClass;
if (classElement != null) {
// The annotation is resolved in the scope of [classElement].
- classElement.ensureResolved(compiler);
+ classElement.ensureResolved(resolution);
}
assert(invariant(node, context != null,
message: "No context found for metadata annotation "
@@ -1034,7 +1043,7 @@
// and the annotated element instead. This will allow the backend to
// retrieve the backend constant and only register metadata on the
// elements for which it is needed. (Issue 17732).
- registry.registerMetadataConstant(annotation, annotatedElement);
+ registry.registerMetadataConstant(annotation);
annotation.resolutionState = STATE_DONE;
}));
}
@@ -1046,7 +1055,7 @@
ParameterMetadataAnnotation metadataAnnotation =
new ParameterMetadataAnnotation(annotation);
metadataAnnotation.annotatedElement = element;
- metadata.add(metadataAnnotation.ensureResolved(compiler));
+ metadata.add(metadataAnnotation.ensureResolved(resolution));
}
return metadata;
}
diff --git a/pkg/compiler/lib/src/resolution/resolution_common.dart b/pkg/compiler/lib/src/resolution/resolution_common.dart
index eb7b80b..1b0b6b5 100644
--- a/pkg/compiler/lib/src/resolution/resolution_common.dart
+++ b/pkg/compiler/lib/src/resolution/resolution_common.dart
@@ -4,12 +4,15 @@
library dart2js.resolution.common;
+import '../common/resolution.dart' show
+ Resolution;
import '../common/tasks.dart' show
DeferredAction;
import '../compiler.dart' show
Compiler;
import '../diagnostics/diagnostic_listener.dart' show
- DiagnosticMessage;
+ DiagnosticMessage,
+ DiagnosticReporter;
import '../diagnostics/messages.dart' show
MessageKind;
import '../diagnostics/spannable.dart' show
@@ -29,8 +32,12 @@
CommonResolverVisitor(Compiler this.compiler);
+ DiagnosticReporter get reporter => compiler.reporter;
+
+ Resolution get resolution => compiler.resolution;
+
R visitNode(Node node) {
- return compiler.internalError(node,
+ return reporter.internalError(node,
'internal error: Unhandled node: ${node.getObjectDescription()}');
}
@@ -75,7 +82,7 @@
if (element.name == 'yield' ||
element.name == 'async' ||
element.name == 'await') {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.ASYNC_KEYWORD_AS_IDENTIFIER,
{'keyword': element.name,
'modifier': currentAsyncMarker});
@@ -86,7 +93,7 @@
/// Register [node] as the definition of [element].
void defineLocalVariable(Node node, LocalVariableElement element) {
if (element == null) {
- throw compiler.internalError(node, 'element is null');
+ throw reporter.internalError(node, 'element is null');
}
checkLocalDefinitionName(node, element);
registry.defineElement(node, element);
@@ -95,13 +102,13 @@
void reportDuplicateDefinition(String name,
Spannable definition,
Spannable existing) {
- compiler.reportError(
- compiler.createMessage(
+ reporter.reportError(
+ reporter.createMessage(
definition,
MessageKind.DUPLICATE_DEFINITION,
{'name': name}),
<DiagnosticMessage>[
- compiler.createMessage(
+ reporter.createMessage(
existing,
MessageKind.EXISTING_DEFINITION,
{'name': name}),
diff --git a/pkg/compiler/lib/src/resolution/signatures.dart b/pkg/compiler/lib/src/resolution/signatures.dart
index 858f9b5..831aed0 100644
--- a/pkg/compiler/lib/src/resolution/signatures.dart
+++ b/pkg/compiler/lib/src/resolution/signatures.dart
@@ -7,6 +7,8 @@
import '../compiler.dart' show
Compiler;
import '../dart_types.dart';
+import '../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import '../diagnostics/invariant.dart' show
invariant;
import '../diagnostics/messages.dart' show
@@ -66,7 +68,7 @@
// This must be a list of optional arguments.
String value = node.beginToken.stringValue;
if ((!identical(value, '[')) && (!identical(value, '{'))) {
- compiler.internalError(node, "expected optional parameters");
+ reporter.internalError(node, "expected optional parameters");
}
optionalParametersAreNamed = (identical(value, '{'));
isOptionalParameter = true;
@@ -78,26 +80,26 @@
FormalElementX visitVariableDefinitions(VariableDefinitions node) {
Link<Node> definitions = node.definitions.nodes;
if (definitions.isEmpty) {
- compiler.internalError(node, 'no parameter definition');
+ reporter.internalError(node, 'no parameter definition');
return null;
}
if (!definitions.tail.isEmpty) {
- compiler.internalError(definitions.tail.head, 'extra definition');
+ reporter.internalError(definitions.tail.head, 'extra definition');
return null;
}
Node definition = definitions.head;
if (definition is NodeList) {
- compiler.internalError(node, 'optional parameters are not implemented');
+ reporter.internalError(node, 'optional parameters are not implemented');
}
if (node.modifiers.isConst) {
- compiler.reportErrorMessage(node, MessageKind.FORMAL_DECLARED_CONST);
+ reporter.reportErrorMessage(node, MessageKind.FORMAL_DECLARED_CONST);
}
if (node.modifiers.isStatic) {
- compiler.reportErrorMessage(node, MessageKind.FORMAL_DECLARED_STATIC);
+ reporter.reportErrorMessage(node, MessageKind.FORMAL_DECLARED_STATIC);
}
if (currentDefinitions != null) {
- compiler.internalError(node, 'function type parameters not supported');
+ reporter.internalError(node, 'function type parameters not supported');
}
currentDefinitions = node;
FormalElementX element = definition.accept(this);
@@ -113,7 +115,7 @@
if (isOptionalParameter &&
optionalParametersAreNamed &&
Name.isPrivateName(node.source)) {
- compiler.reportErrorMessage(node, MessageKind.PRIVATE_NAMED_PARAMETER);
+ reporter.reportErrorMessage(node, MessageKind.PRIVATE_NAMED_PARAMETER);
}
}
@@ -124,8 +126,7 @@
compiler, functionExpression.parameters,
functionExpression.returnType, element, registry,
defaultValuesError: MessageKind.FUNCTION_TYPE_FORMAL_WITH_DEFAULT);
- element.functionSignatureCache = functionSignature;
- element.typeCache = functionSignature.type;
+ element.functionSignature = functionSignature;
}
if (currentDefinitions.type != null) {
@@ -148,7 +149,7 @@
assert(invariant(currentDefinitions,
link.head.asIdentifier() != null || link.head.asSend() != null));
if (fieldElement != null) {
- element.typeCache = fieldElement.computeType(compiler);
+ element.typeCache = fieldElement.computeType(resolution);
} else {
element.typeCache = const DynamicType();
}
@@ -172,7 +173,7 @@
functionExpression.name.asIdentifier() != null) {
return functionExpression.name.asIdentifier();
} else {
- compiler.internalError(node,
+ reporter.internalError(node,
'internal error: unimplemented receiver on parameter send');
return null;
}
@@ -205,12 +206,12 @@
InitializingFormalElementX element;
Identifier receiver = node.receiver.asIdentifier();
if (receiver == null || !receiver.isThis()) {
- compiler.reportErrorMessage(node, MessageKind.INVALID_PARAMETER);
+ reporter.reportErrorMessage(node, MessageKind.INVALID_PARAMETER);
return new ErroneousInitializingFormalElementX(
getParameterName(node), enclosingElement);
} else {
if (!enclosingElement.isGenerativeConstructor) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED);
return new ErroneousInitializingFormalElementX(
getParameterName(node), enclosingElement);
@@ -221,12 +222,12 @@
enclosingElement.enclosingClass.lookupLocalMember(name.source);
if (fieldElement == null ||
!identical(fieldElement.kind, ElementKind.FIELD)) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.NOT_A_FIELD, {'fieldName': name});
fieldElement = new ErroneousFieldElementX(
name, enclosingElement.enclosingClass);
} else if (!fieldElement.isInstanceMember) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.NOT_INSTANCE_FIELD, {'fieldName': name});
fieldElement = new ErroneousFieldElementX(
name, enclosingElement.enclosingClass);
@@ -250,7 +251,7 @@
}
Node defaultValue = node.arguments.head;
if (!defaultValuesAllowed) {
- compiler.reportErrorMessage(defaultValue, defaultValuesError);
+ reporter.reportErrorMessage(defaultValue, defaultValuesError);
}
return element;
}
@@ -259,12 +260,12 @@
// This is a function typed parameter.
Modifiers modifiers = currentDefinitions.modifiers;
if (modifiers.isFinal) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
modifiers,
MessageKind.FINAL_FUNCTION_TYPE_PARAMETER);
}
if (modifiers.isVar) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
modifiers, MessageKind.VAR_FUNCTION_TYPE_PARAMETER);
}
@@ -281,7 +282,7 @@
// If parameter is null, the current node should be the last,
// and a list of optional named parameters.
if (!link.tail.isEmpty || (link.head is !NodeList)) {
- compiler.internalError(link.head, "expected optional parameters");
+ reporter.internalError(link.head, "expected optional parameters");
}
}
}
@@ -305,6 +306,7 @@
{MessageKind defaultValuesError,
bool createRealParameters: false,
bool isFunctionExpression: false}) {
+ DiagnosticReporter reporter = compiler.reporter;
SignatureResolver visitor = new SignatureResolver(compiler, element,
registry, defaultValuesError: defaultValuesError,
@@ -320,7 +322,7 @@
// parse. So we suppress the message about missing formals.
assert(invariant(element, compiler.compilationFailed));
} else {
- compiler.reportErrorMessage(element, MessageKind.MISSING_FORMALS);
+ reporter.reportErrorMessage(element, MessageKind.MISSING_FORMALS);
}
}
} else {
@@ -328,7 +330,7 @@
if (!identical(formalParameters.endToken.next.stringValue,
// TODO(ahe): Remove the check for native keyword.
'native')) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
formalParameters,
MessageKind.EXTRA_FORMALS);
}
@@ -374,7 +376,7 @@
visitor.optionalParameterCount != 0)) {
// If there are no formal parameters, we already reported an error above.
if (formalParameters != null) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
formalParameters,
MessageKind.ILLEGAL_SETTER_FORMALS);
}
@@ -433,7 +435,7 @@
DartType resolveTypeAnnotation(TypeAnnotation annotation) {
DartType type = resolveReturnType(annotation);
if (type.isVoid) {
- compiler.reportErrorMessage(annotation, MessageKind.VOID_NOT_ALLOWED);
+ reporter.reportErrorMessage(annotation, MessageKind.VOID_NOT_ALLOWED);
}
return type;
}
diff --git a/pkg/compiler/lib/src/resolution/tree_elements.dart b/pkg/compiler/lib/src/resolution/tree_elements.dart
index 1204017..ca76d2b 100644
--- a/pkg/compiler/lib/src/resolution/tree_elements.dart
+++ b/pkg/compiler/lib/src/resolution/tree_elements.dart
@@ -44,6 +44,7 @@
Iterable<Element> get otherDependencies;
Element operator[](Node node);
+ Map<Node, DartType> get typesCache;
SendStructure getSendStructure(Send send);
@@ -132,6 +133,7 @@
Map<Spannable, Selector> _selectors;
Map<Spannable, TypeMask> _typeMasks;
Map<Node, DartType> _types;
+ Map<Node, DartType> typesCache = <Node, DartType>{};
Setlet<Node> _superUses;
Setlet<Element> _otherDependencies;
Map<Node, ConstantExpression> _constants;
diff --git a/pkg/compiler/lib/src/resolution/type_resolver.dart b/pkg/compiler/lib/src/resolution/type_resolver.dart
index a4335c8..0101625 100644
--- a/pkg/compiler/lib/src/resolution/type_resolver.dart
+++ b/pkg/compiler/lib/src/resolution/type_resolver.dart
@@ -3,13 +3,16 @@
// BSD-style license that can be found in the LICENSE file.
library dart2js.resolution.types;
+
+import '../common/resolution.dart' show
+ Resolution;
import '../compiler.dart' show
Compiler;
import '../dart_backend/dart_backend.dart' show
DartBackend;
import '../dart_types.dart';
import '../diagnostics/diagnostic_listener.dart' show
- DiagnosticListener,
+ DiagnosticReporter,
DiagnosticMessage;
import '../diagnostics/messages.dart' show
MessageKind;
@@ -42,7 +45,9 @@
TypeResolver(this.compiler);
- DiagnosticListener get listener => compiler;
+ DiagnosticReporter get reporter => compiler.reporter;
+
+ Resolution get resolution => compiler.resolution;
/// Tries to resolve the type name as an element.
Element resolveTypeName(Identifier prefixName,
@@ -52,7 +57,7 @@
Element element;
if (prefixName != null) {
Element prefixElement =
- lookupInScope(compiler, prefixName, scope, prefixName.source);
+ lookupInScope(reporter, prefixName, scope, prefixName.source);
if (prefixElement != null && prefixElement.isPrefix) {
// The receiver is a prefix. Lookup in the imported members.
PrefixElement prefix = prefixElement;
@@ -74,7 +79,7 @@
element = null;
}
} else {
- element = lookupInScope(compiler, typeName, scope, typeName.source);
+ element = lookupInScope(reporter, typeName, scope, typeName.source);
}
return element;
}
@@ -131,13 +136,13 @@
Element erroneousElement,
List<DiagnosticMessage> infos: const <DiagnosticMessage>[]}) {
if (malformedIsError) {
- listener.reportError(
- listener.createMessage(node, messageKind, messageArguments),
+ reporter.reportError(
+ reporter.createMessage(node, messageKind, messageArguments),
infos);
} else {
registry.registerThrowRuntimeError();
- listener.reportWarning(
- listener.createMessage(node, messageKind, messageArguments),
+ reporter.reportWarning(
+ reporter.createMessage(node, messageKind, messageArguments),
infos);
}
if (erroneousElement == null) {
@@ -162,7 +167,7 @@
ambiguous.messageKind,
ambiguous.messageArguments,
infos: ambiguous.computeInfos(
- registry.mapping.analyzedElement, compiler));
+ registry.mapping.analyzedElement, reporter));
;
} else if (element.isErroneous) {
if (element is ErroneousElement) {
@@ -182,7 +187,7 @@
// TODO(johnniwinther): [ensureClassWillBeResolvedInternal] should imply
// [computeType].
compiler.resolver.ensureClassWillBeResolvedInternal(cls);
- cls.computeType(compiler);
+ cls.computeType(resolution);
List<DartType> arguments = <DartType>[];
bool hasTypeArgumentMismatch = resolveTypeArguments(
visitor, node, cls.typeVariables, arguments);
@@ -202,8 +207,8 @@
} else if (element.isTypedef) {
TypedefElement typdef = element;
// TODO(johnniwinther): [ensureResolved] should imply [computeType].
- typdef.ensureResolved(compiler);
- typdef.computeType(compiler);
+ typdef.ensureResolved(resolution);
+ typdef.computeType(resolution);
List<DartType> arguments = <DartType>[];
bool hasTypeArgumentMismatch = resolveTypeArguments(
visitor, node, typdef.typeVariables, arguments);
@@ -235,7 +240,7 @@
}
type = checkNoTypeArguments(type);
} else {
- compiler.internalError(node,
+ reporter.internalError(node,
"Unexpected element kind ${element.kind}.");
}
if (addTypeVariableBoundsCheck) {
@@ -255,7 +260,7 @@
TypeVariableType typeVariable,
DartType bound) {
if (!compiler.types.isSubtype(typeArgument, bound)) {
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
node,
MessageKind.INVALID_TYPE_VARIABLE_BOUND,
{'typeVariable': typeVariable,
@@ -288,7 +293,7 @@
!typeArguments.isEmpty;
typeArguments = typeArguments.tail, index++) {
if (index > expectedVariables - 1) {
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
typeArguments.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT);
typeArgumentCountMismatch = true;
}
@@ -297,7 +302,7 @@
arguments.add(argType);
}
if (index < expectedVariables) {
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
node.typeArguments, MessageKind.MISSING_TYPE_ARGUMENT);
typeArgumentCountMismatch = true;
}
diff --git a/pkg/compiler/lib/src/resolution/typedefs.dart b/pkg/compiler/lib/src/resolution/typedefs.dart
index b86593c..11f57c7 100644
--- a/pkg/compiler/lib/src/resolution/typedefs.dart
+++ b/pkg/compiler/lib/src/resolution/typedefs.dart
@@ -7,6 +7,8 @@
import '../compiler.dart' show
Compiler;
import '../dart_types.dart';
+import '../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import '../diagnostics/messages.dart' show
MessageKind;
import '../elements/elements.dart' show
@@ -39,7 +41,7 @@
: super(compiler, typedefElement, registry);
visitTypedef(Typedef node) {
- element.computeType(compiler);
+ element.computeType(resolution);
scope = new TypeDeclarationScope(scope, element);
resolveTypeVariableBounds(node.typeParameters);
@@ -54,7 +56,7 @@
element.alias = signature.type;
void checkCyclicReference() {
- element.checkCyclicReference(compiler);
+ element.checkCyclicReference(resolution);
}
addDeferredAction(element, checkCyclicReference);
}
@@ -63,7 +65,7 @@
// TODO(johnniwinther): Replace with a traversal on the AST when the type
// annotations in typedef alias are stored in a [TreeElements] mapping.
class TypedefCyclicVisitor extends BaseDartTypeVisitor {
- final Compiler compiler;
+ final DiagnosticReporter reporter;
final TypedefElementX element;
bool hasCyclicReference = false;
@@ -74,7 +76,7 @@
Link<TypeVariableElement> seenTypeVariables =
const Link<TypeVariableElement>();
- TypedefCyclicVisitor(Compiler this.compiler, TypedefElement this.element);
+ TypedefCyclicVisitor(this.reporter, TypedefElement this.element);
visitType(DartType type, _) {
// Do nothing.
@@ -89,13 +91,13 @@
hasCyclicReference = true;
if (seenTypedefsCount == 1) {
// Direct cyclicity.
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
element,
MessageKind.CYCLIC_TYPEDEF,
{'typedefName': element.name});
} else if (seenTypedefsCount == 2) {
// Cyclicity through one other typedef.
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
element,
MessageKind.CYCLIC_TYPEDEF_ONE,
{'typedefName': element.name,
@@ -104,7 +106,7 @@
// Cyclicity through more than one other typedef.
for (TypedefElement cycle in seenTypedefs) {
if (!identical(typedefElement, cycle)) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
element,
MessageKind.CYCLIC_TYPEDEF_ONE,
{'typedefName': element.name,
diff --git a/pkg/compiler/lib/src/resolution/variables.dart b/pkg/compiler/lib/src/resolution/variables.dart
index 5fe7193..03d0fb8 100644
--- a/pkg/compiler/lib/src/resolution/variables.dart
+++ b/pkg/compiler/lib/src/resolution/variables.dart
@@ -46,7 +46,7 @@
new VariableDefinitionScope(resolver.scope, name);
resolver.visitIn(node.arguments.head, scope);
if (scope.variableReferencedInInitializer) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
identifier, MessageKind.REFERENCE_IN_INITIALIZATION,
{'variableName': name});
}
@@ -57,12 +57,12 @@
// The variable is initialized to null.
registry.registerInstantiatedClass(compiler.nullClass);
if (definitions.modifiers.isConst) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.CONST_WITHOUT_INITIALIZER);
}
if (definitions.modifiers.isFinal &&
!resolver.allowFinalWithoutInitializer) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.FINAL_WITHOUT_INITIALIZER);
}
return node;
diff --git a/pkg/compiler/lib/src/scanner/scanner_task.dart b/pkg/compiler/lib/src/scanner/scanner_task.dart
index cc13bb5..17b3dbc 100644
--- a/pkg/compiler/lib/src/scanner/scanner_task.dart
+++ b/pkg/compiler/lib/src/scanner/scanner_task.dart
@@ -30,9 +30,9 @@
String canonicalUri = library.canonicalUri.toString();
String resolvedUri = compilationUnit.script.resourceUri.toString();
if (canonicalUri == resolvedUri) {
- compiler.log("Scanning library $canonicalUri");
+ reporter.log("Scanning library $canonicalUri");
} else {
- compiler.log("Scanning library $canonicalUri ($resolvedUri)");
+ reporter.log("Scanning library $canonicalUri ($resolvedUri)");
}
scan(compilationUnit);
}
diff --git a/pkg/compiler/lib/src/serialization/modelz.dart b/pkg/compiler/lib/src/serialization/modelz.dart
index 83b8f5b..a4719ed 100644
--- a/pkg/compiler/lib/src/serialization/modelz.dart
+++ b/pkg/compiler/lib/src/serialization/modelz.dart
@@ -11,6 +11,8 @@
import 'serialization.dart';
import 'keys.dart';
+import '../common/resolution.dart' show
+ Resolution;
import '../compiler.dart'
show Compiler;
import '../constants/constructors.dart';
@@ -18,7 +20,6 @@
import '../diagnostics/source_span.dart'
show SourceSpan;
import '../dart_types.dart';
-import '../diagnostics/diagnostic_listener.dart';
import '../elements/elements.dart';
import '../elements/modelx.dart' show
FunctionSignatureX;
@@ -662,7 +663,7 @@
}
@override
- DartType computeType(Compiler compiler) => type;
+ DartType computeType(Resolution resolution) => type;
}
abstract class ParametersMixin
@@ -897,8 +898,8 @@
ClassElement get superclass => supertype != null ? supertype.element : null;
@override
- void ensureResolved(Compiler compiler) {
- compiler.world.registerClass(this);
+ void ensureResolved(Resolution resolution) {
+ resolution.registerClass(this);
}
}
@@ -1236,7 +1237,7 @@
}
@override
- T computeType(Compiler compiler) => thisType;
+ T computeType(Resolution resolution) => thisType;
@override
bool get isResolved => true;
@@ -1275,10 +1276,10 @@
}
@override
- void ensureResolved(Compiler compiler) {}
+ void ensureResolved(Resolution resolution) {}
@override
- void checkCyclicReference(Compiler compiler) {}
+ void checkCyclicReference(Resolution resolution) {}
}
class TypeVariableElementZ extends DeserializedElementZ
diff --git a/pkg/compiler/lib/src/serialization/task.dart b/pkg/compiler/lib/src/serialization/task.dart
index 3573b35..2b86c5e 100644
--- a/pkg/compiler/lib/src/serialization/task.dart
+++ b/pkg/compiler/lib/src/serialization/task.dart
@@ -65,7 +65,7 @@
@override
WorldImpact run(Compiler compiler, ResolutionEnqueuer world) {
_isAnalyzed = true;
- world.registerResolvedElement(element);
+ world.registerProcessedElement(element);
return worldImpact;
}
}
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 0273c96..bcf70e2 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -60,10 +60,12 @@
backend = backend,
super(backend.compiler);
+ DiagnosticReporter get reporter => compiler.reporter;
+
HGraph build(CodegenWorkItem work) {
return measure(() {
Element element = work.element.implementation;
- return compiler.withCurrentElement(element, () {
+ return reporter.withCurrentElement(element, () {
HInstruction.idCounter = 0;
SsaBuilder builder =
new SsaBuilder(
@@ -86,7 +88,7 @@
graph = builder.buildLazyInitializer(element);
}
} else {
- compiler.internalError(element, 'Unexpected element kind $kind.');
+ reporter.internalError(element, 'Unexpected element kind $kind.');
}
assert(graph.isValid());
if (!identical(kind, ElementKind.FIELD)) {
@@ -439,10 +441,10 @@
if (isAccessedDirectly(local)) {
if (directLocals[local] == null) {
if (local is TypeVariableElement) {
- builder.compiler.internalError(builder.compiler.currentElement,
+ builder.reporter.internalError(builder.compiler.currentElement,
"Runtime type information not available for $local.");
} else {
- builder.compiler.internalError(local,
+ builder.reporter.internalError(local,
"Cannot find value $local.");
}
}
@@ -792,17 +794,17 @@
// used as the target of a break, and therefore doesn't need a break
// handler associated with it.
class NullJumpHandler implements JumpHandler {
- final Compiler compiler;
+ final DiagnosticReporter reporter;
- NullJumpHandler(this.compiler);
+ NullJumpHandler(this.reporter);
void generateBreak([LabelDefinition label]) {
- compiler.internalError(CURRENT_ELEMENT_SPANNABLE,
+ reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
'NullJumpHandler.generateBreak should not be called.');
}
void generateContinue([LabelDefinition label]) {
- compiler.internalError(CURRENT_ELEMENT_SPANNABLE,
+ reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
'NullJumpHandler.generateContinue should not be called.');
}
@@ -1105,6 +1107,12 @@
work.element.implementation);
}
+
+ DiagnosticReporter get reporter => compiler.reporter;
+
+ // TODO(johnniwinther): Avoid the need for this.
+ Resolution get resolution => compiler.resolution;
+
@override
SemanticSendVisitor get sendVisitor => this;
@@ -1493,7 +1501,7 @@
inlinedFrom(Element element, f()) {
assert(element is FunctionElement || element is VariableElement);
- return compiler.withCurrentElement(element, () {
+ return reporter.withCurrentElement(element, () {
// The [sourceElementStack] contains declaration elements.
SourceInformationBuilder oldSourceInformationBuilder =
sourceInformationBuilder;
@@ -1865,7 +1873,7 @@
Map<Element, HInstruction> fieldValues,
FunctionElement caller) {
callee = callee.implementation;
- compiler.withCurrentElement(callee, () {
+ reporter.withCurrentElement(callee, () {
constructors.add(callee);
ClassElement enclosingClass = callee.enclosingClass;
if (backend.classNeedsRti(enclosingClass)) {
@@ -1980,7 +1988,7 @@
// forwarding constructor in a mixin application did not match the
// constructor (which, for example, may happen when the libraries are
// not compatible for private names, see issue 20394).
- compiler.internalError(constructor,
+ reporter.internalError(constructor,
'forwarding constructor call does not match');
}
inlineSuperOrRedirect(
@@ -2042,7 +2050,7 @@
// TODO(johnniwinther): Should we find injected constructors as well?
FunctionElement target = superClass.lookupDefaultConstructor();
if (target == null) {
- compiler.internalError(superClass,
+ reporter.internalError(superClass,
"No default constructor available.");
}
List<HInstruction> arguments =
@@ -2072,7 +2080,7 @@
classElement.forEachInstanceField(
(ClassElement enclosingClass, VariableElement member) {
if (compiler.elementHasCompileTimeError(member)) return;
- compiler.withCurrentElement(member, () {
+ reporter.withCurrentElement(member, () {
TreeElements definitions = member.treeElements;
ast.Node node = member.node;
ast.Expression initializer = member.initializer;
@@ -2479,7 +2487,7 @@
DartType type,
int kind) {
if (type == null) return original;
- type = type.unalias(compiler);
+ type = type.unalias(resolution);
assert(assertTypeInContext(type, original));
if (type.isInterfaceType && !type.treatAsRaw) {
TypeMask subtype = new TypeMask.subtype(type.element, compiler.world);
@@ -2515,7 +2523,7 @@
assert(compiler.trustTypeAnnotations);
assert(type != null);
type = localsHandler.substInContext(type);
- type = type.unalias(compiler);
+ type = type.unalias(resolution);
if (type.isDynamic) return original;
if (!type.isInterfaceType) return original;
// The type element is either a class or the void element.
@@ -2660,19 +2668,19 @@
if (!isReachable) {
// The block has been aborted by a return or a throw.
if (!stack.isEmpty) {
- compiler.internalError(node, 'Non-empty instruction stack.');
+ reporter.internalError(node, 'Non-empty instruction stack.');
}
return;
}
}
assert(!current.isClosed());
if (!stack.isEmpty) {
- compiler.internalError(node, 'Non-empty instruction stack.');
+ reporter.internalError(node, 'Non-empty instruction stack.');
}
}
visitClassNode(ast.ClassNode node) {
- compiler.internalError(node,
+ reporter.internalError(node,
'SsaBuilder.visitClassNode should not be called.');
}
@@ -3212,7 +3220,7 @@
if (node.isThis()) {
visitThisGet(node);
} else {
- compiler.internalError(node,
+ reporter.internalError(node,
"SsaFromAstMixin.visitIdentifier on non-this.");
}
}
@@ -3810,7 +3818,7 @@
HInstruction buildIsNode(ast.Node node,
DartType type,
HInstruction expression) {
- type = localsHandler.substInContext(type).unalias(compiler);
+ type = localsHandler.substInContext(type).unalias(resolution);
if (type.isFunctionType) {
List arguments = [buildFunctionType(type), expression];
pushInvokeDynamic(
@@ -4075,7 +4083,7 @@
// argument, which is the foreign code.
if (link.isEmpty || link.tail.isEmpty) {
// We should not get here because the call should be compiled to NSM.
- compiler.internalError(node.argumentsNode,
+ reporter.internalError(node.argumentsNode,
'At least two arguments expected.');
}
native.NativeBehavior nativeBehavior =
@@ -4085,7 +4093,7 @@
addGenericSendArgumentsToList(link.tail.tail, inputs);
if (nativeBehavior.codeTemplate.positionalArgumentCount != inputs.length) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.GENERIC,
{'text':
'Mismatch between number of placeholders'
@@ -4119,14 +4127,14 @@
List<HInstruction> inputs = <HInstruction>[];
addGenericSendArgumentsToList(node.arguments, inputs);
if (inputs.length != 2) {
- compiler.internalError(node.argumentsNode, 'Two arguments expected.');
+ reporter.internalError(node.argumentsNode, 'Two arguments expected.');
}
push(new HStringConcat(inputs[0], inputs[1], node, backend.stringType));
}
void handleForeignJsCurrentIsolateContext(ast.Send node) {
if (!node.arguments.isEmpty) {
- compiler.internalError(node,
+ reporter.internalError(node,
'Too many arguments to JS_CURRENT_ISOLATE_CONTEXT.');
}
@@ -4143,7 +4151,7 @@
// Leg's isolate.
Element element = backend.isolateHelperLibrary.find('_currentIsolate');
if (element == null) {
- compiler.internalError(node,
+ reporter.internalError(node,
'Isolate library and compiler mismatch.');
}
pushInvokeStatic(null, element, [], typeMask: backend.dynamicType);
@@ -4155,7 +4163,7 @@
ast.Node argument;
switch (arguments.length) {
case 0:
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.GENERIC,
{'text': 'Error: Expected one argument to JS_GET_FLAG.'});
return;
@@ -4164,7 +4172,7 @@
break;
default:
for (int i = 1; i < arguments.length; i++) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
arguments[i], MessageKind.GENERIC,
{'text': 'Error: Extra argument to JS_GET_FLAG.'});
}
@@ -4172,7 +4180,7 @@
}
ast.LiteralString string = argument.asLiteralString();
if (string == null) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
argument, MessageKind.GENERIC,
{'text': 'Error: Expected a literal string.'});
}
@@ -4186,7 +4194,7 @@
value = compiler.useContentSecurityPolicy;
break;
default:
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.GENERIC,
{'text': 'Error: Unknown internal flag "$name".'});
}
@@ -4198,7 +4206,7 @@
ast.Node argument;
switch (arguments.length) {
case 0:
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.GENERIC,
{'text': 'Error: Expected one argument to JS_GET_NAME.'});
return;
@@ -4207,7 +4215,7 @@
break;
default:
for (int i = 1; i < arguments.length; i++) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
arguments[i], MessageKind.GENERIC,
{'text': 'Error: Extra argument to JS_GET_NAME.'});
}
@@ -4217,7 +4225,7 @@
if (element == null ||
element is! FieldElement ||
element.enclosingClass != backend.jsGetNameEnum) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
argument, MessageKind.GENERIC,
{'text': 'Error: Expected a JsGetName enum value.'});
}
@@ -4233,7 +4241,7 @@
List<ast.Node> arguments = node.arguments.toList();
ast.Node argument;
if (arguments.length < 2) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.GENERIC,
{'text': 'Error: Expected at least two arguments to JS_BUILTIN.'});
}
@@ -4242,7 +4250,7 @@
if (builtinElement == null ||
(builtinElement is! FieldElement) ||
builtinElement.enclosingClass != backend.jsBuiltinEnum) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
argument, MessageKind.GENERIC,
{'text': 'Error: Expected a JsBuiltin enum value.'});
}
@@ -4276,7 +4284,7 @@
switch (arguments.length) {
case 0:
case 1:
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node, MessageKind.GENERIC,
{'text': 'Error: Expected two arguments to JS_EMBEDDED_GLOBAL.'});
return;
@@ -4287,7 +4295,7 @@
break;
default:
for (int i = 2; i < arguments.length; i++) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
arguments[i], MessageKind.GENERIC,
{'text': 'Error: Extra argument to JS_EMBEDDED_GLOBAL.'});
}
@@ -4296,7 +4304,7 @@
visit(globalNameNode);
HInstruction globalNameHNode = pop();
if (!globalNameHNode.isConstantString()) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
arguments[1], MessageKind.GENERIC,
{'text': 'Error: Expected String as second argument '
'to JS_EMBEDDED_GLOBAL.'});
@@ -4333,7 +4341,7 @@
}
}
}
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
node,
MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
stack.add(graph.addConstantNull(compiler));
@@ -4352,7 +4360,7 @@
// Call a helper method from the isolate library.
Element element = backend.isolateHelperLibrary.find('_callInIsolate');
if (element == null) {
- compiler.internalError(node,
+ reporter.internalError(node,
'Isolate library and compiler mismatch.');
}
List<HInstruction> inputs = <HInstruction>[];
@@ -4363,13 +4371,13 @@
FunctionSignature handleForeignRawFunctionRef(ast.Send node, String name) {
if (node.arguments.isEmpty || !node.arguments.tail.isEmpty) {
- compiler.internalError(node.argumentsNode,
+ reporter.internalError(node.argumentsNode,
'"$name" requires exactly one argument.');
}
ast.Node closure = node.arguments.head;
Element element = elements[closure];
if (!Elements.isStaticOrTopLevelFunction(element)) {
- compiler.internalError(closure,
+ reporter.internalError(closure,
'"$name" requires a static or top-level method.');
}
FunctionElement function = element;
@@ -4379,7 +4387,7 @@
FunctionElement implementation = function.implementation;
FunctionSignature params = implementation.functionSignature;
if (params.optionalParameterCount != 0) {
- compiler.internalError(closure,
+ reporter.internalError(closure,
'"$name" does not handle closure with optional parameters.');
}
@@ -4402,7 +4410,7 @@
void handleForeignJsSetStaticState(ast.Send node) {
if (node.arguments.isEmpty || !node.arguments.tail.isEmpty) {
- compiler.internalError(node.argumentsNode,
+ reporter.internalError(node.argumentsNode,
'Exactly one argument required.');
}
visit(node.arguments.head);
@@ -4419,7 +4427,7 @@
void handleForeignJsGetStaticState(ast.Send node) {
if (!node.arguments.isEmpty) {
- compiler.internalError(node.argumentsNode, 'Too many arguments.');
+ reporter.internalError(node.argumentsNode, 'Too many arguments.');
}
push(new HForeignCode(js.js.parseForeignJS(backend.namer.staticStateHolder),
backend.dynamicType,
@@ -4457,7 +4465,7 @@
} else if (name == 'JS_STRING_CONCAT') {
handleJsStringConcat(node);
} else {
- compiler.internalError(node, "Unknown foreign: ${element}");
+ reporter.internalError(node, "Unknown foreign: ${element}");
}
}
@@ -4884,7 +4892,7 @@
type.element,
sourceInformation: sourceInformation);
} else {
- compiler.internalError(type.element,
+ reporter.internalError(type.element,
'Unexpected type variable in static context.');
return null;
}
@@ -5571,7 +5579,7 @@
// TODO(antonm): migrate rest of SsaFromAstMixin to internalError.
internalError(Spannable node, String reason) {
- compiler.internalError(node, reason);
+ reporter.internalError(node, reason);
}
void generateError(ast.Node node, String message, Element helper) {
@@ -6891,7 +6899,7 @@
visitNodeList(ast.NodeList node) {
for (Link<ast.Node> link = node.nodes; !link.isEmpty; link = link.tail) {
if (isAborted()) {
- compiler.reportHintMessage(
+ reporter.reportHintMessage(
link.head,
MessageKind.GENERIC,
{'text': 'dead code'});
@@ -6907,7 +6915,7 @@
visitOperator(ast.Operator node) {
// Operators are intercepted in their surrounding Send nodes.
- compiler.internalError(node,
+ reporter.internalError(node,
'SsaBuilder.visitOperator should not be called.');
}
@@ -6934,7 +6942,7 @@
HInstruction exception = rethrowableException;
if (exception == null) {
exception = graph.addConstantNull(compiler);
- compiler.internalError(node,
+ reporter.internalError(node,
'rethrowableException should not be null.');
}
handleInTryStatement();
@@ -7059,7 +7067,7 @@
}
visitTypeAnnotation(ast.TypeAnnotation node) {
- compiler.internalError(node,
+ reporter.internalError(node,
'Visiting type annotation in SSA builder.');
}
@@ -7135,7 +7143,7 @@
visitStringInterpolationPart(ast.StringInterpolationPart node) {
// The parts are iterated in visitStringInterpolation.
- compiler.internalError(node,
+ reporter.internalError(node,
'SsaBuilder.visitStringInterpolation should not be called.');
}
@@ -7190,7 +7198,7 @@
JumpTarget element = elements.getTargetDefinition(node);
if (element == null || !identical(element.statement, node)) {
// No breaks or continues to this node.
- return new NullJumpHandler(compiler);
+ return new NullJumpHandler(reporter);
}
if (isLoopJump && node is ast.SwitchStatement) {
// Create a special jump handler for loops created for switch statements
@@ -7457,7 +7465,7 @@
}
visitLabel(ast.Label node) {
- compiler.internalError(node, 'SsaFromAstMixin.visitLabel.');
+ reporter.internalError(node, 'SsaFromAstMixin.visitLabel.');
}
visitLabeledStatement(ast.LabeledStatement node) {
@@ -7787,7 +7795,7 @@
// is not the generated switch statement but instead the loop generated
// in the call to [handleLoop] below.
handleSwitch(node,
- new NullJumpHandler(compiler),
+ new NullJumpHandler(reporter),
buildExpression, node.cases, getConstants,
(_) => false, // No case is default.
buildSwitchCase);
@@ -7954,11 +7962,11 @@
}
visitSwitchCase(ast.SwitchCase node) {
- compiler.internalError(node, 'SsaFromAstMixin.visitSwitchCase.');
+ reporter.internalError(node, 'SsaFromAstMixin.visitSwitchCase.');
}
visitCaseMatch(ast.CaseMatch node) {
- compiler.internalError(node, 'SsaFromAstMixin.visitCaseMatch.');
+ reporter.internalError(node, 'SsaFromAstMixin.visitCaseMatch.');
}
/// Calls [buildTry] inside a synthetic try block with [buildFinally] in the
@@ -8109,7 +8117,7 @@
if (catchBlock.onKeyword != null) {
DartType type = elements.getType(catchBlock.type);
if (type == null) {
- compiler.internalError(catchBlock.type, 'On with no type.');
+ reporter.internalError(catchBlock.type, 'On with no type.');
}
HInstruction condition =
buildIsNode(catchBlock.type, type, unwrappedException);
@@ -8127,7 +8135,7 @@
// condition.
DartType type = elements.getType(declaration.type);
if (type == null) {
- compiler.internalError(catchBlock, 'Catch with unresolved type.');
+ reporter.internalError(catchBlock, 'Catch with unresolved type.');
}
condition = buildIsNode(declaration.type, type, unwrappedException);
push(condition);
@@ -8266,7 +8274,7 @@
}
visitTypeVariable(ast.TypeVariable node) {
- compiler.internalError(node, 'SsaFromAstMixin.visitTypeVariable.');
+ reporter.internalError(node, 'SsaFromAstMixin.visitTypeVariable.');
}
/**
@@ -8403,7 +8411,7 @@
}
visitNode(ast.Node node) {
- builder.compiler.internalError(node, 'Unexpected node.');
+ builder.reporter.internalError(node, 'Unexpected node.');
}
void visitExpression(ast.Node node) {
@@ -8984,7 +8992,7 @@
}
void visitTypedefType(TypedefType type, SsaBuilder builder) {
- DartType unaliased = type.unalias(builder.compiler);
+ DartType unaliased = type.unalias(builder.compiler.resolution);
if (unaliased is TypedefType) throw 'unable to unalias $type';
unaliased.accept(this, builder);
}
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 4ac5881..7b7596e 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -152,12 +152,17 @@
continueAction = new Map<Entity, EntityAction>();
Compiler get compiler => backend.compiler;
+
NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter;
+
CodegenRegistry get registry => work.registry;
+
native.NativeEnqueuer get nativeEnqueuer {
return compiler.enqueuer.codegen.nativeEnqueuer;
}
+ DiagnosticReporter get reporter => compiler.reporter;
+
bool isGenerateAtUseSite(HInstruction instruction) {
return generateAtUseSite.contains(instruction);
}
@@ -935,7 +940,7 @@
currentContainer = oldContainer;
break;
default:
- compiler.internalError(condition.conditionExpression,
+ reporter.internalError(condition.conditionExpression,
'Unexpected loop kind: ${info.kind}.');
}
js.Statement result = loop;
@@ -1336,10 +1341,10 @@
// is responsible for visiting the successor.
if (dominated.isEmpty) return;
if (dominated.length > 2) {
- compiler.internalError(node, 'dominated.length = ${dominated.length}');
+ reporter.internalError(node, 'dominated.length = ${dominated.length}');
}
if (dominated.length == 2 && block != currentGraph.entry) {
- compiler.internalError(node, 'node.block != currentGraph.entry');
+ reporter.internalError(node, 'node.block != currentGraph.entry');
}
assert(dominated[0] == block.successors[0]);
visitBasicBlock(dominated[0]);
@@ -1430,7 +1435,7 @@
visitTry(HTry node) {
// We should never get here. Try/catch/finally is always handled using block
// information in [visitTryInfo].
- compiler.internalError(node, 'visitTry should not be called.');
+ reporter.internalError(node, 'visitTry should not be called.');
}
bool tryControlFlowOperation(HIf node) {
@@ -2703,7 +2708,7 @@
checkString(input, '!==', input.sourceInformation);
return pop();
}
- compiler.internalError(input, 'Unexpected check: $checkedType.');
+ reporter.internalError(input, 'Unexpected check: $checkedType.');
return null;
}
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 4fa2735..ed3f955 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -1312,7 +1312,7 @@
HInstruction convertType(Compiler compiler, DartType type, int kind) {
if (type == null) return this;
- type = type.unalias(compiler);
+ type = type.unalias(compiler.resolution);
// Only the builder knows how to create [HTypeConversion]
// instructions with generics. It has the generic type context
// available.
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 07611f6..741dd32 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -200,6 +200,41 @@
return node;
}
+ ConstantValue getConstantFromType(HInstruction node) {
+ if (node.isValue() && !node.canBeNull()) {
+ ValueTypeMask valueMask = node.instructionType;
+ if (valueMask.value.isBool) {
+ return valueMask.value;
+ }
+ // TODO(het): consider supporting other values (short strings?)
+ }
+ return null;
+ }
+
+ void propagateConstantValueToUses(HInstruction node) {
+ if (node.usedBy.isEmpty) return;
+ ConstantValue value = getConstantFromType(node);
+ if (value != null) {
+ HConstant constant = graph.addConstant(value, compiler);
+ for (HInstruction user in node.usedBy.toList()) {
+ user.changeUse(node, constant);
+ }
+ }
+ }
+
+ HInstruction visitParameterValue(HParameterValue node) {
+ // It is possible for the parameter value to be assigned to in the function
+ // body. If that happens then we should not forward the constant value to
+ // its uses since since the uses reachable from the assignment may have
+ // values in addition to the constant passed to the function.
+ if (node.usedBy.any((user) =>
+ user is HLocalSet && identical(user.local, node))) {
+ return node;
+ }
+ propagateConstantValueToUses(node);
+ return node;
+ }
+
HInstruction visitBoolify(HBoolify node) {
List<HInstruction> inputs = node.inputs;
assert(inputs.length == 1);
@@ -372,6 +407,7 @@
}
HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
+ propagateConstantValueToUses(node);
if (node.isInterceptedCall) {
HInstruction folded = handleInterceptedCall(node);
if (folded != node) return folded;
@@ -437,7 +473,7 @@
bool canInline = true;
signature.forEachParameter((ParameterElement element) {
if (inputPosition++ < inputs.length && canInline) {
- DartType type = element.type.unalias(compiler);
+ DartType type = element.type.unalias(compiler.resolution);
if (type is FunctionType) {
canInline = false;
}
@@ -806,6 +842,7 @@
}
HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) {
+ propagateConstantValueToUses(node);
if (node.isInterceptedCall) {
HInstruction folded = handleInterceptedCall(node);
if (folded != node) return folded;
@@ -867,6 +904,7 @@
}
HInstruction visitInvokeStatic(HInvokeStatic node) {
+ propagateConstantValueToUses(node);
if (node.element == backend.getCheckConcurrentModificationError()) {
if (node.inputs.length == 2) {
HInstruction firstArgument = node.inputs[0];
@@ -1306,13 +1344,6 @@
} else {
markBlockLive(instruction.elseBlock);
}
- } else if (condition.isValue()) {
- ValueTypeMask valueType = condition.instructionType;
- if (valueType.value == true) {
- markBlockLive(instruction.thenBlock);
- } else {
- markBlockLive(instruction.elseBlock);
- }
} else {
visitControlFlow(instruction);
}
diff --git a/pkg/compiler/lib/src/ssa/ssa.dart b/pkg/compiler/lib/src/ssa/ssa.dart
index 77322c9..3ab874f 100644
--- a/pkg/compiler/lib/src/ssa/ssa.dart
+++ b/pkg/compiler/lib/src/ssa/ssa.dart
@@ -15,6 +15,8 @@
import '../common/names.dart' show
Identifiers,
Selectors;
+import '../common/resolution.dart' show
+ Resolution;
import '../common/tasks.dart' show
CompilerTask;
import '../compiler.dart' show
@@ -24,6 +26,8 @@
import '../constants/expressions.dart';
import '../constants/values.dart';
import '../dart_types.dart';
+import '../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import '../diagnostics/invariant.dart' show
invariant;
import '../diagnostics/messages.dart';
diff --git a/pkg/compiler/lib/src/ssa/variable_allocator.dart b/pkg/compiler/lib/src/ssa/variable_allocator.dart
index bd95f58..fb35705 100644
--- a/pkg/compiler/lib/src/ssa/variable_allocator.dart
+++ b/pkg/compiler/lib/src/ssa/variable_allocator.dart
@@ -209,10 +209,12 @@
: liveInstructions = new Map<HBasicBlock, LiveEnvironment>(),
liveIntervals = new Map<HInstruction, LiveInterval>();
+ DiagnosticReporter get reporter => compiler.reporter;
+
void visitGraph(HGraph graph) {
visitPostDominatorTree(graph);
if (!liveInstructions[graph.entry].isEmpty) {
- compiler.internalError(CURRENT_ELEMENT_SPANNABLE, 'LiveIntervalBuilder.');
+ reporter.internalError(CURRENT_ELEMENT_SPANNABLE, 'LiveIntervalBuilder.');
}
}
diff --git a/pkg/compiler/lib/src/string_validator.dart b/pkg/compiler/lib/src/string_validator.dart
index f953ec0..b790774 100644
--- a/pkg/compiler/lib/src/string_validator.dart
+++ b/pkg/compiler/lib/src/string_validator.dart
@@ -15,9 +15,9 @@
import 'util/characters.dart';
class StringValidator {
- final DiagnosticListener listener;
+ final DiagnosticReporter reporter;
- StringValidator(this.listener);
+ StringValidator(this.reporter);
DartString validateInterpolationPart(Token token, StringQuoting quoting,
{bool isFirst: false,
@@ -102,7 +102,7 @@
}
void stringParseError(String message, Token token, int offset) {
- listener.reportErrorMessage(
+ reporter.reportErrorMessage(
token, MessageKind.GENERIC, {'text': "$message @ $offset"});
}
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
index 3aef3a6..ddaf34d 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
@@ -1534,6 +1534,7 @@
visitYield(Yield node) {
node.input = visitExpression(node.input);
+ node.next = visitStatement(node.next);
return node;
}
}
diff --git a/pkg/compiler/lib/src/typechecker.dart b/pkg/compiler/lib/src/typechecker.dart
index ec44ea0..fe017ef 100644
--- a/pkg/compiler/lib/src/typechecker.dart
+++ b/pkg/compiler/lib/src/typechecker.dart
@@ -6,6 +6,8 @@
import 'common/names.dart' show
Identifiers;
+import 'common/resolution.dart' show
+ Resolution;
import 'common/tasks.dart' show
CompilerTask;
import 'compiler.dart' show
@@ -15,7 +17,8 @@
import 'core_types.dart';
import 'dart_types.dart';
import 'diagnostics/diagnostic_listener.dart' show
- DiagnosticMessage;
+ DiagnosticMessage,
+ DiagnosticReporter;
import 'diagnostics/invariant.dart' show
invariant;
import 'diagnostics/messages.dart';
@@ -66,7 +69,7 @@
if (element.isClass) return;
if (element.isTypedef) return;
ResolvedAst resolvedAst = element.resolvedAst;
- compiler.withCurrentElement(element.implementation, () {
+ reporter.withCurrentElement(element.implementation, () {
measure(() {
TypeCheckerVisitor visitor = new TypeCheckerVisitor(
compiler, resolvedAst.elements, compiler.types);
@@ -104,7 +107,7 @@
String get name => element.name;
- DartType computeType(Compiler compiler);
+ DartType computeType(Resolution resolution);
/// Returns [: true :] if the element can be access as an invocation.
bool isCallable(Compiler compiler) {
@@ -116,7 +119,7 @@
}
}
return compiler.types.isAssignable(
- computeType(compiler), compiler.coreTypes.functionType);
+ computeType(compiler.resolution), compiler.coreTypes.functionType);
}
}
@@ -128,7 +131,7 @@
Element get element => member.declarations.first.element;
- DartType computeType(Compiler compiler) => member.type;
+ DartType computeType(Resolution resolution) => member.type;
String toString() => 'MemberAccess($member)';
}
@@ -141,7 +144,7 @@
String get name => 'dynamic';
- DartType computeType(Compiler compiler) => const DynamicType();
+ DartType computeType(Resolution resolution) => const DynamicType();
bool isCallable(Compiler compiler) => true;
@@ -159,14 +162,14 @@
assert(element != null);
}
- DartType computeType(Compiler compiler) {
+ DartType computeType(Resolution resolution) {
if (element.isGetter) {
GetterElement getter = element;
- FunctionType functionType = getter.computeType(compiler);
+ FunctionType functionType = getter.computeType(resolution);
return functionType.returnType;
} else if (element.isSetter) {
SetterElement setter = element;
- FunctionType functionType = setter.computeType(compiler);
+ FunctionType functionType = setter.computeType(resolution);
if (functionType.parameterTypes.length != 1) {
// TODO(johnniwinther,karlklose): this happens for malformed static
// setters. Treat them the same as instance members.
@@ -175,11 +178,11 @@
return functionType.parameterTypes.first;
} else if (element.isTypedef || element.isClass) {
TypeDeclarationElement typeDeclaration = element;
- typeDeclaration.computeType(compiler);
+ typeDeclaration.computeType(resolution);
return typeDeclaration.thisType;
} else {
TypedElement typedElement = element;
- typedElement.computeType(compiler);
+ typedElement.computeType(resolution);
return typedElement.type;
}
}
@@ -197,7 +200,7 @@
assert(type != null);
}
- DartType computeType(Compiler compiler) => type;
+ DartType computeType(Resolution resolution) => type;
String toString() => 'PromotedAccess($element,$type)';
}
@@ -214,7 +217,7 @@
Element get element => type.element;
- DartType computeType(Compiler compiler) => type;
+ DartType computeType(Resolution resolution) => type;
String toString() => 'TypeAccess($type)';
}
@@ -233,7 +236,7 @@
String get name => type.name;
- DartType computeType(Compiler compiler) => compiler.typeClass.rawType;
+ DartType computeType(Resolution resolution) => resolution.coreTypes.typeType;
String toString() => 'TypeLiteralAccess($type)';
}
@@ -248,7 +251,7 @@
String get name => 'call';
- DartType computeType(Compiler compiler) => type;
+ DartType computeType(Resolution resolution) => type;
bool isCallable(Compiler compiler) => true;
@@ -305,6 +308,10 @@
CoreTypes get coreTypes => compiler.coreTypes;
+ DiagnosticReporter get reporter => compiler.reporter;
+
+ Resolution get resolution => compiler.resolution;
+
InterfaceType get intType => coreTypes.intType;
InterfaceType get doubleType => coreTypes.doubleType;
InterfaceType get boolType => coreTypes.boolType;
@@ -394,16 +401,16 @@
reportTypeWarning(Spannable spannable, MessageKind kind,
[Map arguments = const {}]) {
- compiler.reportWarningMessage(spannable, kind, arguments);
+ reporter.reportWarningMessage(spannable, kind, arguments);
}
reportMessage(Spannable spannable, MessageKind kind,
Map arguments,
{bool isHint: false}) {
if (isHint) {
- compiler.reportHintMessage(spannable, kind, arguments);
+ reporter.reportHintMessage(spannable, kind, arguments);
} else {
- compiler.reportWarningMessage(spannable, kind, arguments);
+ reporter.reportWarningMessage(spannable, kind, arguments);
}
}
@@ -411,7 +418,7 @@
if (!reportedTypePromotions.contains(typePromotion)) {
reportedTypePromotions.add(typePromotion);
for (TypePromotionMessage message in typePromotion.messages) {
- compiler.reportHint(message.hint, message.infos);
+ reporter.reportHint(message.hint, message.infos);
}
}
}
@@ -437,9 +444,9 @@
if (node == null) {
final String error = 'Unexpected node: null';
if (lastSeenNode != null) {
- compiler.internalError(lastSeenNode, error);
+ reporter.internalError(lastSeenNode, error);
} else {
- compiler.internalError(executableContext, error);
+ reporter.internalError(executableContext, error);
}
} else {
lastSeenNode = node;
@@ -449,9 +456,9 @@
DartType result = node.accept(this);
analyzingInitializer = previouslyInitializer;
if (result == null) {
- compiler.internalError(node, 'Type is null.');
+ reporter.internalError(node, 'Type is null.');
}
- return result;
+ return _record(node, result);
}
void checkTypePromotion(Node node, TypePromotion typePromotion,
@@ -461,13 +468,13 @@
List<Node> potentialMutationsIn =
elements.getPotentialMutationsIn(node, variable);
if (!potentialMutationsIn.isEmpty) {
- DiagnosticMessage hint = compiler.createMessage(
+ DiagnosticMessage hint = reporter.createMessage(
typePromotion.node,
MessageKind.POTENTIAL_MUTATION,
{'variableName': variableName, 'shownType': typePromotion.type});
List<DiagnosticMessage> infos = <DiagnosticMessage>[];
for (Node mutation in potentialMutationsIn) {
- infos.add(compiler.createMessage(mutation,
+ infos.add(reporter.createMessage(mutation,
MessageKind.POTENTIAL_MUTATION_HERE,
{'variableName': variableName}));
}
@@ -476,13 +483,13 @@
List<Node> potentialMutationsInClosures =
elements.getPotentialMutationsInClosure(variable);
if (!potentialMutationsInClosures.isEmpty) {
- DiagnosticMessage hint = compiler.createMessage(
+ DiagnosticMessage hint = reporter.createMessage(
typePromotion.node,
MessageKind.POTENTIAL_MUTATION_IN_CLOSURE,
{'variableName': variableName, 'shownType': typePromotion.type});
List<DiagnosticMessage> infos = <DiagnosticMessage>[];
for (Node mutation in potentialMutationsInClosures) {
- infos.add(compiler.createMessage(
+ infos.add(reporter.createMessage(
mutation,
MessageKind.POTENTIAL_MUTATION_IN_CLOSURE_HERE,
{'variableName': variableName}));
@@ -493,19 +500,19 @@
List<Node> accesses = elements.getAccessesByClosureIn(node, variable);
List<Node> mutations = elements.getPotentialMutations(variable);
if (!accesses.isEmpty && !mutations.isEmpty) {
- DiagnosticMessage hint = compiler.createMessage(
+ DiagnosticMessage hint = reporter.createMessage(
typePromotion.node,
MessageKind.ACCESSED_IN_CLOSURE,
{'variableName': variableName, 'shownType': typePromotion.type});
List<DiagnosticMessage> infos = <DiagnosticMessage>[];
for (Node access in accesses) {
- infos.add(compiler.createMessage(
+ infos.add(reporter.createMessage(
access,
MessageKind.ACCESSED_IN_CLOSURE_HERE,
{'variableName': variableName}));
}
for (Node mutation in mutations) {
- infos.add(compiler.createMessage(
+ infos.add(reporter.createMessage(
mutation,
MessageKind.POTENTIAL_MUTATION_HERE,
{'variableName': variableName}));
@@ -560,12 +567,12 @@
{bool isConst: false}) {
if (!types.isAssignable(from, to)) {
if (compiler.enableTypeAssertions && isConst) {
- compiler.reportErrorMessage(
+ reporter.reportErrorMessage(
spannable,
MessageKind.NOT_ASSIGNABLE,
{'fromType': from, 'toType': to});
} else {
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
spannable,
MessageKind.NOT_ASSIGNABLE,
{'fromType': from, 'toType': to});
@@ -656,14 +663,14 @@
if (parameter.isInitializingFormal) {
InitializingFormalElement fieldParameter = parameter;
checkAssignable(parameter, parameter.type,
- fieldParameter.fieldElement.computeType(compiler));
+ fieldParameter.fieldElement.computeType(resolution));
}
});
if (node.initializers != null) {
analyze(node.initializers, inInitializer: true);
}
} else {
- FunctionType functionType = element.computeType(compiler);
+ FunctionType functionType = element.computeType(resolution);
returnType = functionType.returnType;
type = functionType;
}
@@ -695,7 +702,7 @@
element.isParameter ||
element.isField,
message: 'Unexpected context element ${element}'));
- return element.computeType(compiler);
+ return element.computeType(resolution);
}
}
@@ -878,13 +885,13 @@
MemberKind memberKind,
{bool isHint: false}) {
return lookupMember(node, type, name, memberKind, null, isHint: isHint)
- .computeType(compiler);
+ .computeType(resolution);
}
void analyzeArguments(Send send, Element element, DartType type,
[LinkBuilder<DartType> argumentTypes]) {
Link<Node> arguments = send.arguments;
- DartType unaliasedType = type.unalias(compiler);
+ DartType unaliasedType = type.unalias(resolution);
if (identical(unaliasedType.kind, TypeKind.FUNCTION)) {
/// Report [warning] including info(s) about the declaration of [element]
@@ -897,17 +904,17 @@
if (declaration == null) {
declaration = type.element;
} else if (type.isTypedef) {
- infos.add(compiler.createMessage(
+ infos.add(reporter.createMessage(
declaration,
MessageKind.THIS_IS_THE_DECLARATION,
{'name': element.name}));
declaration = type.element;
}
if (declaration != null) {
- infos.add(compiler.createMessage(
+ infos.add(reporter.createMessage(
declaration, MessageKind.THIS_IS_THE_METHOD));
}
- compiler.reportWarning(warning, infos);
+ reporter.reportWarning(warning, infos);
}
/// Report a warning on [node] if [argumentType] is not assignable to
@@ -916,7 +923,7 @@
DartType argumentType,
DartType parameterType) {
if (!types.isAssignable(argumentType, parameterType)) {
- reportWarning(compiler.createMessage(
+ reportWarning(reporter.createMessage(
node,
MessageKind.NOT_ASSIGNABLE,
{'fromType': argumentType, 'toType': parameterType}));
@@ -938,7 +945,7 @@
if (namedParameterType == null) {
// TODO(johnniwinther): Provide better information on the called
// function.
- reportWarning(compiler.createMessage(
+ reportWarning(reporter.createMessage(
argument,
MessageKind.NAMED_ARGUMENT_NOT_FOUND,
{'argumentName': argumentName}));
@@ -956,7 +963,7 @@
// TODO(johnniwinther): Provide better information on the
// called function.
- reportWarning(compiler.createMessage(
+ reportWarning(reporter.createMessage(
argument, MessageKind.ADDITIONAL_ARGUMENT));
DartType argumentType = analyze(argument);
@@ -978,7 +985,7 @@
if (parameterTypes.moveNext()) {
// TODO(johnniwinther): Provide better information on the called
// function.
- reportWarning(compiler.createMessage(
+ reportWarning(reporter.createMessage(
send, MessageKind.MISSING_ARGUMENT,
{'argumentType': parameterTypes.current}));
}
@@ -997,7 +1004,7 @@
// analysis.
DartType analyzeInvocation(Send node, ElementAccess elementAccess,
[LinkBuilder<DartType> argumentTypes]) {
- DartType type = elementAccess.computeType(compiler);
+ DartType type = elementAccess.computeType(resolution);
if (elementAccess.isCallable(compiler)) {
analyzeArguments(node, elementAccess.element, type, argumentTypes);
} else {
@@ -1006,7 +1013,7 @@
analyzeArguments(node, elementAccess.element, const DynamicType(),
argumentTypes);
}
- type = type.unalias(compiler);
+ type = type.unalias(resolution);
if (identical(type.kind, TypeKind.FUNCTION)) {
FunctionType funType = type;
return funType.returnType;
@@ -1086,7 +1093,7 @@
} else if (element.isGetter || element.isSetter) {
return createResolvedAccess(node, name, element);
} else {
- compiler.internalError(element,
+ reporter.internalError(element,
'Unexpected element kind ${element.kind}.');
return null;
}
@@ -1117,9 +1124,9 @@
{bool lookupClassMember: false}) {
DartType type =
computeAccess(node, name, element, memberKind,
- lookupClassMember: lookupClassMember).computeType(compiler);
+ lookupClassMember: lookupClassMember).computeType(resolution);
if (type == null) {
- compiler.internalError(node, 'Type is null on access of $name on $node.');
+ reporter.internalError(node, 'Type is null on access of $name on $node.');
}
return type;
}
@@ -1159,6 +1166,23 @@
}
+ static bool _fyiShown = false;
+ DartType _record(Node node, DartType type) {
+ if (node is! Expression) return type;
+ if (const bool.fromEnvironment('send_stats') &&
+ executableContext != null &&
+ // TODO(sigmund): enable also in core libs.
+ !executableContext.library.isPlatformLibrary && !type.isDynamic) {
+ if (!_fyiShown) {
+ print('FYI experiment to collect send stats is on: '
+ 'caching types of expressions');
+ _fyiShown = true;
+ }
+ elements.typesCache[node] = type;
+ }
+ return type;
+ }
+
DartType visitSend(Send node) {
Element element = elements[node];
@@ -1221,7 +1245,7 @@
if (!types.isMoreSpecific(shownType, knownType)) {
String variableName = variable.name;
if (!types.isSubtype(shownType, knownType)) {
- typePromotion.addHint(compiler.createMessage(
+ typePromotion.addHint(reporter.createMessage(
node,
MessageKind.NOT_MORE_SPECIFIC_SUBTYPE,
{'variableName': variableName,
@@ -1231,7 +1255,7 @@
DartType shownTypeSuggestion =
computeMoreSpecificType(shownType, knownType);
if (shownTypeSuggestion != null) {
- typePromotion.addHint(compiler.createMessage(
+ typePromotion.addHint(reporter.createMessage(
node,
MessageKind.NOT_MORE_SPECIFIC_SUGGESTION,
{'variableName': variableName,
@@ -1239,7 +1263,7 @@
'shownTypeSuggestion': shownTypeSuggestion,
'knownType': knownType}));
} else {
- typePromotion.addHint(compiler.createMessage(
+ typePromotion.addHint(reporter.createMessage(
node,
MessageKind.NOT_MORE_SPECIFIC,
{'variableName': variableName,
@@ -1334,7 +1358,7 @@
} else if (node.isPropertyAccess) {
ElementAccess access =
computeAccess(node, selector.source, element, MemberKind.GETTER);
- return access.computeType(compiler);
+ return access.computeType(resolution);
} else if (node.isFunctionObjectInvocation) {
return unhandledExpression();
} else {
@@ -1528,7 +1552,7 @@
case '<<=': operatorName = '<<'; break;
case '>>=': operatorName = '>>'; break;
default:
- compiler.internalError(node, 'Unexpected assignment operator $name.');
+ reporter.internalError(node, 'Unexpected assignment operator $name.');
}
if (node.isIndex) {
// base[key] o= value for some operator o.
@@ -1578,7 +1602,7 @@
DartType computeConstructorType(ConstructorElement constructor,
DartType type) {
if (Elements.isUnresolved(constructor)) return const DynamicType();
- DartType constructorType = constructor.computeType(compiler);
+ DartType constructorType = constructor.computeType(resolution);
if (identical(type.kind, TypeKind.INTERFACE)) {
if (constructor.isSynthesized) {
// TODO(johnniwinther): Remove this when synthesized constructors handle
@@ -1732,6 +1756,17 @@
SendSet initialization = definition;
DartType initializer = analyzeNonVoid(initialization.arguments.head);
checkAssignable(initialization.assignmentOperator, initializer, type);
+ // TODO(sigmund): explore inferring a type for `var` using the RHS (like
+ // DDC does), for example:
+ // if (node.type == null && node.modifiers.isVar &&
+ // !initializer.isDynamic) {
+ // var variable = elements[definition];
+ // if (variable != null) {
+ // var typePromotion = new TypePromotion(
+ // node, variable, initializer);
+ // registerKnownTypePromotion(typePromotion);
+ // }
+ // }
}
}
return const StatementType();
@@ -1801,7 +1836,7 @@
DartType elementType = computeForInElementType(node);
DartType expressionType = analyze(node.expression);
// TODO(johnniwinther): Move this to _CompilerCoreTypes.
- compiler.streamClass.ensureResolved(compiler);
+ compiler.streamClass.ensureResolved(resolution);
DartType streamOfDynamic = coreTypes.streamType();
if (!types.isAssignable(expressionType, streamOfDynamic)) {
reportMessage(node.expression,
@@ -1936,7 +1971,7 @@
}
unreferencedFields.addAll(enumValues.values);
if (!unreferencedFields.isEmpty) {
- compiler.reportWarningMessage(
+ reporter.reportWarningMessage(
node, MessageKind.MISSING_ENUM_CASES,
{'enumType': expressionType,
'enumValues': unreferencedFields.map(
@@ -1973,7 +2008,7 @@
}
visitNode(Node node) {
- compiler.internalError(node,
+ reporter.internalError(node,
'Unexpected node ${node.getObjectDescription()} in the type checker.');
}
}
diff --git a/pkg/compiler/lib/src/types/constants.dart b/pkg/compiler/lib/src/types/constants.dart
index e036901..0a303d4 100644
--- a/pkg/compiler/lib/src/types/constants.dart
+++ b/pkg/compiler/lib/src/types/constants.dart
@@ -7,8 +7,13 @@
import '../compiler.dart' show
Compiler;
import '../constants/values.dart';
+import '../diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
+import '../diagnostics/spannable.dart' show
+ CURRENT_ELEMENT_SPANNABLE;
+import '../js_backend/js_backend.dart' show
+ SyntheticConstantKind;
import 'types.dart';
-import '../js_backend/js_backend.dart' show SyntheticConstantKind;
/// Computes the [TypeMask] for the constant [value].
TypeMask computeTypeMask(Compiler compiler, ConstantValue value) {
@@ -58,7 +63,8 @@
case SyntheticConstantKind.NAME:
return compiler.typesTask.stringType;
default:
- compiler.internalError(compiler.currentElement,
+ DiagnosticReporter reporter = compiler.reporter;
+ reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
"Unexpected DummyConstantKind.");
return null;
}
diff --git a/pkg/compiler/lib/src/types/types.dart b/pkg/compiler/lib/src/types/types.dart
index 9858a6e..6b18981 100644
--- a/pkg/compiler/lib/src/types/types.dart
+++ b/pkg/compiler/lib/src/types/types.dart
@@ -10,13 +10,13 @@
CompilerTask;
import '../compiler.dart' show
Compiler;
+import '../constants/values.dart' show
+ PrimitiveConstantValue;
import '../diagnostics/invariant.dart' show
invariant;
import '../diagnostics/spannable.dart' show
NO_LOCATION_SPANNABLE;
import '../elements/elements.dart';
-import '../inferrer/concrete_types_inferrer.dart' show
- ConcreteTypesInferrer;
import '../inferrer/type_graph_inferrer.dart' show
TypeGraphInferrer;
import '../tree/tree.dart';
@@ -64,15 +64,11 @@
final String name = 'Type inference';
final ClassWorld classWorld;
TypesInferrer typesInferrer;
- ConcreteTypesInferrer concreteTypesInferrer;
TypesTask(Compiler compiler)
: this.classWorld = compiler.world,
super(compiler) {
typesInferrer = new TypeGraphInferrer(compiler);
- if (compiler.enableConcreteTypeInference) {
- concreteTypesInferrer = new ConcreteTypesInferrer(compiler);
- }
}
TypeMask dynamicTypeCache;
@@ -284,15 +280,6 @@
void onResolutionComplete(Element mainElement) {
measure(() {
typesInferrer.analyzeMain(mainElement);
- if (concreteTypesInferrer != null) {
- bool success = concreteTypesInferrer.analyzeMain(mainElement);
- if (!success) {
- // If the concrete type inference bailed out, we pretend it didn't
- // happen. In the future we might want to record that it failed but
- // use the partial results as hints.
- concreteTypesInferrer = null;
- }
- }
});
typesInferrer.clear();
}
@@ -303,11 +290,7 @@
TypeMask getGuaranteedTypeOfElement(Element element) {
return measure(() {
TypeMask guaranteedType = typesInferrer.getTypeOfElement(element);
- return (concreteTypesInferrer == null)
- ? guaranteedType
- : intersection(guaranteedType,
- concreteTypesInferrer.getTypeOfElement(element),
- element);
+ return guaranteedType;
});
}
@@ -315,11 +298,7 @@
return measure(() {
TypeMask guaranteedType =
typesInferrer.getReturnTypeOfElement(element);
- return (concreteTypesInferrer == null)
- ? guaranteedType
- : intersection(guaranteedType,
- concreteTypesInferrer.getReturnTypeOfElement(element),
- element);
+ return guaranteedType;
});
}
@@ -330,11 +309,7 @@
TypeMask getGuaranteedTypeOfNode(owner, node) {
return measure(() {
TypeMask guaranteedType = typesInferrer.getTypeOfNode(owner, node);
- return (concreteTypesInferrer == null)
- ? guaranteedType
- : intersection(guaranteedType,
- concreteTypesInferrer.getTypeOfNode(owner, node),
- node);
+ return guaranteedType;
});
}
@@ -345,12 +320,7 @@
return measure(() {
TypeMask guaranteedType =
typesInferrer.getTypeOfSelector(selector, mask);
- return (concreteTypesInferrer == null)
- ? guaranteedType
- : intersection(
- guaranteedType,
- concreteTypesInferrer.getTypeOfSelector(selector, mask),
- selector);
+ return guaranteedType;
});
}
}
diff --git a/pkg/compiler/lib/src/types/value_type_mask.dart b/pkg/compiler/lib/src/types/value_type_mask.dart
index 737be5e..72c5af2 100644
--- a/pkg/compiler/lib/src/types/value_type_mask.dart
+++ b/pkg/compiler/lib/src/types/value_type_mask.dart
@@ -6,7 +6,7 @@
class ValueTypeMask extends ForwardingTypeMask {
final TypeMask forwardTo;
- final value;
+ final PrimitiveConstantValue value;
ValueTypeMask(this.forwardTo, this.value);
@@ -44,6 +44,6 @@
}
String toString() {
- return 'Value mask: [$value] type: $forwardTo';
+ return 'Value mask: [${value.unparse()}] type: $forwardTo';
}
}
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/universe/universe.dart b/pkg/compiler/lib/src/universe/universe.dart
index ccb402b..6e572b5 100644
--- a/pkg/compiler/lib/src/universe/universe.dart
+++ b/pkg/compiler/lib/src/universe/universe.dart
@@ -6,30 +6,21 @@
import 'dart:collection';
-import '../common/names.dart' show
- Identifiers,
- Names,
- Selectors;
+import '../common/resolution.dart' show
+ Resolution;
import '../compiler.dart' show
Compiler;
import '../diagnostics/invariant.dart' show
invariant;
-import '../diagnostics/spannable.dart' show
- SpannableAssertionFailure;
import '../elements/elements.dart';
import '../dart_types.dart';
-import '../tree/tree.dart';
-import '../types/types.dart';
import '../util/util.dart';
import '../world.dart' show
ClassWorld,
World;
-import 'call_structure.dart';
import 'selector.dart' show
Selector;
-import 'function_set.dart';
-import 'side_effects.dart';
class UniverseSelector {
final Selector selector;
@@ -393,7 +384,7 @@
}
DartType registerIsCheck(DartType type, Compiler compiler) {
- type = type.unalias(compiler);
+ type = type.unalias(compiler.resolution);
// Even in checked mode, type annotations for return type and argument
// types do not imply type checks, so there should never be a check
// against the type variable of a typedef.
diff --git a/pkg/compiler/lib/src/use_unused_api.dart b/pkg/compiler/lib/src/use_unused_api.dart
index d2e8648..7a9c03c 100644
--- a/pkg/compiler/lib/src/use_unused_api.dart
+++ b/pkg/compiler/lib/src/use_unused_api.dart
@@ -28,7 +28,6 @@
import 'elements/modelx.dart' as modelx;
import 'elements/visitor.dart' as elements_visitor;
import 'filenames.dart' as filenames;
-import 'inferrer/concrete_types_inferrer.dart' as concrete_types_inferrer;
import 'inferrer/type_graph_inferrer.dart' as type_graph_inferrer;
import 'io/line_column_provider.dart' as io;
import 'io/source_map_builder.dart' as io;
@@ -69,7 +68,6 @@
useJsNode(new js.ArrayHole());
useJsOther(new js.SimpleJavaScriptPrintingContext());
useJsBackend(null);
- useConcreteTypesInferrer(null);
useColor();
useFilenames();
useSsa(null);
@@ -230,10 +228,6 @@
backend.getGeneratedCode(null);
}
-useConcreteTypesInferrer(concrete_types_inferrer.ConcreteTypesInferrer c) {
- c.debug();
-}
-
useColor() {
colors.white(null);
colors.blue(null);
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index 502ea8e..46cc830 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -13,6 +13,8 @@
import 'compiler.dart' show
Compiler;
import 'dart_types.dart';
+import 'diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
import 'diagnostics/invariant.dart' show
invariant;
import 'elements/elements.dart' show
@@ -87,6 +89,10 @@
/// including [cls] itself.
Iterable<ClassElement> strictSubclassesOf(ClassElement cls);
+ /// Returns an iterable over the directly instantiated that implement [cls]
+ /// possibly including [cls] itself, if it is live.
+ Iterable<ClassElement> subtypesOf(ClassElement cls);
+
/// Returns an iterable over the live classes that implement [cls] _not_
/// including [cls] if it is live.
Iterable<ClassElement> strictSubtypesOf(ClassElement cls);
@@ -218,6 +224,19 @@
}
/// Returns an iterable over the directly instantiated that implement [cls]
+ /// possibly including [cls] itself, if it is live.
+ Iterable<ClassElement> subtypesOf(ClassElement cls) {
+ ClassSet classSet = _classSets[cls.declaration];
+ if (classSet == null) {
+ return const <ClassElement>[];
+ } else {
+ return classSet.subtypes(
+ includeIndirectlyInstantiated: false,
+ includeUninstantiated: false);
+ }
+ }
+
+ /// Returns an iterable over the directly instantiated that implement [cls]
/// _not_ including [cls].
Iterable<ClassElement> strictSubtypesOf(ClassElement cls) {
ClassSet classSet = _classSets[cls.declaration];
@@ -417,6 +436,8 @@
this.compiler = compiler,
alreadyPopulated = compiler.cacheStrategy.newSet();
+ DiagnosticReporter get reporter => compiler.reporter;
+
/// Called to add [cls] to the set of known classes.
///
/// This ensures that class hierarchy queries can be performed on [cls] and
@@ -500,7 +521,7 @@
}
assert(cls.isDeclaration);
if (!cls.isResolved) {
- compiler.internalError(cls, 'Class "${cls.name}" is not resolved.');
+ reporter.internalError(cls, 'Class "${cls.name}" is not resolved.');
}
updateClassHierarchyNodeForClass(cls, directlyInstantiated: true);
@@ -658,11 +679,6 @@
return elementsThatCannotThrow.contains(element);
}
- void registerImplicitSuperCall(Registry registry,
- FunctionElement superConstructor) {
- registry.registerDependency(superConstructor);
- }
-
void registerMightBePassedToApply(Element element) {
functionsThatMightBePassedToApply.add(element);
}
diff --git a/pkg/compiler/pubspec.yaml b/pkg/compiler/pubspec.yaml
index 8e74b36..f396ed0 100644
--- a/pkg/compiler/pubspec.yaml
+++ b/pkg/compiler/pubspec.yaml
@@ -11,11 +11,11 @@
path: ../../sdk/lib/_internal/js_runtime
sdk_library_metadata:
path: ../../sdk/lib/_internal/sdk_library_metadata
- dart2js_info: ^0.0.2
+ dart2js_info:
+ path: ../../../../dart2js_info
lookup_map:
path: ../lookup_map
-
# Uncomment if running gclient, so you can depend directly on the downloaded
# versions of dart2js's transitive dependencies:
#
diff --git a/pkg/compiler/tool/track_memory.dart b/pkg/compiler/tool/track_memory.dart
new file mode 100644
index 0000000..effd92f
--- /dev/null
+++ b/pkg/compiler/tool/track_memory.dart
@@ -0,0 +1,193 @@
+// Copyright (c) 2015, 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.
+
+/// A script to track the high water-mark of memory usage of an application.
+/// To monitor how much memory dart2js is using, run dart2js as follows:
+///
+/// DART_VM_OPTIONS=--observe dart2js ...
+///
+/// and run this script immediately after.
+library compiler.tool.track_memory;
+
+import 'dart:math' show max;
+import 'dart:io';
+import 'dart:async';
+
+import 'dart:convert';
+
+/// Socket to connect to the vm observatory service.
+WebSocket socket;
+
+main(args) async {
+ _printHeader();
+ _showProgress(0, 0, 0, 0);
+ try {
+ var port = args.length > 0 ? int.parse(args[0]) : 8181;
+ socket = await WebSocket.connect('ws://localhost:$port/ws');
+ socket.listen(_handleResponse);
+ await _resumeMainIsolateIfPaused();
+ _streamListen('GC');
+ _streamListen('Isolate');
+ _streamListen('Debug');
+ } catch (e) {
+ // TODO(sigmund): add better error messages, maybe option to retry.
+ print('\n${_RED}error${_NONE}: $e');
+ print('usage:\n'
+ ' Start a Dart process with the --observe flag (and optionally '
+ 'the --pause_isolates_on_start flag), then invoke:\n'
+ ' dart tool/track_memory.dart [<port>]\n'
+ ' by default port is 8181');
+ }
+}
+
+/// Internal counter for request ids.
+int _requestId = 0;
+Map _pendingResponses = {};
+
+/// Subscribe to listen to a vm service data stream.
+_streamListen(String streamId) =>
+ _sendMessage('streamListen', {'streamId': '$streamId'});
+
+/// Tell the vm service to resume a specific isolate.
+_resumeIsolate(String isolateId) =>
+ _sendMessage('resume', {'isolateId': '$isolateId'});
+
+/// Resumes the main isolate if it was paused on start.
+_resumeMainIsolateIfPaused() async {
+ var vm = await _sendMessage('getVM');
+ var isolateId = vm['isolates'][0]['id'];
+ var isolate = await _sendMessage('getIsolate', {'isolateId': isolateId});
+ bool isPaused = isolate['pauseEvent']['kind'] == 'PauseStart';
+ if (isPaused) _resumeIsolate(isolateId);
+}
+
+/// Send a message to the vm service.
+Future _sendMessage(String method, [Map args= const {}]) {
+ var id = _requestId++;
+ _pendingResponses[id] = new Completer();
+ socket.add(JSON.encode({
+ 'jsonrpc': '2.0',
+ 'id': '$id',
+ 'method': '$method',
+ 'params': args,
+ }));
+ return _pendingResponses[id].future;
+}
+
+/// Handle all responses
+_handleResponse(String s) {
+ var json = JSON.decode(s);
+ if (json['method'] != 'streamNotify') {
+ var id = json['id'];
+ if (id is String) id = int.parse(id);
+ if (id == null || !_pendingResponses.containsKey(id)) return;
+ _pendingResponses.remove(id).complete(json['result']);
+ return;
+ }
+
+ // isolate pauses on exit automatically. We detect this to stop and exit.
+ if (json['params']['streamId'] == 'Debug') {
+ _handleDebug(json);
+ } else if (json['params']['streamId'] == 'Isolate') {
+ _handleIsolate(json);
+ } else if (json['params']['streamId'] == 'GC') {
+ _handleGC(json);
+ }
+}
+
+/// Handle a `Debug` notification.
+_handleDebug(Map json) {
+ var isolateId = json['params']['event']['isolate']['id'];
+ if (json['params']['event']['kind'] == 'PauseStart') {
+ _resumeIsolate(isolateId);
+ } if (json['params']['event']['kind'] == 'PauseExit') {
+ _resumeIsolate(isolateId);
+ }
+}
+
+/// Handle a `Isolate` notification.
+_handleIsolate(Map json) {
+ if (json['params']['event']['kind'] == 'IsolateExit') {
+ print('');
+ socket.close();
+ }
+}
+
+/// Handle a `GC` notification.
+_handleGC(Map json) {
+ // print(new JsonEncoder.withIndent(' ').convert(json));
+ var event = json['params']['event'];
+ var newUsed = event['new']['used'];
+ var newCapacity = event['new']['capacity'];
+ var oldUsed = event['old']['used'];
+ var oldCapacity = event['old']['capacity'];
+ _showProgress(newUsed, newCapacity, oldUsed, oldCapacity);
+}
+
+int lastNewUsed = 0;
+int lastOldUsed = 0;
+int lastMaxUsed = 0;
+int lastNewCapacity = 0;
+int lastOldCapacity = 0;
+int lastMaxCapacity = 0;
+
+/// Shows a status line with use/capacity numbers for new/old/total/max,
+/// highlighting in red when capacity increases, and in green when it decreases.
+_showProgress(newUsed, newCapacity, oldUsed, oldCapacity) {
+ var sb = new StringBuffer();
+ sb.write('\r '); // replace the status-line in place
+ _writeNumber(sb, lastNewUsed, newUsed);
+ _writeNumber(sb, lastNewCapacity, newCapacity, color: true);
+
+ sb.write(' | ');
+ _writeNumber(sb, lastOldUsed, oldUsed);
+ _writeNumber(sb, lastOldCapacity, oldCapacity, color: true);
+
+ sb.write(' | ');
+ _writeNumber(sb, lastNewUsed + lastOldUsed, newUsed + oldUsed);
+ _writeNumber(sb, lastNewCapacity + lastOldCapacity, newCapacity + oldCapacity,
+ color: true);
+
+ sb.write(' | ');
+ var maxUsed = max(lastMaxUsed, newUsed + oldUsed);
+ var maxCapacity = max(lastMaxCapacity, newCapacity + oldCapacity);
+ _writeNumber(sb, lastMaxUsed, maxUsed);
+ _writeNumber(sb, lastMaxCapacity, maxCapacity, color: true);
+ stdout.write('$sb');
+
+ lastNewUsed = newUsed;
+ lastOldUsed = oldUsed;
+ lastMaxUsed = maxUsed;
+ lastNewCapacity = newCapacity;
+ lastOldCapacity = oldCapacity;
+ lastMaxCapacity = maxCapacity;
+}
+
+const mega = 1024 * 1024;
+_writeNumber(sb, before, now, {color: false}) {
+ if (color) sb.write(before < now ? _RED : before > now ? _GREEN : '');
+ var string;
+ if (now < 1024) {
+ string = ' ${now}b';
+ } else if (now < mega) {
+ string = ' ${(now/1024).toStringAsFixed(0)}K';
+ } else {
+ string = ' ${(now/mega).toStringAsFixed(1)}M';
+ }
+ if (string.length < 10) string = '${' ' * (8 - string.length)}$string';
+ sb.write(string);
+ if (color) sb.write(before != now ? _NONE : '');
+ return before > now;
+}
+
+_printHeader() {
+ print('''
+Memory usage:
+ new generation | old generation | total | max
+ in-use/capacity | in-use/capacity | in-use/capacity | in-use/capacity ''');
+}
+
+const _RED = '\x1b[31m';
+const _GREEN = '\x1b[32m';
+const _NONE = '\x1b[0m';
diff --git a/pkg/dart2js_incremental/lib/library_updater.dart b/pkg/dart2js_incremental/lib/library_updater.dart
index 3499f4f..eb4bbd1 100644
--- a/pkg/dart2js_incremental/lib/library_updater.dart
+++ b/pkg/dart2js_incremental/lib/library_updater.dart
@@ -74,11 +74,7 @@
import 'package:compiler/src/js/js.dart' as jsAst;
import 'package:compiler/src/js_emitter/js_emitter.dart' show
- ClassBuilder,
- ClassEmitter,
CodeEmitterTask,
- ContainerBuilder,
- MemberInfo,
computeMixinClass;
import 'package:compiler/src/js_emitter/full_emitter/emitter.dart'
@@ -687,7 +683,7 @@
PartialFunctionElement before,
PartialFunctionElement after) {
FunctionExpression node =
- after.parseNode(compiler).asFunctionExpression();
+ after.parseNode(compiler.parsing).asFunctionExpression();
if (node == null) {
return cannotReuse(after, "Not a function expression: '$node'");
}
@@ -709,7 +705,7 @@
Token diffToken,
PartialClassElement before,
PartialClassElement after) {
- ClassNode node = after.parseNode(compiler).asClassNode();
+ ClassNode node = after.parseNode(compiler.parsing).asClassNode();
if (node == null) {
return cannotReuse(after, "Not a ClassNode: '$node'");
}
diff --git a/pkg/pkg.status b/pkg/pkg.status
index bd76884..40e35e9 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -165,3 +165,33 @@
[ $compiler == dart2js && $cps_ir ]
lookup_map/test/lookup_map_test: RuntimeError # $async$temp1.get$tests is not a function
+
+[ $compiler == dart2js && $cps_ir && $host_checked ]
+analyzer/test/src/task/html_test: Crash # Issue 24485
+analyzer/test/src/task/incremental_element_builder_test: Crash # Issue 24485
+analyzer/test/src/task/strong_mode_test: Crash # Issue 24485
+analyzer/test/src/task/inputs_test: Crash # Issue 24485
+analyzer/test/src/task/model_test: Crash # Issue 24485
+analyzer/test/src/task/manager_test: Crash # Issue 24485
+analyzer/test/generated/static_warning_code_test: Crash # Issue 24485
+analyzer/test/generated/utilities_test: Crash # Issue 24485
+analyzer/test/src/task/dart_test: Crash # Issue 24485
+analyzer/test/src/task/html_work_manager_test: Crash # Issue 24485
+analyzer/test/src/task/general_test: Crash # Issue 24485
+analyzer/test/src/task/dart_work_manager_test: Crash # Issue 24485
+analyzer/test/generated/parser_test: Crash # Issue 24485
+analyzer/test/generated/static_type_warning_code_test: Crash # Issue 24485
+analyzer/test/src/context/cache_test: Crash # Issue 24485
+analyzer/test/generated/incremental_resolver_test: Crash # Issue 24485
+analyzer/test/generated/element_test: Crash # Issue 24485
+analyzer/test/generated/incremental_scanner_test: Crash # Issue 24485
+analyzer/test/generated/scanner_test: Crash # Issue 24485
+analyzer/test/src/task/driver_test: Crash # Issue 24485
+analyzer/test/generated/compile_time_error_code_test: Crash # Issue 24485
+analyzer/test/generated/non_error_resolver_test: Crash # Issue 24485
+analyzer/test/generated/resolver_test: Crash # Issue 24485
+analyzer/test/generated/source_factory_test: Crash # Issue 24485
+analyzer/test/generated/ast_test: Crash # Issue 24485
+analyzer/test/src/context/context_test: Crash # Issue 24485
+analyzer/test/enum_test: Crash # Issue 24485
+analyzer/test/generated/all_the_rest_test: Crash # Issue 24485
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index 253d8d7..1185ee4 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -205,6 +205,8 @@
"*secure_socket.h",
"*filter_unsupported.cc",
"*io_service_unsupported.cc",
+ "*io_service.cc",
+ "*io_service.h",
"*_test.cc",
"*_test.h",
"*dbg*",
diff --git a/runtime/bin/bin.gypi b/runtime/bin/bin.gypi
index 78a71e7..1777513 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -137,6 +137,9 @@
'log_macos.cc',
'log_win.cc',
],
+ 'defines': [
+ 'LEGACY_DEBUG_PROTOCOL_ENABLED',
+ ],
'includes': [
'builtin_impl_sources.gypi',
'../platform/platform_sources.gypi',
@@ -737,6 +740,7 @@
'../vm/vm_sources.gypi',
],
'defines': [
+ 'LEGACY_DEBUG_PROTOCOL_ENABLED',
'TESTING',
],
# Only include _test.[cc|h] files.
diff --git a/runtime/bin/builtin.dart b/runtime/bin/builtin.dart
index feb26a9..8ee15ce 100644
--- a/runtime/bin/builtin.dart
+++ b/runtime/bin/builtin.dart
@@ -71,8 +71,7 @@
SendPort _loadPort;
// The receive port for a load request. Multiple sources can be fetched in
// a single load request.
-RawReceivePort _receivePort;
-SendPort _sendPort;
+RawReceivePort _dataPort;
// A request id valid only for the current load cycle (while the number of
// outstanding load requests is greater than 0). Can be reset when loading is
// completed.
@@ -125,17 +124,16 @@
// Class collecting all of the information about a particular load request.
class _LoadRequest {
- final int _id;
+ final int _id = _reqId++;
final int _tag;
final String _uri;
final Uri _resourceUri;
final _context;
- _LoadRequest(this._id,
- this._tag,
- this._uri,
- this._resourceUri,
- this._context);
+ _LoadRequest(this._tag, this._uri, this._resourceUri, this._context) {
+ assert(_reqMap[_id] == null);
+ _reqMap[_id] = this;
+ }
toString() => "LoadRequest($_id, $_tag, $_uri, $_resourceUri, $_context)";
}
@@ -320,13 +318,13 @@
}
}
- if (!_pendingLoads()) {
+ if (!_pendingLoads() && (_dataPort != null)) {
+ // Close the _dataPort now that there are no more requests outstanding.
if (_traceLoading) {
_log("Closing loading port.");
}
- _receivePort.close();
- _receivePort = null;
- _sendPort = null;
+ _dataPort.close();
+ _dataPort = null;
_reqId = 0;
_signalDoneLoading();
}
@@ -367,33 +365,26 @@
void _startLoadRequest(int tag, String uri, Uri resourceUri, context) {
- if (_receivePort == null) {
+ if (_dataPort == null) {
if (_traceLoading) {
_log("Initializing load port.");
}
- assert(_receivePort == null);
- assert(_sendPort == null);
- _receivePort = new RawReceivePort(_handleLoaderReply);
- _sendPort = _receivePort.sendPort;
+ assert(_dataPort == null);
+ _dataPort = new RawReceivePort(_handleLoaderReply);
}
// Register the load request and send it to the VM service isolate.
- var curId = _reqId++;
+ var req = new _LoadRequest(tag, uri, resourceUri, context);
- assert(_reqMap[curId] == null);
- _reqMap[curId] = new _LoadRequest(curId, tag, uri, resourceUri, context);
-
- assert(_receivePort != null);
- assert(_sendPort != null);
-
+ assert(_dataPort != null);
var msg = new List(4);
- msg[0] = _sendPort;
+ msg[0] = _dataPort.sendPort;
msg[1] = _traceLoading;
- msg[2] = curId;
+ msg[2] = req._id;
msg[3] = resourceUri.toString();
_loadPort.send(msg);
if (_traceLoading) {
- _log("Loading of $resourceUri for $uri started with id: $curId. "
+ _log("Loading of $resourceUri for $uri started with id: ${req._id}. "
"${_reqMap.length} requests remaining, "
"${_pendingPackageLoads.length} packages pending.");
}
@@ -434,17 +425,10 @@
// Resolve all pending package loads now that we know how to resolve them.
while (_pendingPackageLoads.length > 0) {
+ // Order does not matter as we queue all of the requests up right now.
var req = _pendingPackageLoads.removeLast();
- if (req != null) {
- if (_traceLoading) {
- _log("Handling deferred load request: $req");
- }
- _loadPackage(req._tag, req._uri, req._resourceUri, req._context);
- } else {
- if (_traceLoading) {
- _log("Skipping dummy deferred request.");
- }
- }
+ // Call the registered closure, to handle the delayed action.
+ req();
}
// Reset the pending package loads to empty. So that we eventually can
// finish loading.
@@ -516,7 +500,13 @@
// Signal that the resolution of the packages map has started. But in this
// case it is not tied to a particular request.
- _pendingPackageLoads.add(null);
+ _pendingPackageLoads.add(() {
+ // Nothing to be done beyond registering that there is pending package
+ // resolution requested by having an empty entry.
+ if (_traceLoading) {
+ _log("Skipping dummy deferred request.");
+ }
+ });
if (_traceLoading) {
_log("Requested packages map at '$packagesUri'.");
@@ -553,8 +543,10 @@
}
// Wrap inside a _LoadError unless we are already propagating a previously
// seen _LoadError.
- var error = (e is _LoadError) ? e : new _LoadError(e.toString());
- _asyncLoadError(tag, uri, context, error, s);
+ var error = (e is _LoadError) ? e : new _LoadError(uri, e.toString());
+ // Register a dummy load request and fail to load it.
+ var req = new _LoadRequest(tag, uri, resourceUri, context);
+ _asyncLoadError(req, error, s);
}
}
@@ -570,8 +562,15 @@
// request for package resolution & loading.
_requestPackagesMap();
}
- var req = new _LoadRequest(-1, tag, uri, resourceUri, context);
- _pendingPackageLoads.add(req);
+ // Register the action of loading this package once the package resolution
+ // is ready.
+ _pendingPackageLoads.add(() {
+ if (_traceLoading) {
+ _log("Handling deferred package request: "
+ "$tag, $uri, $resourceUri, $context");
+ }
+ _loadPackage(tag, uri, resourceUri, context);
+ });
if (_traceLoading) {
_log("Pending package load of '$uri': "
"${_pendingPackageLoads.length} pending");
@@ -635,6 +634,48 @@
}
+// Handling of access to the package root or package map from user code.
+_triggerPackageResolution(action) {
+ if (_packagesReady()) {
+ // Packages are ready. Execute the action now.
+ action();
+ } else {
+ if (_pendingPackageLoads.isEmpty) {
+ // Package resolution has not been setup yet, and this is the first
+ // request for package resolution & loading.
+ _requestPackagesMap();
+ }
+ // Register the action for when the package resolution is ready.
+ _pendingPackageLoads.add(action);
+ }
+}
+
+
+Future<Uri> _getPackageRoot() {
+ if (_traceLoading) {
+ _log("Request for package root from user code.");
+ }
+ var completer = new Completer<Uri>();
+ _triggerPackageResolution(() {
+ completer.complete(_packageRoot);
+ });
+ return completer.future;
+}
+
+
+Future<Map<String, Uri>> _getPackageMap() {
+ if (_traceLoading) {
+ _log("Request for package map from user code.");
+ }
+ var completer = new Completer<Map<String, Uri>>();
+ _triggerPackageResolution(() {
+ var result = (_packageMap != null) ? new Map.from(_packageMap) : {};
+ completer.complete(result);
+ });
+ return completer.future;
+}
+
+
// Handling of Resource class by dispatching to the load port.
Future<List<int>> _resourceReadAsBytes(Uri uri) {
var completer = new Completer<List<int>>();
@@ -762,4 +803,6 @@
_setupHooks() {
_setupCompleted = true;
VMLibraryHooks.resourceReadAsBytes = _resourceReadAsBytes;
+ VMLibraryHooks.getPackageRoot = _getPackageRoot;
+ VMLibraryHooks.getPackageMap = _getPackageMap;
}
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index 6e27f82..33f59d6 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -29,6 +29,7 @@
static const int kBufferSize = 64 * 1024;
static const int kStdOverlappedBufferSize = 16 * 1024;
+static const int kMaxUDPPackageLength = 64 * 1024;
OverlappedBuffer* OverlappedBuffer::AllocateBuffer(int buffer_size,
Operation operation) {
@@ -989,7 +990,8 @@
ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
ASSERT(pending_read_ == NULL);
- OverlappedBuffer* buffer = OverlappedBuffer::AllocateRecvFromBuffer(1024);
+ OverlappedBuffer* buffer =
+ OverlappedBuffer::AllocateRecvFromBuffer(kMaxUDPPackageLength);
DWORD flags;
flags = 0;
@@ -1212,14 +1214,18 @@
int bytes,
OverlappedBuffer* buffer) {
ASSERT(handle->is_datagram_socket());
- buffer->set_data_length(bytes);
- handle->ReadComplete(buffer);
- if (!handle->IsClosing()) {
- int event_mask = 1 << kInEvent;
- if ((handle->Mask() & event_mask) != 0) {
+ if (bytes >= 0) {
+ buffer->set_data_length(bytes);
+ handle->ReadComplete(buffer);
+ if (!handle->IsClosing()) {
+ int event_mask = 1 << kInEvent;
+ if ((handle->Mask() & event_mask) != 0) {
Dart_Port port = handle->NextNotifyDartPort(event_mask);
- DartUtils::PostInt32(port, event_mask);
+ DartUtils::PostInt32(port, event_mask);
+ }
}
+ } else {
+ HandleError(handle);
}
DeleteIfClosed(handle);
@@ -1413,6 +1419,11 @@
last_error == ERROR_BROKEN_PIPE) {
ASSERT(bytes == 0);
handler_impl->HandleIOCompletion(bytes, key, overlapped);
+ } else if (last_error == ERROR_MORE_DATA) {
+ // Don't ASSERT no bytes in this case. This can happen if the receive
+ // buffer for datagram sockets is to small to contain a full datagram,
+ // and in this case bytes hold the bytes that was read.
+ handler_impl->HandleIOCompletion(-1, key, overlapped);
} else {
ASSERT(bytes == 0);
handler_impl->HandleIOCompletion(-1, key, overlapped);
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index 9c28ac1..086e9f3 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -132,7 +132,6 @@
V(Socket_SetOption, 4) \
V(Socket_JoinMulticast, 4) \
V(Socket_LeaveMulticast, 4) \
- V(Socket_MarkSocketAsSharedHack, 1) \
V(Socket_GetSocketId, 1) \
V(Socket_SetSocketId, 2) \
V(Stdin_ReadByte, 1) \
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 09dfbf0..d829587 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -81,6 +81,12 @@
static bool has_run_precompiled_snapshot = false;
+// Global flag that is used to indicate that we want to compile everything in
+// the same way as precompilation before main, then continue running in the
+// same process.
+static bool has_noopt = false;
+
+
extern const char* kPrecompiledLibraryName;
extern const char* kPrecompiledSymbolName;
static const char* kPrecompiledVmIsolateName = "precompiled.vmisolate";
@@ -108,6 +114,8 @@
static const int kCompilationErrorExitCode = 254;
// Exit code indicating an unhandled error that is not a compilation error.
static const int kErrorExitCode = 255;
+// Exit code indicating a vm restart request. Never returned to the user.
+static const int kRestartRequestExitCode = 1000;
extern bool do_vm_shutdown; // Defined in bin/process.cc
static void ErrorExit(int exit_code, const char* format, ...) {
@@ -326,7 +334,7 @@
return false;
}
has_gen_precompiled_snapshot = true;
- vm_options->AddArgument("--precompile");
+ vm_options->AddArgument("--precompilation");
return true;
}
@@ -339,7 +347,20 @@
return false;
}
has_run_precompiled_snapshot = true;
- vm_options->AddArgument("--precompile");
+ vm_options->AddArgument("--precompilation");
+ return true;
+}
+
+
+static bool ProcessNooptOption(
+ const char* arg,
+ CommandLineOptions* vm_options) {
+ ASSERT(arg != NULL);
+ if (*arg != '\0') {
+ return false;
+ }
+ has_noopt = true;
+ vm_options->AddArgument("--precompilation");
return true;
}
@@ -483,6 +504,7 @@
{ "--debug", ProcessDebugOption },
{ "--enable-vm-service", ProcessEnableVmServiceOption },
{ "--gen-precompiled-snapshot", ProcessGenPrecompiledSnapshotOption },
+ { "--noopt", ProcessNooptOption },
{ "--observe", ProcessObserveOption },
{ "--run-precompiled-snapshot", ProcessRunPrecompiledSnapshotOption },
{ "--shutdown", ProcessShutdownOption },
@@ -665,8 +687,15 @@
#define CHECK_RESULT(result) \
if (Dart_IsError(result)) { \
*error = strdup(Dart_GetError(result)); \
- *exit_code = Dart_IsCompilationError(result) ? kCompilationErrorExitCode : \
- (Dart_IsApiError(result) ? kApiErrorExitCode : kErrorExitCode); \
+ if (Dart_IsCompilationError(result)) { \
+ *exit_code = kCompilationErrorExitCode; \
+ } else if (Dart_IsApiError(result)) { \
+ *exit_code = kApiErrorExitCode; \
+ } else if (Dart_IsVMRestartRequest(result)) { \
+ *exit_code = kRestartRequestExitCode; \
+ } else { \
+ *exit_code = kErrorExitCode; \
+ } \
Dart_ExitScope(); \
Dart_ShutdownIsolate(); \
return NULL; \
@@ -782,6 +811,7 @@
#undef CHECK_RESULT
+
static Dart_Isolate CreateIsolateAndSetup(const char* script_uri,
const char* main,
const char* package_root,
@@ -887,9 +917,6 @@
" enables the VM service and listens on specified port for connections\n"
" (default port number is 8181)\n"
"\n"
-"--noopt\n"
-" run unoptimized code only\n"
-"\n"
"The following options are only used for VM development and may\n"
"be changed in any future version:\n");
const char* print_flags = "--print_flags";
@@ -933,16 +960,6 @@
return buffer;
}
-static void DartExitOnError(Dart_Handle error) {
- if (!Dart_IsError(error)) {
- return;
- }
- const int exit_code = Dart_IsCompilationError(error) ?
- kCompilationErrorExitCode : kErrorExitCode;
- ErrorExit(exit_code, "%s\n", Dart_GetError(error));
-}
-
-
static void ShutdownIsolate(void* callback_data) {
IsolateData* isolate_data = reinterpret_cast<IsolateData*>(callback_data);
delete isolate_data;
@@ -1077,6 +1094,212 @@
}
+#define CHECK_RESULT(result) \
+ if (Dart_IsError(result)) { \
+ if (Dart_IsVMRestartRequest(result)) { \
+ Dart_ExitScope(); \
+ Dart_ShutdownIsolate(); \
+ return true; \
+ } \
+ const int exit_code = Dart_IsCompilationError(result) ? \
+ kCompilationErrorExitCode : kErrorExitCode; \
+ ErrorExit(exit_code, "%s\n", Dart_GetError(result)); \
+ }
+
+bool RunMainIsolate(const char* script_name,
+ CommandLineOptions* dart_options) {
+ // Call CreateIsolateAndSetup which creates an isolate and loads up
+ // the specified application script.
+ char* error = NULL;
+ int exit_code = 0;
+ char* isolate_name = BuildIsolateName(script_name, "main");
+ Dart_Isolate isolate = CreateIsolateAndSetupHelper(script_name,
+ "main",
+ commandline_package_root,
+ commandline_packages_file,
+ NULL,
+ &error,
+ &exit_code);
+ if (isolate == NULL) {
+ delete [] isolate_name;
+ if (exit_code == kRestartRequestExitCode) {
+ free(error);
+ return true;
+ }
+ Log::PrintErr("%s\n", error);
+ free(error);
+ error = NULL;
+ Process::TerminateExitCodeHandler();
+ error = Dart_Cleanup();
+ if (error != NULL) {
+ Log::PrintErr("VM cleanup failed: %s\n", error);
+ free(error);
+ }
+ if (do_vm_shutdown) {
+ DebuggerConnectionHandler::StopHandler();
+ EventHandler::Stop();
+ }
+ exit((exit_code != 0) ? exit_code : kErrorExitCode);
+ }
+ delete [] isolate_name;
+
+ Dart_EnterIsolate(isolate);
+ ASSERT(isolate == Dart_CurrentIsolate());
+ ASSERT(isolate != NULL);
+ Dart_Handle result;
+
+ Dart_EnterScope();
+
+ if (generate_script_snapshot) {
+ // First create a snapshot.
+ Dart_Handle result;
+ uint8_t* buffer = NULL;
+ intptr_t size = 0;
+ result = Dart_CreateScriptSnapshot(&buffer, &size);
+ CHECK_RESULT(result);
+
+ // Open the snapshot file.
+ File* snapshot_file = File::Open(snapshot_filename, File::kWriteTruncate);
+ if (snapshot_file == NULL) {
+ ErrorExit(kErrorExitCode,
+ "Unable to open file %s for writing the snapshot\n",
+ snapshot_filename);
+ }
+
+ // Write the magic number to indicate file is a script snapshot.
+ DartUtils::WriteMagicNumber(snapshot_file);
+
+ // Now write the snapshot out to specified file.
+ bool bytes_written = snapshot_file->WriteFully(buffer, size);
+ ASSERT(bytes_written);
+ delete snapshot_file;
+ snapshot_file = NULL;
+ } else {
+ // Lookup the library of the root script.
+ Dart_Handle root_lib = Dart_RootLibrary();
+ // Import the root library into the builtin library so that we can easily
+ // lookup the main entry point exported from the root library.
+ Dart_Handle builtin_lib =
+ Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
+ ASSERT(!Dart_IsError(builtin_lib));
+ result = Dart_LibraryImportLibrary(builtin_lib, root_lib, Dart_Null());
+
+ if (has_noopt || has_gen_precompiled_snapshot) {
+ Dart_QualifiedFunctionName standalone_entry_points[] = {
+ { "dart:_builtin", "::", "_getMainClosure" },
+ { "dart:_builtin", "::", "_getPrintClosure" },
+ { "dart:_builtin", "::", "_getUriBaseClosure" },
+ { "dart:_builtin", "::", "_resolveUri" },
+ { "dart:_builtin", "::", "_setWorkingDirectory" },
+ { "dart:_builtin", "::", "_loadDataAsync" },
+ { "dart:io", "::", "_makeUint8ListView" },
+ { "dart:io", "::", "_makeDatagram" },
+ { "dart:io", "::", "_setupHooks" },
+ { "dart:io", "CertificateException", "CertificateException." },
+ { "dart:io", "HandshakeException", "HandshakeException." },
+ { "dart:io", "TlsException", "TlsException." },
+ { "dart:io", "X509Certificate", "X509Certificate." },
+ { "dart:io", "_ExternalBuffer", "set:data" },
+ { "dart:io", "_Platform", "set:_nativeScript" },
+ { "dart:io", "_ProcessStartStatus", "set:_errorCode" },
+ { "dart:io", "_ProcessStartStatus", "set:_errorMessage" },
+ { "dart:io", "_SecureFilterImpl", "get:ENCRYPTED_SIZE" },
+ { "dart:io", "_SecureFilterImpl", "get:SIZE" },
+ { "dart:vmservice_io", "::", "_addResource" },
+ { "dart:vmservice_io", "::", "main" },
+ { NULL, NULL, NULL } // Must be terminated with NULL entries.
+ };
+
+ const bool reset_fields = has_gen_precompiled_snapshot;
+ result = Dart_Precompile(standalone_entry_points, reset_fields);
+ CHECK_RESULT(result);
+ }
+
+ if (has_gen_precompiled_snapshot) {
+ uint8_t* vm_isolate_buffer = NULL;
+ intptr_t vm_isolate_size = 0;
+ uint8_t* isolate_buffer = NULL;
+ intptr_t isolate_size = 0;
+ uint8_t* instructions_buffer = NULL;
+ intptr_t instructions_size = 0;
+ result = Dart_CreatePrecompiledSnapshot(&vm_isolate_buffer,
+ &vm_isolate_size,
+ &isolate_buffer,
+ &isolate_size,
+ &instructions_buffer,
+ &instructions_size);
+ CHECK_RESULT(result);
+ WriteSnapshotFile(kPrecompiledVmIsolateName,
+ vm_isolate_buffer,
+ vm_isolate_size);
+ WriteSnapshotFile(kPrecompiledIsolateName,
+ isolate_buffer,
+ isolate_size);
+ WriteSnapshotFile(kPrecompiledInstructionsName,
+ instructions_buffer,
+ instructions_size);
+ } else {
+ if (has_compile_all) {
+ result = Dart_CompileAll();
+ CHECK_RESULT(result);
+ }
+
+ if (Dart_IsNull(root_lib)) {
+ ErrorExit(kErrorExitCode,
+ "Unable to find root library for '%s'\n",
+ script_name);
+ }
+
+ // The helper function _getMainClosure creates a closure for the main
+ // entry point which is either explicitly or implictly exported from the
+ // root library.
+ Dart_Handle main_closure = Dart_Invoke(builtin_lib,
+ Dart_NewStringFromCString("_getMainClosure"), 0, NULL);
+ CHECK_RESULT(main_closure);
+
+ // Set debug breakpoint if specified on the command line before calling
+ // the main function.
+ if (breakpoint_at != NULL) {
+ result = SetBreakpoint(breakpoint_at, root_lib);
+ if (Dart_IsError(result)) {
+ ErrorExit(kErrorExitCode,
+ "Error setting breakpoint at '%s': %s\n",
+ breakpoint_at,
+ Dart_GetError(result));
+ }
+ }
+
+ // Call _startIsolate in the isolate library to enable dispatching the
+ // initial startup message.
+ const intptr_t kNumIsolateArgs = 2;
+ Dart_Handle isolate_args[kNumIsolateArgs];
+ isolate_args[0] = main_closure; // entryPoint
+ isolate_args[1] = CreateRuntimeOptions(dart_options); // args
+
+ Dart_Handle isolate_lib =
+ Dart_LookupLibrary(Dart_NewStringFromCString("dart:isolate"));
+ result = Dart_Invoke(isolate_lib,
+ Dart_NewStringFromCString("_startMainIsolate"),
+ kNumIsolateArgs, isolate_args);
+ CHECK_RESULT(result);
+
+ // Keep handling messages until the last active receive port is closed.
+ result = Dart_RunLoop();
+ CHECK_RESULT(result);
+ }
+ }
+
+ Dart_ExitScope();
+ // Shutdown the isolate.
+ Dart_ShutdownIsolate();
+
+ // No restart.
+ return false;
+}
+
+#undef CHECK_RESULT
+
+
void main(int argc, char** argv) {
char* script_name;
const int EXTRA_VM_ARGUMENTS = 2;
@@ -1183,182 +1406,11 @@
Dart_SetServiceStreamCallbacks(&ServiceStreamListenCallback,
&ServiceStreamCancelCallback);
- // Call CreateIsolateAndSetup which creates an isolate and loads up
- // the specified application script.
- int exit_code = 0;
- char* isolate_name = BuildIsolateName(script_name, "main");
- Dart_Isolate isolate = CreateIsolateAndSetupHelper(script_name,
- "main",
- commandline_package_root,
- commandline_packages_file,
- NULL,
- &error,
- &exit_code);
- if (isolate == NULL) {
- Log::PrintErr("%s\n", error);
- free(error);
- error = NULL;
- delete [] isolate_name;
- Process::TerminateExitCodeHandler();
- error = Dart_Cleanup();
- if (error != NULL) {
- Log::PrintErr("VM cleanup failed: %s\n", error);
- free(error);
- }
- if (do_vm_shutdown) {
- DebuggerConnectionHandler::StopHandler();
- EventHandler::Stop();
- }
- exit((exit_code != 0) ? exit_code : kErrorExitCode);
- }
- delete [] isolate_name;
-
- Dart_EnterIsolate(isolate);
- ASSERT(isolate == Dart_CurrentIsolate());
- ASSERT(isolate != NULL);
- Dart_Handle result;
-
- Dart_EnterScope();
-
- if (generate_script_snapshot) {
- // First create a snapshot.
- Dart_Handle result;
- uint8_t* buffer = NULL;
- intptr_t size = 0;
- result = Dart_CreateScriptSnapshot(&buffer, &size);
- DartExitOnError(result);
-
- // Open the snapshot file.
- File* snapshot_file = File::Open(snapshot_filename, File::kWriteTruncate);
- if (snapshot_file == NULL) {
- ErrorExit(kErrorExitCode,
- "Unable to open file %s for writing the snapshot\n",
- snapshot_filename);
- }
-
- // Write the magic number to indicate file is a script snapshot.
- DartUtils::WriteMagicNumber(snapshot_file);
-
- // Now write the snapshot out to specified file.
- bool bytes_written = snapshot_file->WriteFully(buffer, size);
- ASSERT(bytes_written);
- delete snapshot_file;
- snapshot_file = NULL;
- } else {
- // Lookup the library of the root script.
- Dart_Handle root_lib = Dart_RootLibrary();
- // Import the root library into the builtin library so that we can easily
- // lookup the main entry point exported from the root library.
- Dart_Handle builtin_lib =
- Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
- ASSERT(!Dart_IsError(builtin_lib));
- result = Dart_LibraryImportLibrary(builtin_lib, root_lib, Dart_Null());
-
- if (has_gen_precompiled_snapshot) {
- Dart_QualifiedFunctionName standalone_entry_points[] = {
- { "dart:_builtin", "::", "_getMainClosure" },
- { "dart:_builtin", "::", "_getPrintClosure" },
- { "dart:_builtin", "::", "_getUriBaseClosure" },
- { "dart:_builtin", "::", "_resolveUri" },
- { "dart:_builtin", "::", "_setWorkingDirectory" },
- { "dart:_builtin", "::", "_loadDataAsync" },
- { "dart:io", "::", "_makeUint8ListView" },
- { "dart:io", "::", "_makeDatagram" },
- { "dart:io", "::", "_setupHooks" },
- { "dart:io", "CertificateException", "CertificateException." },
- { "dart:io", "HandshakeException", "HandshakeException." },
- { "dart:io", "TlsException", "TlsException." },
- { "dart:io", "X509Certificate", "X509Certificate." },
- { "dart:io", "_ExternalBuffer", "set:data" },
- { "dart:io", "_Platform", "set:_nativeScript" },
- { "dart:io", "_ProcessStartStatus", "set:_errorCode" },
- { "dart:io", "_ProcessStartStatus", "set:_errorMessage" },
- { "dart:io", "_SecureFilterImpl", "get:ENCRYPTED_SIZE" },
- { "dart:io", "_SecureFilterImpl", "get:SIZE" },
- { "dart:vmservice_io", "::", "_addResource" },
- { "dart:vmservice_io", "::", "main" },
- { NULL, NULL, NULL } // Must be terminated with NULL entries.
- };
-
- result = Dart_Precompile(standalone_entry_points);
- DartExitOnError(result);
-
- uint8_t* vm_isolate_buffer = NULL;
- intptr_t vm_isolate_size = 0;
- uint8_t* isolate_buffer = NULL;
- intptr_t isolate_size = 0;
- uint8_t* instructions_buffer = NULL;
- intptr_t instructions_size = 0;
- result = Dart_CreatePrecompiledSnapshot(&vm_isolate_buffer,
- &vm_isolate_size,
- &isolate_buffer,
- &isolate_size,
- &instructions_buffer,
- &instructions_size);
- DartExitOnError(result);
- WriteSnapshotFile(kPrecompiledVmIsolateName,
- vm_isolate_buffer,
- vm_isolate_size);
- WriteSnapshotFile(kPrecompiledIsolateName,
- isolate_buffer,
- isolate_size);
- WriteSnapshotFile(kPrecompiledInstructionsName,
- instructions_buffer,
- instructions_size);
- } else {
- if (has_compile_all) {
- result = Dart_CompileAll();
- DartExitOnError(result);
- }
-
- if (Dart_IsNull(root_lib)) {
- ErrorExit(kErrorExitCode,
- "Unable to find root library for '%s'\n",
- script_name);
- }
-
- // The helper function _getMainClosure creates a closure for the main
- // entry point which is either explicitly or implictly exported from the
- // root library.
- Dart_Handle main_closure = Dart_Invoke(builtin_lib,
- Dart_NewStringFromCString("_getMainClosure"), 0, NULL);
- DartExitOnError(main_closure);
-
- // Set debug breakpoint if specified on the command line before calling
- // the main function.
- if (breakpoint_at != NULL) {
- result = SetBreakpoint(breakpoint_at, root_lib);
- if (Dart_IsError(result)) {
- ErrorExit(kErrorExitCode,
- "Error setting breakpoint at '%s': %s\n",
- breakpoint_at,
- Dart_GetError(result));
- }
- }
-
- // Call _startIsolate in the isolate library to enable dispatching the
- // initial startup message.
- const intptr_t kNumIsolateArgs = 2;
- Dart_Handle isolate_args[kNumIsolateArgs];
- isolate_args[0] = main_closure; // entryPoint
- isolate_args[1] = CreateRuntimeOptions(&dart_options); // args
-
- Dart_Handle isolate_lib =
- Dart_LookupLibrary(Dart_NewStringFromCString("dart:isolate"));
- result = Dart_Invoke(isolate_lib,
- Dart_NewStringFromCString("_startMainIsolate"),
- kNumIsolateArgs, isolate_args);
- DartExitOnError(result);
-
- // Keep handling messages until the last active receive port is closed.
- result = Dart_RunLoop();
- DartExitOnError(result);
- }
+ // Run the main isolate until we aren't told to restart.
+ while (RunMainIsolate(script_name, &dart_options)) {
+ Log::PrintErr("Restarting VM\n");
}
- Dart_ExitScope();
- // Shutdown the isolate.
- Dart_ShutdownIsolate();
// Terminate process exit-code handler.
Process::TerminateExitCodeHandler();
diff --git a/runtime/bin/process.cc b/runtime/bin/process.cc
index 9e3e14e..47e2ff5 100644
--- a/runtime/bin/process.cc
+++ b/runtime/bin/process.cc
@@ -262,7 +262,15 @@
free(error);
}
if (do_vm_shutdown) {
+#ifdef LEGACY_DEBUG_PROTOCOL_ENABLED
+ // Note that this dependency crosses logical project boundaries by making
+ // the dart:io implementation depend upon the standalone VM's legacy debug
+ // protocol. This breaks projects which want to use our dart:io
+ // implementation. Because the protocol is going away shortly, it's
+ // reasonable to leave it behind a #ifdef that is only enabled for the
+ // standalone VM for now.
DebuggerConnectionHandler::StopHandler();
+#endif
EventHandler::Stop();
}
exit(static_cast<int>(status));
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index af90fab..1b82008 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -43,18 +43,33 @@
static const bool SSL_LOG_STATUS = false;
static const bool SSL_LOG_DATA = false;
-static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 200;
+static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 1000;
/* Handle an error reported from the BoringSSL library. */
-static void ThrowIOException(const char* exception_type,
+static void ThrowIOException(int status,
+ const char* exception_type,
const char* message,
bool free_message = false) {
- // TODO(24068): Get the error code and message from the error stack.
- // There may be more than one error on the stack - should we
- // concatenate the error messages?
- int error_code = 0;
- const char* error_message = "Unknown error from BoringSSL library";
- OSError os_error_struct(error_code, error_message, OSError::kBoringSSL);
+ char error_string[SSL_ERROR_MESSAGE_BUFFER_SIZE];
+ error_string[0] = '\0';
+ int error = ERR_get_error();
+ while (error != 0) {
+ int length = strlen(error_string);
+ int free_length = SSL_ERROR_MESSAGE_BUFFER_SIZE - length;
+ if (free_length > 16) {
+ // Enough room for error code at least.
+ if (length > 0) {
+ error_string[length] = '\n';
+ error_string[length + 1] = '\0';
+ length++;
+ free_length--;
+ }
+ ERR_error_string_n(error, error_string + length, free_length);
+ // ERR_error_string_n is guaranteed to leave a null-terminated string.
+ }
+ error = ERR_get_error();
+ }
+ OSError os_error_struct(status, error_string, OSError::kBoringSSL);
Dart_Handle os_error = DartUtils::NewDartOSError(&os_error_struct);
Dart_Handle exception =
DartUtils::NewDartIOException(exception_type, message, os_error);
@@ -332,28 +347,26 @@
int PasswordCallback(char* buf, int size, int rwflag, void* userdata) {
char* password = static_cast<char*>(userdata);
- if (static_cast<size_t>(size) < strlen(password) + 1) {
- Log::PrintErr("Password buffer too small.\n");
- exit(1);
- // TODO(24182): Find the actual value of size passed in here, and
- // check for password length longer than this in the Dart function
- // that passes in the password, so we never have this problem.
- }
- strncpy(buf, static_cast<char*>(userdata), size);
- return strlen(static_cast<char*>(userdata));
+ ASSERT(size == PEM_BUFSIZE);
+ strncpy(buf, password, size);
+ return strlen(password);
}
-void CheckStatus(int status, const char* message, int line) {
+void CheckStatus(int status,
+ const char* type,
+ const char* message) {
// TODO(24183): Take appropriate action on failed calls,
// throw exception that includes all messages from the error stack.
- if (status != 1 && SSL_LOG_STATUS) {
+ if (status == 1) return;
+ if (SSL_LOG_STATUS) {
int error = ERR_get_error();
- Log::PrintErr("Failed: %s line %d\n", message, line);
+ Log::PrintErr("Failed: %s status %d", message, status);
char error_string[SSL_ERROR_MESSAGE_BUFFER_SIZE];
ERR_error_string_n(error, error_string, SSL_ERROR_MESSAGE_BUFFER_SIZE);
Log::PrintErr("ERROR: %d %s\n", error, error_string);
}
+ ThrowIOException(status, type, message);
}
@@ -371,12 +384,16 @@
const char* password = NULL;
if (Dart_IsString(password_object)) {
ThrowIfError(Dart_StringToCString(password_object, &password));
+ if (strlen(password) > PEM_BUFSIZE - 1) {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "SecurityContext.usePrivateKey password length is greater than"
+ " 1023 (PEM_BUFSIZE)"));
+ }
} else if (Dart_IsNull(password_object)) {
password = "";
} else {
Dart_ThrowException(DartUtils::NewDartArgumentError(
- "Password argument to SecurityContext.usePrivateKey is not "
- "a String or null"));
+ "SecurityContext.usePrivateKey password is not a String or null"));
}
SSL_CTX_set_default_passwd_cb(context, PasswordCallback);
@@ -387,7 +404,7 @@
// TODO(24184): Handle different expected errors here - file missing,
// incorrect password, file not a PEM, and throw exceptions.
// CheckStatus should also throw an exception in uncaught cases.
- CheckStatus(status, "SSL_CTX_use_PrivateKey_file", __LINE__);
+ CheckStatus(status, "TlsException", "Failure in usePrivateKey");
SSL_CTX_set_default_passwd_cb_userdata(context, NULL);
}
@@ -413,7 +430,8 @@
}
int status = SSL_CTX_load_verify_locations(context, filename, directory);
- CheckStatus(status, "SSL_CTX_load_verify_locations", __LINE__);
+ CheckStatus(
+ status, "TlsException", "SSL_CTX_load_verify_locations");
}
@@ -448,7 +466,9 @@
" is not a String"));
}
int status = SSL_CTX_use_certificate_chain_file(context, filename);
- CheckStatus(status, "SSL_CTX_use_certificate_chain_file", __LINE__);
+ CheckStatus(status,
+ "TlsException",
+ "Failure in useCertificateChain");
}
@@ -873,13 +893,9 @@
int error;
BIO* ssl_side;
status = BIO_new_bio_pair(&ssl_side, 10000, &socket_side_, 10000);
- CheckStatus(status, "BIO_new_bio_pair", __LINE__);
+ CheckStatus(status, "TlsException", "BIO_new_bio_pair");
- if (context == NULL) {
- DART_CHECK_VALID(Dart_ThrowException(DartUtils::NewDartArgumentError(
- "Default SecurityContext not implemented, context cannot be null.")));
- }
-
+ assert(context != NULL);
ssl_ = SSL_new(context);
SSL_set_bio(ssl_, ssl_side, ssl_side);
SSL_set_mode(ssl_, SSL_MODE_AUTO_RETRY); // TODO(whesse): Is this right?
@@ -891,6 +907,8 @@
SSL_set_verify(ssl_, SSL_VERIFY_NONE, NULL);
} else {
SetAlpnProtocolList(protocols_handle, ssl_, NULL, false);
+ status = SSL_set_tlsext_host_name(ssl_, hostname);
+ CheckStatus(status, "TlsException", "Set SNI host name");
// Sets the hostname in the certificate-checking object, so it is checked
// against the certificate presented by the server.
X509_VERIFY_PARAM* certificate_checking_parameters = SSL_get0_param(ssl_);
@@ -899,11 +917,10 @@
X509_V_FLAG_PARTIAL_CHAIN |
X509_V_FLAG_TRUSTED_FIRST);
X509_VERIFY_PARAM_set_hostflags(certificate_checking_parameters, 0);
- X509_VERIFY_PARAM_set1_host(certificate_checking_parameters,
- hostname_, strlen(hostname_));
- // TODO(24225) Check return value of set1_host().
- // TODO(24186) free hostname_ if it is not freed when SSL is destroyed.
- // otherwise, make it a local variable, not a instance field.
+ status = X509_VERIFY_PARAM_set1_host(certificate_checking_parameters,
+ hostname_, strlen(hostname_));
+ CheckStatus(status, "TlsException",
+ "Set hostname for certificate checking");
}
// Make the connection:
if (is_server_) {
@@ -948,7 +965,6 @@
void SSLFilter::Handshake() {
// Try and push handshake along.
int status;
- int error;
status = SSL_do_handshake(ssl_);
if (callback_error != NULL) {
// The SSL_do_handshake will try performing a handshake and might call
@@ -957,57 +973,33 @@
// logic and we propagate the error"
Dart_PropagateError(callback_error);
}
- if (SSL_LOG_STATUS) Log::Print("SSL_handshake status: %d\n", status);
- if (status != 1) {
- error = SSL_get_error(ssl_, status);
- if (SSL_LOG_STATUS) {
- Log::Print("ERROR: %d\n", error);
- ERR_print_errors_cb(printErrorCallback, NULL);
- }
+ if (SSL_want_write(ssl_) || SSL_want_read(ssl_)) {
+ in_handshake_ = true;
+ return;
}
- if (status == 1) {
- if (in_handshake_) {
- // TODO(24071): Check return value of SSL_get_verify_result, this
- // should give us the hostname check.
- int result = SSL_get_verify_result(ssl_);
- if (SSL_LOG_STATUS) {
- Log::Print("Handshake verification status: %d\n", result);
- X509* peer_certificate = SSL_get_peer_certificate(ssl_);
- if (peer_certificate == NULL) {
- Log::Print("No peer certificate received\n");
- } else {
- X509_NAME* s_name = X509_get_subject_name(peer_certificate);
- printf("Peer certificate SN: ");
- X509_NAME_print_ex_fp(stdout, s_name, 4, 0);
- printf("\n");
- }
- }
- ThrowIfError(Dart_InvokeClosure(
- Dart_HandleFromPersistent(handshake_complete_), 0, NULL));
- in_handshake_ = false;
- }
- } else if (status == 0) {
- if (is_server_) {
- ThrowIOException("HandshakeException",
- "Handshake error in server");
- } else {
- ThrowIOException("HandshakeException",
- "Handshake error in client");
- }
- } else if (status < 0) {
- if (SSL_want_write(ssl_) || SSL_want_read(ssl_)) {
- if (!in_handshake_) {
- in_handshake_ = true;
- }
- } else {
- if (is_server_) {
- ThrowIOException("HandshakeException",
- "Handshake error in server");
+ CheckStatus(status,
+ "HandshakeException",
+ is_server_ ? "Handshake error in server" : "Handshake error in client");
+ // Handshake succeeded.
+ if (in_handshake_) {
+ // TODO(24071): Check return value of SSL_get_verify_result, this
+ // should give us the hostname check.
+ int result = SSL_get_verify_result(ssl_);
+ if (SSL_LOG_STATUS) {
+ Log::Print("Handshake verification status: %d\n", result);
+ X509* peer_certificate = SSL_get_peer_certificate(ssl_);
+ if (peer_certificate == NULL) {
+ Log::Print("No peer certificate received\n");
} else {
- ThrowIOException("HandshakeException",
- "Handshake error in client");
+ X509_NAME* s_name = X509_get_subject_name(peer_certificate);
+ printf("Peer certificate SN: ");
+ X509_NAME_print_ex_fp(stdout, s_name, 4, 0);
+ printf("\n");
}
}
+ ThrowIfError(Dart_InvokeClosure(
+ Dart_HandleFromPersistent(handshake_complete_), 0, NULL));
+ in_handshake_ = false;
}
}
@@ -1044,6 +1036,10 @@
BIO_free(socket_side_);
socket_side_ = NULL;
}
+ if (hostname_ != NULL) {
+ free(hostname_);
+ hostname_ = NULL;
+ }
for (int i = 0; i < kNumBuffers; ++i) {
Dart_DeletePersistentHandle(dart_buffer_objects_[i]);
delete[] buffers_[i];
diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc
index ea5154e..b0b6a34 100644
--- a/runtime/bin/socket.cc
+++ b/runtime/bin/socket.cc
@@ -170,20 +170,6 @@
}
-Dart_Handle ListeningSocketRegistry::MarkSocketFdAsSharableHack(
- intptr_t socketfd) {
- MutexLocker ml(ListeningSocketRegistry::mutex_);
-
- SocketsIterator it = sockets_by_fd_.find(socketfd);
- if (it != sockets_by_fd_.end()) {
- it->second->shared = true;
- return Dart_True();
- } else {
- return Dart_False();
- }
-}
-
-
void FUNCTION_NAME(InternetAddress_Parse)(Dart_NativeArguments args) {
const char* address =
DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
@@ -855,15 +841,6 @@
}
-void FUNCTION_NAME(Socket_MarkSocketAsSharedHack)(Dart_NativeArguments args) {
- intptr_t socketfd =
- Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
-
- ListeningSocketRegistry *registry = ListeningSocketRegistry::Instance();
- Dart_SetReturnValue(args, registry->MarkSocketFdAsSharableHack(socketfd));
-}
-
-
void Socket::SetSocketIdNativeField(Dart_Handle socket, intptr_t id) {
Dart_Handle err =
Dart_SetNativeInstanceField(socket, kSocketIdNativeField, id);
diff --git a/runtime/bin/socket.h b/runtime/bin/socket.h
index 507acd9..1910f86 100644
--- a/runtime/bin/socket.h
+++ b/runtime/bin/socket.h
@@ -395,13 +395,6 @@
// this function.
bool CloseSafe(intptr_t socketfd);
- // Mark an existing socket as sharable if it is not already marked as
- // sharable.
- //
- // NOTE: This is a temporary measure until ServerSocketReference's are
- // removed.
- Dart_Handle MarkSocketFdAsSharableHack(intptr_t socketfd);
-
Mutex *mutex() { return mutex_; }
private:
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index 47e5f44..7de16a9 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -1083,8 +1083,6 @@
bool nativeLeaveMulticast(
List<int> addr, List<int> interfaceAddr, int interfaceIndex)
native "Socket_LeaveMulticast";
- bool _nativeMarkSocketAsSharedHack()
- native "Socket_MarkSocketAsSharedHack";
}
@@ -1187,50 +1185,10 @@
}
}
- RawServerSocketReference get reference {
- if (_referencePort == null) {
- bool successfull = _socket._nativeMarkSocketAsSharedHack();
- _referencePort = new ReceivePort();
- _referencePort.listen((sendPort) {
- sendPort.send(
- [_socket.address,
- _socket.port,
- _v6Only]);
- });
- }
- return new _RawServerSocketReference(_referencePort.sendPort);
- }
-
void set _owner(owner) { _socket.owner = owner; }
}
-class _RawServerSocketReference implements RawServerSocketReference {
- final SendPort _sendPort;
-
- _RawServerSocketReference(this._sendPort);
-
- Future<RawServerSocket> create() {
- var port = new ReceivePort();
- _sendPort.send(port.sendPort);
- return port.first.then((List args) {
- port.close();
-
- InternetAddress address = args[0];
- int tcpPort = args[1];
- bool v6Only = args[2];
- return
- RawServerSocket.bind(address, tcpPort, v6Only: v6Only, shared: true);
- });
- }
-
- int get hashCode => _sendPort.hashCode;
-
- bool operator==(Object other)
- => other is _RawServerSocketReference && _sendPort == other._sendPort;
-}
-
-
class _RawSocket extends Stream<RawSocketEvent>
implements RawSocket {
final _NativeSocket _socket;
@@ -1393,17 +1351,6 @@
}
-class _ServerSocketReference implements ServerSocketReference {
- final RawServerSocketReference _rawReference;
-
- _ServerSocketReference(this._rawReference);
-
- Future<ServerSocket> create() {
- return _rawReference.create().then((raw) => new _ServerSocket(raw));
- }
-}
-
-
class _ServerSocket extends Stream<Socket>
implements ServerSocket {
final _socket;
@@ -1436,10 +1383,6 @@
Future close() => _socket.close().then((_) => this);
- ServerSocketReference get reference {
- return new _ServerSocketReference(_socket.reference);
- }
-
void set _owner(owner) { _socket._owner = owner; }
}
diff --git a/runtime/bin/vmservice/vmservice_io.dart b/runtime/bin/vmservice/vmservice_io.dart
index d9b0c75..eb44a6c 100644
--- a/runtime/bin/vmservice/vmservice_io.dart
+++ b/runtime/bin/vmservice/vmservice_io.dart
@@ -8,7 +8,7 @@
import 'dart:convert';
import 'dart:io';
import 'dart:isolate';
-import 'dart:vmservice';
+import 'dart:_vmservice';
part 'loader.dart';
part 'resources.dart';
diff --git a/runtime/codereview.settings b/runtime/codereview.settings
index 210cc8b..b731156 100644
--- a/runtime/codereview.settings
+++ b/runtime/codereview.settings
@@ -1,4 +1,4 @@
# This file is used by gcl to get repository specific information.
-CODE_REVIEW_SERVER: http://codereview.chromium.org/
+CODE_REVIEW_SERVER: http://codereview.chromium.org
VIEW_VC: https://github.com/dart-lang/sdk/commit/
CC_LIST: reviews@dartlang.org,vm-dev@dartlang.org
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 031b8c5..c5658951 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -131,7 +131,10 @@
* occur in any function which triggers the execution of Dart code.
*
* - Fatal error handles are produced when the system wants to shut
- * down the current isolate.
+ * down the current isolate. Sometimes a fatal error may be a
+ * restart request (see Dart_IsRestartRequest). If the embedder does
+ * not support restarting the VM, then this should be treated as a
+ * normal fatal error.
*
* --- Propagating errors ---
*
@@ -268,6 +271,17 @@
DART_EXPORT bool Dart_IsFatalError(Dart_Handle handle);
/**
+ * Is this error a request to restart the VM?
+ *
+ * If an embedder chooses to support restarting the VM from tools
+ * (such as a debugger), then this function is used to distinguish
+ * restart requests from other fatal errors.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT bool Dart_IsVMRestartRequest(Dart_Handle handle);
+
+/**
* Gets the error message from an error handle.
*
* Requires there to be a current isolate.
@@ -2877,8 +2891,29 @@
} Dart_QualifiedFunctionName;
+/**
+ * Compiles all functions reachable from the provided entry points and marks
+ * the isolate to disallow future compilation.
+ *
+ * \param entry_points A list of functions that may be invoked through the
+ * embedding API, e.g. Dart_Invoke/GetField/SetField/New/InvokeClosure.
+ *
+ * \param reset_fields Controls whether static fields are reset. Fields without
+ * an initializer will be set to null, and fields with an initializer will have
+ * their initializer run the next time they are accessed.
+ *
+ * reset_fields is true when we are about to create a precompilated snapshot.
+ * Some fields are already been initialized as part of the loading logic, and
+ * we want them to be reinitialized in the new process that will load the
+ * snapshot. reset_fields is false for --noopt, which will continue running in
+ * the same process.
+ *
+ * \return An error handle if a compilation error or runtime error running const
+ * constructors was encountered.
+ */
DART_EXPORT Dart_Handle Dart_Precompile(
- Dart_QualifiedFunctionName entry_points[]);
+ Dart_QualifiedFunctionName entry_points[],
+ bool reset_fields);
DART_EXPORT Dart_Handle Dart_CreatePrecompiledSnapshot(
diff --git a/runtime/include/dart_tools_api.h b/runtime/include/dart_tools_api.h
index 0e279e0..6d1567c 100644
--- a/runtime/include/dart_tools_api.h
+++ b/runtime/include/dart_tools_api.h
@@ -891,19 +891,22 @@
#define DART_TIMELINE_STREAM_API (1 << 0)
/** Timeline stream for compiler events */
#define DART_TIMELINE_STREAM_COMPILER (1 << 1)
+/** Timeline stream for Dart provided events */
+#define DART_TIMELINE_STREAM_DART (1 << 2)
/** Timeline stream for embedder provided events */
-#define DART_TIMELINE_STREAM_EMBEDDER (1 << 2)
+#define DART_TIMELINE_STREAM_EMBEDDER (1 << 3)
/** Timeline stream for GC events */
-#define DART_TIMELINE_STREAM_GC (1 << 3)
+#define DART_TIMELINE_STREAM_GC (1 << 4)
/** Timeline stream for isolate events */
-#define DART_TIMELINE_STREAM_ISOLATE (1 << 4)
+#define DART_TIMELINE_STREAM_ISOLATE (1 << 5)
/** Timeline stream for VM events */
-#define DART_TIMELINE_STREAM_VM (1 << 5)
+#define DART_TIMELINE_STREAM_VM (1 << 6)
/** Enable all timeline stream recording for an isolate */
#define DART_TIMELINE_STREAM_ALL (DART_TIMELINE_STREAM_API | \
DART_TIMELINE_STREAM_COMPILER | \
+ DART_TIMELINE_STREAM_DART | \
DART_TIMELINE_STREAM_EMBEDDER | \
DART_TIMELINE_STREAM_GC | \
DART_TIMELINE_STREAM_ISOLATE)
@@ -966,7 +969,7 @@
typedef void (*Dart_StreamConsumer)(
Dart_StreamConsumer_State state,
const char* stream_name,
- uint8_t* buffer,
+ const uint8_t* buffer,
intptr_t buffer_length,
void* stream_callback_data);
diff --git a/runtime/lib/async_patch.dart b/runtime/lib/async_patch.dart
index d785347..fdeb5c9 100644
--- a/runtime/lib/async_patch.dart
+++ b/runtime/lib/async_patch.dart
@@ -182,3 +182,5 @@
return cancellationCompleter.future;
}
}
+
+patch void _rethrow(Object error, StackTrace stackTrace) native "Async_rethrow";
diff --git a/runtime/lib/developer_sources.gypi b/runtime/lib/developer_sources.gypi
index 4d4218c..e3f1ea6 100644
--- a/runtime/lib/developer_sources.gypi
+++ b/runtime/lib/developer_sources.gypi
@@ -10,6 +10,8 @@
'developer.dart',
'profiler.cc',
'profiler.dart',
+ 'timeline.cc',
+ 'timeline.dart',
],
}
diff --git a/runtime/lib/errors.cc b/runtime/lib/errors.cc
index 8383a30..c7a2164 100644
--- a/runtime/lib/errors.cc
+++ b/runtime/lib/errors.cc
@@ -126,4 +126,12 @@
return Object::null();
}
+// Rethrow an error with a stacktrace.
+DEFINE_NATIVE_ENTRY(Async_rethrow, 2) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Instance, error, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Instance, stacktrace, arguments->NativeArgAt(1));
+ Exceptions::ReThrow(thread, error, stacktrace);
+ return Object::null();
+}
+
} // namespace dart
diff --git a/runtime/lib/internal_patch.dart b/runtime/lib/internal_patch.dart
index f2fe680..8e95506 100644
--- a/runtime/lib/internal_patch.dart
+++ b/runtime/lib/internal_patch.dart
@@ -15,6 +15,9 @@
static var eventHandlerSendData;
// Implementation of Resource.readAsBytes.
static var resourceReadAsBytes;
+ // Implementation of package root/map provision.
+ static var getPackageRoot;
+ static var getPackageMap;
}
patch class CodeUnits {
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index 5199f19..82f468f 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -259,17 +259,25 @@
}
-DEFINE_NATIVE_ENTRY(Isolate_spawnUri, 10) {
+DEFINE_NATIVE_ENTRY(Isolate_spawnUri, 12) {
GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(String, uri, arguments->NativeArgAt(1));
+
GET_NON_NULL_NATIVE_ARGUMENT(Instance, args, arguments->NativeArgAt(2));
GET_NON_NULL_NATIVE_ARGUMENT(Instance, message, arguments->NativeArgAt(3));
+
GET_NON_NULL_NATIVE_ARGUMENT(Bool, paused, arguments->NativeArgAt(4));
- GET_NATIVE_ARGUMENT(Bool, checked, arguments->NativeArgAt(5));
- GET_NATIVE_ARGUMENT(String, package_root, arguments->NativeArgAt(6));
+ GET_NATIVE_ARGUMENT(SendPort, onExit, arguments->NativeArgAt(5));
+ GET_NATIVE_ARGUMENT(SendPort, onError, arguments->NativeArgAt(6));
+
GET_NATIVE_ARGUMENT(Bool, fatalErrors, arguments->NativeArgAt(7));
- GET_NATIVE_ARGUMENT(SendPort, onExit, arguments->NativeArgAt(8));
- GET_NATIVE_ARGUMENT(SendPort, onError, arguments->NativeArgAt(9));
+ GET_NATIVE_ARGUMENT(Bool, checked, arguments->NativeArgAt(8));
+
+ GET_NATIVE_ARGUMENT(Array, environment, arguments->NativeArgAt(9));
+
+ GET_NATIVE_ARGUMENT(String, package_root, arguments->NativeArgAt(10));
+ GET_NATIVE_ARGUMENT(Array, packages, arguments->NativeArgAt(11));
+
// Canonicalize the uri with respect to the current isolate.
char* error = NULL;
diff --git a/runtime/lib/isolate_patch.dart b/runtime/lib/isolate_patch.dart
index daaaf97..08fc247 100644
--- a/runtime/lib/isolate_patch.dart
+++ b/runtime/lib/isolate_patch.dart
@@ -275,6 +275,22 @@
/* patch */ static Isolate get current => _currentIsolate;
+ /* patch */ static Future<Uri> get packageRoot {
+ var hook = VMLibraryHooks.getPackageRoot;
+ if (hook == null) {
+ throw new UnimplementedError("Isolate.packageRoot");
+ }
+ return hook();
+ }
+
+ /* patch */ static Future<Map<String, Uri>> get packageMap {
+ var hook = VMLibraryHooks.getPackageMap;
+ if (hook == null) {
+ throw new UnimplementedError("Isolate.packageMap");
+ }
+ return hook();
+ }
+
/* patch */ static Future<Isolate> spawn(
void entryPoint(message), var message,
{bool paused: false, bool errorsAreFatal,
@@ -318,15 +334,21 @@
Map<String, Uri> packages}) {
RawReceivePort readyPort;
if (environment != null) throw new UnimplementedError("environment");
+ if (packages != null) throw new UnimplementedError("packages");
try {
// The VM will invoke [_startIsolate] and not `main`.
// TODO: Handle [packages].
readyPort = new RawReceivePort();
var packageRootString =
(packageRoot == null) ? null : packageRoot.toString();
- _spawnUri(readyPort.sendPort, uri.toString(), args, message,
- paused, checked, packageRootString,
- errorsAreFatal, onExit, onError);
+ var packagesList = null;
+
+ _spawnUri(readyPort.sendPort, uri.toString(),
+ args, message,
+ paused, onExit, onError,
+ errorsAreFatal, checked,
+ null, /* environment */
+ packageRootString, packagesList);
Completer completer = new Completer<Isolate>.sync();
readyPort.handler = (readyMessage) {
readyPort.close();
@@ -369,8 +391,10 @@
static void _spawnUri(SendPort readyPort, String uri,
List<String> args, var message,
- bool paused, bool checked, String packageRoot,
- bool errorsAreFatal, SendPort onExit, SendPort onError)
+ bool paused, SendPort onExit, SendPort onError,
+ bool errorsAreFatal, bool checked,
+ List environment,
+ String packageRoot, List packages)
native "Isolate_spawnUri";
static void _sendOOB(port, msg) native "Isolate_sendOOB";
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 65f7c62..8e80deb 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -91,8 +91,7 @@
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const Class& cls = Class::Handle(zone, func.Owner());
- const Error& error = Error::Handle(
- zone, cls.EnsureIsFinalized(thread->isolate()));
+ const Error& error = Error::Handle(zone, cls.EnsureIsFinalized(thread));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
UNREACHABLE();
@@ -345,7 +344,7 @@
}
}
- const Error& error = Error::Handle(cls.EnsureIsFinalized(Isolate::Current()));
+ const Error& error = Error::Handle(cls.EnsureIsFinalized(Thread::Current()));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
UNREACHABLE();
@@ -382,9 +381,17 @@
str = lib.name();
args.SetAt(1, str);
str = lib.url();
- if (str.Equals("dart:_builtin") || str.Equals("dart:_blink")) {
- // Censored library (grumble).
- return Instance::null();
+ const char* censored_libraries[] = {
+ "dart:_builtin",
+ "dart:_blink",
+ "dart:_vmservice",
+ NULL,
+ };
+ for (intptr_t i = 0; censored_libraries[i] != NULL; i++) {
+ if (str.Equals(censored_libraries[i])) {
+ // Censored library (grumble).
+ return Instance::null();
+ }
}
if (str.Equals("dart:io")) {
// Hack around dart:io being loaded into non-service isolates in Dartium.
@@ -589,11 +596,12 @@
static void VerifyMethodKindShifts() {
#ifdef DEBUG
- Isolate* isolate = Isolate::Current();
- const Library& lib = Library::Handle(isolate, Library::MirrorsLibrary());
- const Class& cls = Class::Handle(isolate,
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ const Library& lib = Library::Handle(zone, Library::MirrorsLibrary());
+ const Class& cls = Class::Handle(zone,
lib.LookupClassAllowPrivate(Symbols::_LocalMethodMirror()));
- const Error& error = Error::Handle(isolate, cls.EnsureIsFinalized(isolate));
+ const Error& error = Error::Handle(zone, cls.EnsureIsFinalized(thread));
ASSERT(error.IsNull());
Field& field = Field::Handle();
@@ -977,7 +985,7 @@
UNREACHABLE();
}
const Class& cls = Class::Handle(type.type_class());
- const Error& error = Error::Handle(cls.EnsureIsFinalized(isolate));
+ const Error& error = Error::Handle(cls.EnsureIsFinalized(thread));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
}
@@ -994,7 +1002,7 @@
UNREACHABLE();
}
const Class& cls = Class::Handle(type.type_class());
- const Error& error = Error::Handle(cls.EnsureIsFinalized(isolate));
+ const Error& error = Error::Handle(cls.EnsureIsFinalized(thread));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
}
@@ -1059,7 +1067,7 @@
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(2));
const Class& klass = Class::Handle(ref.GetClassReferent());
- const Error& error = Error::Handle(klass.EnsureIsFinalized(isolate));
+ const Error& error = Error::Handle(klass.EnsureIsFinalized(thread));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
}
@@ -1110,7 +1118,7 @@
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(2));
const Class& klass = Class::Handle(ref.GetClassReferent());
- const Error& error = Error::Handle(klass.EnsureIsFinalized(isolate));
+ const Error& error = Error::Handle(klass.EnsureIsFinalized(thread));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
}
diff --git a/runtime/lib/timeline.cc b/runtime/lib/timeline.cc
new file mode 100644
index 0000000..ac2426e
--- /dev/null
+++ b/runtime/lib/timeline.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2015, 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.
+
+#include "vm/bootstrap_natives.h"
+
+#include "include/dart_api.h"
+
+#include "vm/native_entry.h"
+#include "vm/object.h"
+#include "vm/os.h"
+#include "vm/timeline.h"
+
+namespace dart {
+
+// Native implementations for the dart:developer library.
+DEFINE_NATIVE_ENTRY(Timeline_getTraceClock, 0) {
+ return Integer::New(OS::GetCurrentTraceMicros(), Heap::kNew, true);
+}
+
+
+DEFINE_NATIVE_ENTRY(Timeline_reportCompleteEvent, 5) {
+ TimelineEventRecorder* recorder = Timeline::recorder();
+ if (recorder == NULL) {
+ return Object::null();
+ }
+
+ if (!isolate->GetDartStream()->Enabled()) {
+ // Dart stream is not enabled for this isolate, do nothing.
+ return Object::null();
+ }
+
+ GET_NON_NULL_NATIVE_ARGUMENT(Integer, start, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Integer, end, arguments->NativeArgAt(1));
+ GET_NON_NULL_NATIVE_ARGUMENT(String, category, arguments->NativeArgAt(2));
+ GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(3));
+ GET_NON_NULL_NATIVE_ARGUMENT(String, args, arguments->NativeArgAt(4));
+
+ int64_t duration = end.AsInt64Value() - start.AsInt64Value();
+ int64_t pid = OS::ProcessId();
+ int64_t tid = OSThread::ThreadIdToIntPtr(OSThread::GetCurrentThreadTraceId());
+
+ char* event = OS::SCreate(zone,
+ "{\"name\":\"%s\",\"cat\":\"%s\",\"tid\":%" Pd64 ",\"pid\":%" Pd64 ","
+ "\"ts\":%" Pd64 ",\"ph\":\"X\",\"dur\":%" Pd64 ",\"args\":%s}",
+ name.ToCString(),
+ category.ToCString(),
+ tid,
+ pid,
+ start.AsInt64Value(),
+ duration,
+ args.ToCString());
+
+ // event was allocated in the zone and will be copied by AppendDartEvent.
+ recorder->AppendDartEvent(isolate, event);
+
+ return Object::null();
+}
+
+} // namespace dart
diff --git a/runtime/lib/timeline.dart b/runtime/lib/timeline.dart
new file mode 100644
index 0000000..38ffa5f
--- /dev/null
+++ b/runtime/lib/timeline.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2015, 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:_internal';
+
+patch int _getTraceClock() native "Timeline_getTraceClock";
+
+patch void _reportCompleteEvent(
+ int start,
+ int end,
+ String category,
+ String name,
+ String argumentsAsJson) native "Timeline_reportCompleteEvent";
diff --git a/runtime/lib/vmservice.cc b/runtime/lib/vmservice.cc
new file mode 100644
index 0000000..29581b4
--- /dev/null
+++ b/runtime/lib/vmservice.cc
@@ -0,0 +1,149 @@
+// Copyright (c) 2015, 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.
+
+#include "vm/bootstrap_natives.h"
+
+#include "vm/dart_api_impl.h"
+#include "vm/exceptions.h"
+#include "vm/message.h"
+#include "vm/native_entry.h"
+#include "vm/object.h"
+#include "vm/port.h"
+#include "vm/service_isolate.h"
+#include "vm/symbols.h"
+
+namespace dart {
+
+DECLARE_FLAG(bool, trace_service);
+
+static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) {
+ void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
+ return reinterpret_cast<uint8_t*>(new_ptr);
+}
+
+
+class RegisterRunningIsolatesVisitor : public IsolateVisitor {
+ public:
+ explicit RegisterRunningIsolatesVisitor(Isolate* service_isolate)
+ : IsolateVisitor(),
+ register_function_(Function::Handle(service_isolate)),
+ service_isolate_(service_isolate) {
+ ASSERT(ServiceIsolate::IsServiceIsolate(Isolate::Current()));
+ // Get library.
+ const String& library_url = Symbols::DartVMService();
+ ASSERT(!library_url.IsNull());
+ const Library& library =
+ Library::Handle(Library::LookupLibrary(library_url));
+ ASSERT(!library.IsNull());
+ // Get function.
+ const String& function_name =
+ String::Handle(String::New("_registerIsolate"));
+ ASSERT(!function_name.IsNull());
+ register_function_ = library.LookupFunctionAllowPrivate(function_name);
+ ASSERT(!register_function_.IsNull());
+ }
+
+ virtual void VisitIsolate(Isolate* isolate) {
+ ASSERT(ServiceIsolate::IsServiceIsolate(Isolate::Current()));
+ if (ServiceIsolate::IsServiceIsolateDescendant(isolate) ||
+ (isolate == Dart::vm_isolate())) {
+ // We do not register the service (and descendants) or the vm-isolate.
+ return;
+ }
+ // Setup arguments for call.
+ Dart_Port port_id = isolate->main_port();
+ const Integer& port_int = Integer::Handle(Integer::New(port_id));
+ ASSERT(!port_int.IsNull());
+ const SendPort& send_port = SendPort::Handle(SendPort::New(port_id));
+ const String& name = String::Handle(String::New(isolate->name()));
+ ASSERT(!name.IsNull());
+ const Array& args = Array::Handle(Array::New(3));
+ ASSERT(!args.IsNull());
+ args.SetAt(0, port_int);
+ args.SetAt(1, send_port);
+ args.SetAt(2, name);
+ Object& r = Object::Handle(service_isolate_);
+ r = DartEntry::InvokeFunction(register_function_, args);
+ if (FLAG_trace_service) {
+ OS::Print("vm-service: Isolate %s %" Pd64 " registered.\n",
+ name.ToCString(),
+ port_id);
+ }
+ ASSERT(!r.IsError());
+ }
+
+ private:
+ Function& register_function_;
+ Isolate* service_isolate_;
+};
+
+
+DEFINE_NATIVE_ENTRY(VMService_SendIsolateServiceMessage, 2) {
+ GET_NON_NULL_NATIVE_ARGUMENT(SendPort, sp, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(1));
+
+ // Set the type of the OOB message.
+ message.SetAt(0, Smi::Handle(thread->zone(),
+ Smi::New(Message::kServiceOOBMsg)));
+
+ // Serialize message.
+ uint8_t* data = NULL;
+ MessageWriter writer(&data, &allocator, false);
+ writer.WriteMessage(message);
+
+ // TODO(turnidge): Throw an exception when the return value is false?
+ bool result = PortMap::PostMessage(
+ new Message(sp.Id(), data, writer.BytesWritten(),
+ Message::kOOBPriority));
+ return Bool::Get(result).raw();
+}
+
+
+DEFINE_NATIVE_ENTRY(VMService_SendRootServiceMessage, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0));
+ Service::HandleRootMessage(message);
+ return Object::null();
+}
+
+
+DEFINE_NATIVE_ENTRY(VMService_OnStart, 0) {
+ if (FLAG_trace_service) {
+ OS::Print("vm-service: Booting dart:vmservice library.\n");
+ }
+ // Boot the dart:vmservice library.
+ ServiceIsolate::BootVmServiceLibrary();
+
+ // Register running isolates with service.
+ RegisterRunningIsolatesVisitor register_isolates(isolate);
+ if (FLAG_trace_service) {
+ OS::Print("vm-service: Registering running isolates.\n");
+ }
+ Isolate::VisitIsolates(®ister_isolates);
+
+ return Object::null();
+}
+
+
+DEFINE_NATIVE_ENTRY(VMService_OnExit, 0) {
+ if (FLAG_trace_service) {
+ OS::Print("vm-service: processed exit message.\n");
+ }
+ return Object::null();
+}
+
+
+DEFINE_NATIVE_ENTRY(VMService_ListenStream, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0));
+ bool result = Service::ListenStream(stream_id.ToCString());
+ return Bool::Get(result).raw();
+}
+
+
+DEFINE_NATIVE_ENTRY(VMService_CancelStream, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0));
+ Service::CancelStream(stream_id.ToCString());
+ return Object::null();
+}
+
+} // namespace dart
diff --git a/runtime/vm/service/client.dart b/runtime/lib/vmservice/client.dart
similarity index 100%
rename from runtime/vm/service/client.dart
rename to runtime/lib/vmservice/client.dart
diff --git a/runtime/vm/service/constants.dart b/runtime/lib/vmservice/constants.dart
similarity index 100%
rename from runtime/vm/service/constants.dart
rename to runtime/lib/vmservice/constants.dart
diff --git a/runtime/vm/service/message.dart b/runtime/lib/vmservice/message.dart
similarity index 100%
rename from runtime/vm/service/message.dart
rename to runtime/lib/vmservice/message.dart
diff --git a/runtime/vm/service/message_router.dart b/runtime/lib/vmservice/message_router.dart
similarity index 100%
rename from runtime/vm/service/message_router.dart
rename to runtime/lib/vmservice/message_router.dart
diff --git a/runtime/vm/service/running_isolate.dart b/runtime/lib/vmservice/running_isolate.dart
similarity index 100%
rename from runtime/vm/service/running_isolate.dart
rename to runtime/lib/vmservice/running_isolate.dart
diff --git a/runtime/vm/service/running_isolates.dart b/runtime/lib/vmservice/running_isolates.dart
similarity index 100%
rename from runtime/vm/service/running_isolates.dart
rename to runtime/lib/vmservice/running_isolates.dart
diff --git a/runtime/vm/service/vmservice.dart b/runtime/lib/vmservice/vmservice.dart
similarity index 100%
rename from runtime/vm/service/vmservice.dart
rename to runtime/lib/vmservice/vmservice.dart
diff --git a/runtime/lib/vmservice_sources.gypi b/runtime/lib/vmservice_sources.gypi
new file mode 100644
index 0000000..9fb590a
--- /dev/null
+++ b/runtime/lib/vmservice_sources.gypi
@@ -0,0 +1,19 @@
+# Copyright (c) 2015, 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.
+
+# Sources that make up the library "dart:_vmservice".
+
+{
+ 'sources': [
+ 'vmservice/vmservice.dart',
+ # The above file needs to be first as it imports required libraries.
+ 'vmservice/client.dart',
+ 'vmservice/constants.dart',
+ 'vmservice/running_isolate.dart',
+ 'vmservice/running_isolates.dart',
+ 'vmservice/message.dart',
+ 'vmservice/message_router.dart',
+ 'vmservice.cc',
+ ],
+}
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index 8c1a2ed..4723358 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -1087,6 +1087,51 @@
'Syntax: refresh <subcommand>\n';
}
+class VmRestartCommand extends DebuggerCommand {
+ VmRestartCommand(Debugger debugger) : super(debugger, 'restart', []);
+
+ Future handleModalInput(String line) async {
+ if (line == 'yes') {
+ debugger.console.printRed('Restarting VM...');
+ await debugger.vm.restart();
+ debugger.input.exitMode();
+ } else if (line == 'no') {
+ debugger.console.printRed('VM restart canceled.');
+ debugger.input.exitMode();
+ } else {
+ debugger.console.printRed("Please type 'yes' or 'no'");
+ }
+ }
+
+ Future run(List<String> args) async {
+ debugger.input.enterMode('Restart vm? (yes/no)', handleModalInput);
+ }
+
+ String helpShort = 'Restart a Dart virtual machine';
+
+ String helpLong =
+ 'Restart a Dart virtual machine.\n'
+ '\n'
+ 'Syntax: vm restart\n';
+}
+
+class VmCommand extends DebuggerCommand {
+ VmCommand(Debugger debugger) : super(debugger, 'vm', [
+ new VmRestartCommand(debugger),
+ ]);
+
+ Future run(List<String> args) async {
+ debugger.console.print("'vm' expects a subcommand (see 'help vm')");
+ }
+
+ String helpShort = 'Manage a Dart virtual machine';
+
+ String helpLong =
+ 'Manage a Dart virtual machine.\n'
+ '\n'
+ 'Syntax: vm <subcommand>\n';
+}
+
class _ConsoleStreamPrinter {
ObservatoryDebugger _debugger;
@@ -1234,6 +1279,7 @@
new StepCommand(this),
new SyncNextCommand(this),
new UpCommand(this),
+ new VmCommand(this),
]);
_consolePrinter = new _ConsoleStreamPrinter(this);
}
@@ -1254,23 +1300,24 @@
}
_isolate.reload().then((response) {
+ if (response.isSentinel) {
+ // The isolate has gone away. The IsolateExit event will
+ // clear the isolate for the debugger page.
+ return;
+ }
// TODO(turnidge): Currently the debugger relies on all libs
// being loaded. Fix this.
var pending = [];
- for (var lib in _isolate.libraries) {
+ for (var lib in response.libraries) {
if (!lib.loaded) {
pending.add(lib.load());
}
}
Future.wait(pending).then((_) {
- _refreshStack(isolate.pauseEvent).then((_) {
- reportStatus();
- });
- }).catchError((_) {
- // Error loading libraries, try and display stack.
- _refreshStack(isolate.pauseEvent).then((_) {
- reportStatus();
- });
+ refreshStack();
+ }).catchError((e) {
+ print("UNEXPECTED ERROR $e");
+ reportStatus();
});
});
} else {
@@ -1300,10 +1347,16 @@
});
}
- Future refreshStack() {
- return _refreshStack(isolate.pauseEvent).then((_) {
+ Future refreshStack() async {
+ try {
+ if (_isolate != null) {
+ await _refreshStack(_isolate.pauseEvent);
+ }
+ flushStdio();
reportStatus();
- });
+ } catch (e, st) {
+ console.printRed("Unexpected error in refreshStack: $e\n$st");
+ }
}
bool isolatePaused() {
@@ -1326,9 +1379,12 @@
Future<ServiceMap> _refreshStack(ServiceEvent pauseEvent) {
return isolate.getStack().then((result) {
+ if (result.isSentinel) {
+ // The isolate has gone away. The IsolateExit event will
+ // clear the isolate for the debugger page.
+ return;
+ }
stack = result;
- // TODO(turnidge): Replace only the changed part of the stack to
- // reduce flicker.
stackElement.updateStack(stack, pauseEvent);
if (stack['frames'].length > 0) {
currentFrame = 0;
@@ -1364,8 +1420,7 @@
console.print(
"Paused at isolate exit "
"(type 'continue' or [F7] to exit the isolate')");
- }
- if (stack['frames'].length > 0) {
+ } else if (stack['frames'].length > 0) {
Frame frame = stack['frames'][0];
var script = frame.location.script;
script.load().then((_) {
@@ -1429,6 +1484,10 @@
var iso = event.owner;
console.print(
"Isolate ${iso.number} '${iso.name}' has been created");
+ if (isolate == null) {
+ console.print("Switching to isolate ${iso.number} '${iso.name}'");
+ isolate = iso;
+ }
}
break;
@@ -1436,7 +1495,17 @@
{
var iso = event.owner;
if (iso == isolate) {
- console.print("The current isolate has exited");
+ console.print("The current isolate ${iso.number} '${iso.name}' "
+ "has exited");
+ var isolates = vm.isolates;
+ if (isolates.length > 0) {
+ var newIsolate = isolates.first;
+ console.print("Switching to isolate "
+ "${newIsolate.number} '${newIsolate.name}'");
+ isolate = newIsolate;
+ } else {
+ isolate = null;
+ }
} else {
console.print(
"Isolate ${iso.number} '${iso.name}' has exited");
@@ -1693,9 +1762,7 @@
@published Isolate isolate;
isolateChanged(oldValue) {
- if (isolate != null) {
- debugger.updateIsolate(isolate);
- }
+ debugger.updateIsolate(isolate);
}
ObservatoryDebugger debugger = new ObservatoryDebugger();
@@ -2250,6 +2317,20 @@
@published String text = '';
@observable ObservatoryDebugger debugger;
@observable bool busy = false;
+ @observable String modalPrompt = null;
+ var modalCallback = null;
+
+ void enterMode(String prompt, callback) {
+ assert(prompt == null);
+ modalPrompt = prompt;
+ modalCallback = callback;
+ }
+
+ void exitMode() {
+ assert(prompt != null);
+ modalPrompt = null;
+ modalCallback = null;
+ }
@override
void ready() {
@@ -2262,7 +2343,19 @@
return;
}
busy = true;
- switch (e.keyCode) {
+ if (modalCallback != null) {
+ if (e.keyCode == KeyCode.ENTER) {
+ var response = text;
+ modalCallback(response).whenComplete(() {
+ text = '';
+ busy = false;
+ });
+ } else {
+ busy = false;
+ }
+ return;
+ }
+ switch (e.keyCode) {
case KeyCode.TAB:
e.preventDefault();
int cursorPos = textBox.selectionStart;
@@ -2358,7 +2451,7 @@
default:
busy = false;
break;
- }
+ }
});
}
diff --git a/runtime/observatory/lib/src/elements/debugger.html b/runtime/observatory/lib/src/elements/debugger.html
index 44195bf..5b74667 100644
--- a/runtime/observatory/lib/src/elements/debugger.html
+++ b/runtime/observatory/lib/src/elements/debugger.html
@@ -100,6 +100,7 @@
}
.console {
flex: 1 1 auto;
+ overflow-x: auto;
overflow-y: auto;
}
.commandline {
@@ -442,14 +443,34 @@
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
+ .container {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ }
.textBox {
+ flex: 1 1 auto;
margin: 20px;
padding: 5px;
font: 400 16px consolas, courier, monospace;
width: 95%;
}
+ .modalPrompt {
+ flex: 0 0 auto;
+ margin-top: 20px;
+ margin-left: 20px;
+ padding: 5px;
+ font: 400 16px consolas, courier, monospace;
+ color: red;
+ }
</style>
- <input id="textBox" class="textBox" type="text" value="{{ text }}" autofocus>
+ <div class="container">
+ <template if="{{ modalPrompt != null }}">
+ <div class="modalPrompt">{{ modalPrompt }}</div>
+ </template>
+ <input id="textBox" class="textBox" type="text" value="{{ text }}" autofocus>
+ </div>
</template>
</polymer-element>
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index fac9fc5..e65f5b7 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -637,7 +637,7 @@
@observable int architectureBits;
@observable bool assertsEnabled = false;
@observable bool typeChecksEnabled = false;
- @observable String pid = '';
+ @observable int pid = 0;
@observable DateTime startTime;
@observable DateTime refreshTime;
@observable Duration get upTime =>
@@ -803,6 +803,10 @@
}
}
+ Future restart() {
+ return invokeRpc('_restartVM', {});
+ }
+
Future<ObservableMap> _fetchDirect() async {
if (!loaded) {
// The vm service relies on these events to keep the VM and
@@ -877,7 +881,7 @@
version = map['version'];
targetCPU = map['targetCPU'];
architectureBits = map['architectureBits'];
- var startTimeMillis = map['startTime'].toInt();
+ int startTimeMillis = map['startTime'];
startTime = new DateTime.fromMillisecondsSinceEpoch(startTimeMillis);
refreshTime = new DateTime.now();
notifyPropertyChange(#upTime, 0, 1);
@@ -1270,9 +1274,6 @@
@observable String vmName;
@observable ServiceFunction entry;
- @observable final Map<String, double> timers =
- toObservable(new Map<String, double>());
-
final HeapSpace newSpace = new HeapSpace();
final HeapSpace oldSpace = new HeapSpace();
@@ -1348,7 +1349,7 @@
entry = map['entry'];
}
var savedStartTime = startTime;
- var startTimeInMillis = map['startTime'].toInt();
+ int startTimeInMillis = map['startTime'];
startTime = new DateTime.fromMillisecondsSinceEpoch(startTimeInMillis);
notifyPropertyChange(#upTime, 0, 1);
var countersMap = map['_tagCounters'];
@@ -1373,18 +1374,6 @@
}
}
}
- var timerMap = {};
- map['timers'].forEach((timer) {
- timerMap[timer['name']] = timer['time'];
- });
- timers['total'] = timerMap['time_total_runtime'];
- timers['compile'] = timerMap['time_compilation'];
- timers['gc'] = 0.0; // TODO(turnidge): Export this from VM.
- timers['init'] = (timerMap['time_script_loading'] +
- timerMap['time_creating_snapshot'] +
- timerMap['time_isolate_initialization'] +
- timerMap['time_bootstrap']);
- timers['dart'] = timerMap['time_dart_execution'];
updateHeapsFromMap(map['_heaps']);
_updateBreakpoints(map['breakpoints']);
@@ -1532,7 +1521,7 @@
if (col != null) {
params['column'] = col.toString();
}
- return invokeRpc('addBreakpoint', params);
+ return invokeRpc('addBreakpointWithScriptUri', params);
}
Future<ServiceObject> addBreakpointAtEntry(ServiceFunction function) {
@@ -1894,7 +1883,7 @@
_upgradeCollection(map, owner);
assert(map['isolate'] == null || owner == map['isolate']);
timestamp =
- new DateTime.fromMillisecondsSinceEpoch(map['timestamp'].toInt());
+ new DateTime.fromMillisecondsSinceEpoch(map['timestamp']);
kind = map['kind'];
notifyPropertyChange(#isPauseEvent, 0, 1);
name = 'ServiceEvent $kind';
@@ -1949,7 +1938,7 @@
if (map['logRecord'] != null) {
logRecord = map['logRecord'];
logRecord['time'] =
- new DateTime.fromMillisecondsSinceEpoch(logRecord['time'].toInt());
+ new DateTime.fromMillisecondsSinceEpoch(logRecord['time']);
logRecord['level'] = _findLogLevel(logRecord['level']);
}
}
diff --git a/runtime/observatory/tests/service/get_vm_rpc_test.dart b/runtime/observatory/tests/service/get_vm_rpc_test.dart
index 6aa8e33..d9884bd 100644
--- a/runtime/observatory/tests/service/get_vm_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_vm_rpc_test.dart
@@ -16,7 +16,7 @@
expect(result['targetCPU'], new isInstanceOf<String>());
expect(result['hostCPU'], new isInstanceOf<String>());
expect(result['version'], new isInstanceOf<String>());
- expect(result['pid'], new isInstanceOf<String>());
+ expect(result['pid'], new isInstanceOf<int>());
expect(result['startTime'], isPositive);
expect(result['isolates'].length, isPositive);
expect(result['isolates'][0]['type'], equals('@Isolate'));
diff --git a/runtime/observatory/tests/service/vm_restart_test.dart b/runtime/observatory/tests/service/vm_restart_test.dart
new file mode 100644
index 0000000..de6397f
--- /dev/null
+++ b/runtime/observatory/tests/service/vm_restart_test.dart
@@ -0,0 +1,106 @@
+// Copyright (c) 2015, 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.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override
+
+import 'dart:async';
+import 'dart:developer';
+import 'dart:io';
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'test_helper.dart';
+
+int count = 0;
+
+void test() {
+ while (true) {
+ count++;
+ debugger();
+ }
+}
+
+var tests = [
+ hasStoppedAtBreakpoint,
+
+ (Isolate isolate) async {
+ // The loop has run one time.
+ var result = await isolate.rootLibrary.evaluate('count');
+ expect(result.type, equals('Instance'));
+ expect(result.valueAsString, equals('1'));
+
+ Completer completer = new Completer();
+ var stream = await isolate.vm.getEventStream(VM.kDebugStream);
+ var subscription;
+ subscription = stream.listen((ServiceEvent event) {
+ if (event.kind == ServiceEvent.kResume) {
+ subscription.cancel();
+ completer.complete();
+ }
+ });
+ isolate.resume();
+ await completer.future;
+
+ // The loop has run twice.
+ result = await isolate.rootLibrary.evaluate('count');
+ expect(result.type, equals('Instance'));
+ expect(result.valueAsString, equals('2'));
+ },
+
+ hasStoppedAtBreakpoint,
+
+ (Isolate isolate) async {
+ Isolate newIsolate = null;
+
+ Completer testCompleter = new Completer();
+ var debugStream = await isolate.vm.getEventStream(VM.kDebugStream);
+ var debugSub;
+ debugSub = debugStream.listen((ServiceEvent event) {
+ if (event.kind == ServiceEvent.kPauseBreakpoint) {
+ if (event.isolate == newIsolate) {
+ // The old isolate has died and the new isolate is at
+ // the breakpoint.
+ newIsolate.reload().then((_) {
+ newIsolate.rootLibrary.evaluate('count').then((result) {
+ expect(result.type, equals('Instance'));
+ expect(result.valueAsString, equals('1'));
+ debugSub.cancel();
+ testCompleter.complete();
+ });
+ });
+ }
+ }
+ });
+
+ Completer restartCompleter = new Completer();
+ var isolateStream = await isolate.vm.getEventStream(VM.kIsolateStream);
+ var isolateSub;
+ bool exit = false;
+ bool start = false;
+ isolateSub = isolateStream.listen((ServiceEvent event) {
+ if (event.kind == ServiceEvent.kIsolateExit) {
+ expect(event.isolate, equals(isolate));
+ print('Old isolate exited');
+ exit = true;
+ }
+ if (event.kind == ServiceEvent.kIsolateStart) {
+ print('New isolate started');
+ newIsolate = event.isolate;
+ start = true;
+ }
+ if (exit && start) {
+ isolateSub.cancel();
+ restartCompleter.complete();
+ }
+ });
+
+ // Restart the vm.
+ print("restarting");
+ await isolate.vm.restart();
+ await restartCompleter.future;
+ print("restarted");
+ await testCompleter.future;
+ },
+];
+
+
+main(args) => runIsolateTests(args, tests, testeeConcurrent: test);
diff --git a/runtime/tools/verbose_gc_to_bmu.dart b/runtime/tools/verbose_gc_to_bmu.dart
index ccf9306..67c1605 100644
--- a/runtime/tools/verbose_gc_to_bmu.dart
+++ b/runtime/tools/verbose_gc_to_bmu.dart
@@ -1,7 +1,9 @@
// Copyright (c) 2014, 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.
-
+//
+// NOTE: See also wrapper script sdk/runtime/tools/bmu_benchmark_gallery.sh
+//
// Tool to compute bounded mutator utilization (BMU) from a --verbose_gc log.
// Outputs CSV suitable for, e.g., gnuplot:
//
diff --git a/runtime/vm/allocation.cc b/runtime/vm/allocation.cc
index b6fda7b..b5f0f6c 100644
--- a/runtime/vm/allocation.cc
+++ b/runtime/vm/allocation.cc
@@ -6,6 +6,7 @@
#include "platform/assert.h"
#include "vm/isolate.h"
+#include "vm/thread.h"
#include "vm/zone.h"
namespace dart {
@@ -30,6 +31,41 @@
}
+StackResource::~StackResource() {
+ if (thread_ != NULL) {
+ StackResource* top = thread_->top_resource();
+ ASSERT(top == this);
+ thread_->set_top_resource(previous_);
+ }
+#if defined(DEBUG)
+ if (thread_ != NULL) {
+ ASSERT(Thread::Current() == thread_);
+ BaseIsolate::AssertCurrent(reinterpret_cast<BaseIsolate*>(isolate()));
+ }
+#endif
+}
+
+
+Isolate* StackResource::isolate() const {
+ return thread_ == NULL ? NULL : thread_->isolate();
+}
+
+
+void StackResource::Init(Thread* thread) {
+ // We can only have longjumps and exceptions when there is a current
+ // thread and isolate. If there is no current thread, we don't need to
+ // protect this case.
+ // TODO(23807): Eliminate this special case.
+ if (thread != NULL) {
+ ASSERT(Thread::Current() == thread);
+ thread_ = thread;
+ previous_ = thread_->top_resource();
+ ASSERT((previous_ == NULL) || (previous_->thread_ == thread));
+ thread_->set_top_resource(this);
+ }
+}
+
+
void StackResource::UnwindAbove(Thread* thread, StackResource* new_top) {
StackResource* current_resource = thread->top_resource();
while (current_resource != new_top) {
diff --git a/runtime/vm/allocation.h b/runtime/vm/allocation.h
index 74a2d7d..468c1ad 100644
--- a/runtime/vm/allocation.h
+++ b/runtime/vm/allocation.h
@@ -8,12 +8,12 @@
#include "platform/assert.h"
#include "vm/base_isolate.h"
#include "vm/globals.h"
-#include "vm/thread.h"
namespace dart {
// Forward declarations.
class Isolate;
+class Thread;
// Stack allocated objects subclass from this base class. Objects of this type
// cannot be allocated on either the C or object heaps. Destructors for objects
@@ -48,24 +48,10 @@
Init(thread);
}
- virtual ~StackResource() {
- if (thread_ != NULL) {
- StackResource* top = thread_->top_resource();
- ASSERT(top == this);
- thread_->set_top_resource(previous_);
- }
-#if defined(DEBUG)
- if (thread_ != NULL) {
- ASSERT(Thread::Current() == thread_);
- BaseIsolate::AssertCurrent(reinterpret_cast<BaseIsolate*>(isolate()));
- }
-#endif
- }
+ virtual ~StackResource();
// Convenient access to the isolate of the thread of this resource.
- Isolate* isolate() const {
- return thread_ == NULL ? NULL : thread_->isolate();
- }
+ Isolate* isolate() const;
// The thread that owns this resource.
Thread* thread() const { return thread_; }
@@ -76,19 +62,7 @@
static void UnwindAbove(Thread* thread, StackResource* new_top);
private:
- void Init(Thread* thread) {
- // We can only have longjumps and exceptions when there is a current
- // thread and isolate. If there is no current thread, we don't need to
- // protect this case.
- // TODO(23807): Eliminate this special case.
- if (thread != NULL) {
- ASSERT(Thread::Current() == thread);
- thread_ = thread;
- previous_ = thread_->top_resource();
- ASSERT((previous_ == NULL) || (previous_->thread_ == thread));
- thread_->set_top_resource(this);
- }
- }
+ void Init(Thread* thread);
Thread* thread_;
StackResource* previous_;
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index 2da0383..7fe4193 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -96,8 +96,13 @@
void Assembler::pushl(const Immediate& imm) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
- EmitUint8(0x68);
- EmitImmediate(imm);
+ if (imm.is_int8()) {
+ EmitUint8(0x6A);
+ EmitUint8(imm.value() & 0xFF);
+ } else {
+ EmitUint8(0x68);
+ EmitImmediate(imm);
+ }
}
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index c391612..075ac70 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -787,6 +787,10 @@
Register array,
Register index);
+ static Address VMTagAddress() {
+ return Address(THR, Thread::vm_tag_offset());
+ }
+
/*
* Misc. functionality
*/
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index 714e2d8..5316110 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -1593,6 +1593,10 @@
Register array,
Register index);
+ static Address VMTagAddress() {
+ return Address(THR, Thread::vm_tag_offset());
+ }
+
// On some other platforms, we draw a distinction between safe and unsafe
// smis.
static bool IsSafe(const Object& object) { return true; }
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 87c1f31..0919521 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -122,7 +122,11 @@
void Assembler::pushq(const Immediate& imm) {
- if (imm.is_int32()) {
+ if (imm.is_int8()) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x6A);
+ EmitUint8(imm.value() & 0xFF);
+ } else if (imm.is_int32()) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x68);
EmitImmediate(imm);
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index 89b2944..0a6b694 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -1032,6 +1032,10 @@
Register array,
Register index);
+ static Address VMTagAddress() {
+ return Address(THR, Thread::vm_tag_offset());
+ }
+
// On some other platforms, we draw a distinction between safe and unsafe
// smis.
static bool IsSafe(const Object& object) { return true; }
diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h
index fa4ba21..c3b6ac1 100644
--- a/runtime/vm/ast.h
+++ b/runtime/vm/ast.h
@@ -1226,7 +1226,6 @@
};
-
class LoadInstanceFieldNode : public AstNode {
public:
LoadInstanceFieldNode(intptr_t token_pos,
diff --git a/runtime/vm/ast_transformer.cc b/runtime/vm/ast_transformer.cc
index b4583cf..95d8d4f 100644
--- a/runtime/vm/ast_transformer.cc
+++ b/runtime/vm/ast_transformer.cc
@@ -567,12 +567,21 @@
node->TempAt(i),
new_init_val));
}
- // The transformed LetNode does not have any temporary variables.
- LetNode* result = new(Z) LetNode(node->token_pos());
- for (intptr_t i = 0; i < node->nodes().length(); i++) {
- result->AddNode(Transform(node->nodes()[i]));
+
+ // Add all expressions but the last to the preamble. We must do
+ // this because subexpressions of the awaitable expression we
+ // are currently transforming may depend on each other,
+ // e.g. await foo(a++, a++). Thus we must preserve the order of the
+ // transformed subexpressions.
+ for (intptr_t i = 0; i < node->nodes().length() - 1; i++) {
+ preamble_->Add(Transform(node->nodes()[i]));
}
- result_ = result;
+
+ // The last expression in the let node is the value of the node.
+ // The result of the transformed let node is this expression.
+ ASSERT(node->nodes().length() > 0);
+ const intptr_t last_node_index = node->nodes().length() - 1;
+ result_ = Transform(node->nodes()[last_node_index]);
}
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index 912aa1f..a01f107 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -75,6 +75,10 @@
typed_data,
Bootstrap::typed_data_source_paths_,
Bootstrap::typed_data_patch_paths_),
+ INIT_LIBRARY(ObjectStore::kVMService,
+ _vmservice,
+ Bootstrap::vmservice_source_paths_,
+ NULL),
{ ObjectStore::kNone, NULL, NULL, NULL, NULL }
};
diff --git a/runtime/vm/bootstrap.h b/runtime/vm/bootstrap.h
index 76758b6..ddb7d74 100644
--- a/runtime/vm/bootstrap.h
+++ b/runtime/vm/bootstrap.h
@@ -33,6 +33,7 @@
static const char* profiler_source_paths_[];
static const char* typed_data_source_paths_[];
static const char* utf_source_paths_[];
+ static const char* vmservice_source_paths_[];
// Source path mapping for patch URI and 'parts'.
static const char* async_patch_paths_[];
diff --git a/runtime/vm/bootstrap_natives.cc b/runtime/vm/bootstrap_natives.cc
index 07c4928..d0bef86 100644
--- a/runtime/vm/bootstrap_natives.cc
+++ b/runtime/vm/bootstrap_natives.cc
@@ -10,6 +10,7 @@
#include "vm/dart_api_impl.h"
#include "vm/object.h"
#include "vm/object_store.h"
+#include "vm/service_isolate.h"
namespace dart {
@@ -129,6 +130,11 @@
ASSERT(!library.IsNull());
library.set_native_entry_resolver(resolver);
library.set_native_entry_symbol_resolver(symbol_resolver);
+
+ library = Library::VMServiceLibrary();
+ ASSERT(!library.IsNull());
+ library.set_native_entry_resolver(resolver);
+ library.set_native_entry_symbol_resolver(symbol_resolver);
}
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 38a92de..9e6e507 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -149,11 +149,14 @@
V(DateNatives_timeZoneOffsetInSeconds, 1) \
V(DateNatives_localTimeZoneAdjustmentInSeconds, 0) \
V(AssertionError_throwNew, 2) \
+ V(Async_rethrow, 2) \
V(TypeError_throwNew, 5) \
V(FallThroughError_throwNew, 1) \
V(AbstractClassInstantiationError_throwNew, 2) \
V(Stopwatch_now, 0) \
V(Stopwatch_frequency, 0) \
+ V(Timeline_getTraceClock, 0) \
+ V(Timeline_reportCompleteEvent, 5) \
V(TypedData_Int8Array_new, 1) \
V(TypedData_Uint8Array_new, 1) \
V(TypedData_Uint8ClampedArray_new, 1) \
@@ -302,7 +305,7 @@
V(Int32x4_setFlagW, 2) \
V(Int32x4_select, 3) \
V(Isolate_spawnFunction, 7) \
- V(Isolate_spawnUri, 10) \
+ V(Isolate_spawnUri, 12) \
V(Isolate_getPortAndCapabilitiesOfCurrentIsolate, 0) \
V(Isolate_sendOOB, 2) \
V(Mirrors_evalInLibraryWithPrivateKey, 2) \
@@ -391,7 +394,12 @@
V(Profiler_getCurrentTag, 0) \
V(ClassID_getID, 1) \
V(Num_toString, 1) \
-
+ V(VMService_SendIsolateServiceMessage, 2) \
+ V(VMService_SendRootServiceMessage, 1) \
+ V(VMService_OnStart, 0) \
+ V(VMService_OnExit, 0) \
+ V(VMService_ListenStream, 1) \
+ V(VMService_CancelStream, 1) \
class BootstrapNatives : public AllStatic {
public:
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index e6d61bc..7638850 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -19,7 +19,6 @@
DEFINE_FLAG(bool, print_classes, false, "Prints details about loaded classes.");
DEFINE_FLAG(bool, trace_class_finalization, false, "Trace class finalization.");
DEFINE_FLAG(bool, trace_type_finalization, false, "Trace type finalization.");
-DECLARE_FLAG(bool, supermixin);
DECLARE_FLAG(bool, use_cha_deopt);
@@ -2032,25 +2031,6 @@
class_name.ToCString());
}
- if (!FLAG_supermixin) {
- // Check that the super class of the mixin class is class Object.
- Class& mixin_super_class = Class::Handle(mixin_class.SuperClass());
- // Skip over mixin application alias classes, which are implemented as
- // subclasses of the mixin application classes they name.
- if (!mixin_super_class.IsNull() && mixin_class.is_mixin_app_alias()) {
- while (mixin_super_class.is_mixin_app_alias()) {
- mixin_super_class = mixin_super_class.SuperClass();
- }
- mixin_super_class = mixin_super_class.SuperClass();
- }
- if (mixin_super_class.IsNull() || !mixin_super_class.IsObjectClass()) {
- const String& class_name = String::Handle(mixin_class.Name());
- ReportError(mixin_app_class, mixin_app_class.token_pos(),
- "mixin class '%s' must extend class 'Object'",
- class_name.ToCString());
- }
- }
-
// Copy type parameters to mixin application class.
CloneMixinAppTypeParameters(mixin_app_class);
@@ -3156,21 +3136,23 @@
void ClassFinalizer::VerifyImplicitFieldOffsets() {
#ifdef DEBUG
- Isolate* isolate = Isolate::Current();
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ Zone* zone = thread->zone();
const ClassTable& class_table = *(isolate->class_table());
- Class& cls = Class::Handle(isolate);
- Array& fields_array = Array::Handle(isolate);
- Field& field = Field::Handle(isolate);
- String& name = String::Handle(isolate);
- String& expected_name = String::Handle(isolate);
- Error& error = Error::Handle(isolate);
+ Class& cls = Class::Handle(zone);
+ Array& fields_array = Array::Handle(zone);
+ Field& field = Field::Handle(zone);
+ String& name = String::Handle(zone);
+ String& expected_name = String::Handle(zone);
+ Error& error = Error::Handle(zone);
// First verify field offsets of all the TypedDataView classes.
for (intptr_t cid = kTypedDataInt8ArrayViewCid;
cid <= kTypedDataFloat32x4ArrayViewCid;
cid++) {
cls = class_table.At(cid); // Get the TypedDataView class.
- error = cls.EnsureIsFinalized(isolate);
+ error = cls.EnsureIsFinalized(thread);
ASSERT(error.IsNull());
cls = cls.SuperClass(); // Get it's super class '_TypedListView'.
cls = cls.SuperClass();
@@ -3193,7 +3175,7 @@
// Now verify field offsets of '_ByteDataView' class.
cls = class_table.At(kByteDataViewCid);
- error = cls.EnsureIsFinalized(isolate);
+ error = cls.EnsureIsFinalized(thread);
ASSERT(error.IsNull());
fields_array ^= cls.fields();
ASSERT(fields_array.Length() == TypedDataView::NumberOfFields());
@@ -3214,7 +3196,7 @@
// Now verify field offsets of '_ByteBuffer' class.
cls = class_table.At(kByteBufferCid);
- error = cls.EnsureIsFinalized(isolate);
+ error = cls.EnsureIsFinalized(thread);
ASSERT(error.IsNull());
fields_array ^= cls.fields();
ASSERT(fields_array.Length() == ByteBuffer::NumberOfFields());
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index f844cea..5179b4a 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -31,6 +31,8 @@
DEFINE_FLAG(bool, deoptimize_alot, false,
"Deoptimizes all live frames when we are about to return to Dart code from"
" native entries.");
+DEFINE_FLAG(bool, background_compilation, false,
+ "Run optimizing compilation in background");
DEFINE_FLAG(int, max_subtype_cache_entries, 100,
"Maximum number of subtype cache entries (number of checks cached).");
DEFINE_FLAG(int, optimization_counter_threshold, 30000,
@@ -1449,6 +1451,14 @@
// Reset usage counter for reoptimization before calling optimizer to
// prevent recursive triggering of function optimization.
function.set_usage_counter(0);
+ if (FLAG_background_compilation) {
+ BackgroundCompiler::EnsureInit(isolate);
+ ASSERT(isolate->background_compiler() != NULL);
+ isolate->background_compiler()->CompileOptimized(function);
+ // Continue in the same code.
+ arguments.SetReturn(Code::Handle(isolate, function.CurrentCode()));
+ return;
+ }
if (FLAG_trace_compiler) {
if (function.HasOptimizedCode()) {
THR_Print("ReCompiling function: '%s' \n",
@@ -1542,7 +1552,7 @@
Code& alloc_stub = Code::Handle(isolate, alloc_class.allocation_stub());
if (alloc_stub.IsNull()) {
alloc_stub = StubCode::GetAllocationStubForClass(alloc_class);
- ASSERT(!CodePatcher::IsEntryPatched(alloc_stub));
+ ASSERT(!alloc_stub.IsDisabled());
}
CodePatcher::PatchStaticCallAt(frame->pc(),
caller_code,
diff --git a/runtime/vm/code_patcher.cc b/runtime/vm/code_patcher.cc
index c1fe9f7..c62be00 100644
--- a/runtime/vm/code_patcher.cc
+++ b/runtime/vm/code_patcher.cc
@@ -34,26 +34,4 @@
}
}
-
-// The patch code buffer contains the jmp code which will be inserted at
-// entry point.
-void CodePatcher::PatchEntry(const Code& code, const Code& new_code) {
- ASSERT(code.instructions() == code.active_instructions());
- code.set_active_instructions(new_code.instructions());
-}
-
-
-// The entry point is a jmp instruction, the patch code buffer contains
-// original code, the entry point contains the jump instruction.
-void CodePatcher::RestoreEntry(const Code& code) {
- if (!IsEntryPatched(code)) return;
- ASSERT(code.instructions() != code.active_instructions());
- code.set_active_instructions(code.instructions());
-}
-
-
-bool CodePatcher::IsEntryPatched(const Code& code) {
- return code.instructions() != code.active_instructions();
-}
-
} // namespace dart
diff --git a/runtime/vm/code_patcher.h b/runtime/vm/code_patcher.h
index 2f747f2..dc27168 100644
--- a/runtime/vm/code_patcher.h
+++ b/runtime/vm/code_patcher.h
@@ -49,15 +49,6 @@
const Code& code,
const Code& new_target);
- // Patch entry point with a jump as specified in the code's patch region.
- static void PatchEntry(const Code& code, const Code& new_code);
-
- // Restore entry point with original code (i.e., before patching).
- static void RestoreEntry(const Code& code);
-
- // Has the entry been patched?
- static bool IsEntryPatched(const Code& code);
-
// Return the target address of the static call before return_address
// in given code.
static RawCode* GetStaticCallTargetAt(uword return_address, const Code& code);
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index fb57537..666a47b 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -68,7 +68,6 @@
DECLARE_FLAG(bool, trace_failed_optimization_attempts);
DECLARE_FLAG(bool, trace_inlining_intervals);
DECLARE_FLAG(bool, trace_irregexp);
-DECLARE_FLAG(bool, trace_patching);
bool Compiler::always_optimize_ = false;
@@ -758,17 +757,7 @@
if (optimized) {
// We may not have previous code if 'always_optimize' is set.
if ((osr_id == Isolate::kNoDeoptId) && function.HasCode()) {
- CodePatcher::PatchEntry(
- Code::Handle(function.CurrentCode()),
- Code::Handle(StubCode::FixCallersTarget_entry()->code()));
- if (FLAG_trace_compiler || FLAG_trace_patching) {
- if (FLAG_trace_compiler) {
- THR_Print(" ");
- }
- THR_Print("Patch unoptimized '%s' entry point %#" Px "\n",
- function.ToFullyQualifiedCString(),
- Code::Handle(function.unoptimized_code()).EntryPoint());
- }
+ Code::Handle(function.CurrentCode()).DisableDartCode();
}
function.AttachCode(code);
@@ -1021,7 +1010,6 @@
Isolate* const isolate = thread->isolate();
StackZone stack_zone(thread);
Zone* const zone = stack_zone.GetZone();
- TIMERSCOPE(thread, time_compilation);
Timer per_compile_timer(FLAG_trace_compiler, "Compilation time");
per_compile_timer.Start();
@@ -1414,4 +1402,164 @@
return Object::null();
}
+
+// A simple work queue containing functions to be optimized. Use
+// PushFront and PopBack to add and read from queue.
+// TODO(srdjan): Write a more efficient implementation.
+class CompilationWorkQueue : public ValueObject {
+ public:
+ explicit CompilationWorkQueue(Isolate* isolate) :
+ data_(GrowableObjectArray::Handle()) {
+ data_ = isolate->background_compilation_queue();
+ }
+
+ intptr_t IsEmpty() const { return data_.Length() == 0; }
+
+ // Adds to the queue only if 'function' is not already in there.
+ void PushFront(const Function& function) {
+ for (intptr_t i = 0; i < data_.Length(); i++) {
+ if (data_.At(i) == function.raw()) {
+ return;
+ }
+ }
+ // Insert new element in front.
+ Object& f = Object::Handle();
+ data_.Add(f);
+ for (intptr_t i = data_.Length() - 1; i > 0; i--) {
+ f = data_.At(i - 1);
+ data_.SetAt(i, f);
+ }
+ data_.SetAt(0, function);
+ }
+
+ RawFunction* PopBack() {
+ ASSERT(!IsEmpty());
+ Object& result = Object::Handle();
+ result = data_.At(data_.Length() - 1);
+ data_.SetLength(data_.Length() - 1);
+ return Function::Cast(result).raw();
+ }
+
+ private:
+ GrowableObjectArray& data_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationWorkQueue);
+};
+
+
+BackgroundCompiler::BackgroundCompiler(Isolate* isolate)
+ : isolate_(isolate), running_(true), done_(new bool()),
+ monitor_(new Monitor()), done_monitor_(new Monitor()) {
+ *done_ = false;
+}
+
+
+void BackgroundCompiler::Run() {
+ while (running_) {
+ {
+ // Wait to be notified when the work queue is not empty.
+ MonitorLocker ml(monitor_);
+ ml.Wait();
+ }
+
+ Thread::EnterIsolateAsHelper(isolate_);
+ {
+ Thread* thread = Thread::Current();
+ StackZone stack_zone(thread);
+ HANDLESCOPE(thread);
+ Function& function = Function::Handle();
+ function = RemoveOrNull();
+ while (!function.IsNull()) {
+ if (true) {
+ // Debugging printing
+ THR_Print("Background compilation: %s\n",
+ function.ToQualifiedCString());
+ } else {
+ const Error& error = Error::Handle(
+ Compiler::CompileOptimizedFunction(thread, function));
+ // TODO(srdjan): We do not expect errors while compiling optimized
+ // code, any errors should have been caught when compiling
+ // unotpimized code.
+ // If it still happens mark function as not optimizable.
+ ASSERT(error.IsNull());
+ }
+ function = RemoveOrNull();
+ }
+ }
+ Thread::ExitIsolateAsHelper();
+ }
+ {
+ // Notify that the thread is done.
+ MonitorLocker ml_done(done_monitor_);
+ *done_ = true;
+ ml_done.Notify();
+ }
+}
+
+
+void BackgroundCompiler::CompileOptimized(const Function& function) {
+ Add(function);
+}
+
+
+void BackgroundCompiler::Add(const Function& f) const {
+ MonitorLocker ml(monitor_);
+ CompilationWorkQueue queue(isolate_);
+ queue.PushFront(f);
+ ml.Notify();
+}
+
+
+RawFunction* BackgroundCompiler::RemoveOrNull() const {
+ MonitorLocker ml(monitor_);
+ CompilationWorkQueue queue(isolate_);
+ return queue.IsEmpty() ? Function::null() : queue.PopBack();
+}
+
+
+void BackgroundCompiler::Stop(BackgroundCompiler* task) {
+ if (task == NULL) {
+ return;
+ }
+ Monitor* monitor = task->monitor_;
+ Monitor* done_monitor = task->done_monitor_;
+ bool* task_done = task->done_;
+ // Wake up compiler task and stop it.
+ {
+ MonitorLocker ml(task->monitor_);
+ task->running_ = false;
+ // 'task' will be deleted by thread pool.
+ task = NULL;
+ ml.Notify();
+ }
+
+ {
+ MonitorLocker ml_done(done_monitor);
+ while (!(*task_done)) {
+ ml_done.Wait();
+ }
+ }
+ delete task_done;
+ delete done_monitor;
+ delete monitor;
+}
+
+
+void BackgroundCompiler::EnsureInit(Isolate* isolate) {
+ bool start_task = false;
+ {
+ MutexLocker ml(isolate->mutex());
+ if (isolate->background_compiler() == NULL) {
+ BackgroundCompiler* task = new BackgroundCompiler(isolate);
+ isolate->set_background_compiler(task);
+ isolate->set_background_compilation_queue(
+ GrowableObjectArray::Handle(isolate, GrowableObjectArray::New()));
+ start_task = true;
+ }
+ }
+ if (start_task) {
+ Dart::thread_pool()->Run(isolate->background_compiler());
+ }
+}
+
} // namespace dart
diff --git a/runtime/vm/compiler.h b/runtime/vm/compiler.h
index 9dc11b8..f31e00a 100644
--- a/runtime/vm/compiler.h
+++ b/runtime/vm/compiler.h
@@ -8,6 +8,7 @@
#include "vm/allocation.h"
#include "vm/growable_array.h"
#include "vm/runtime_entry.h"
+#include "vm/thread_pool.h"
namespace dart {
@@ -99,6 +100,35 @@
static bool allow_recompilation_;
};
+
+// Class to run optimizing compilation in a background thread.
+// Current implementation: one task per isolate, it dies with the owning
+// isolate.
+class BackgroundCompiler : public ThreadPool::Task {
+ public:
+ static void EnsureInit(Isolate* isolate);
+
+ static void Stop(BackgroundCompiler* task);
+
+ void CompileOptimized(const Function& function);
+
+ private:
+ explicit BackgroundCompiler(Isolate* isolate);
+
+ virtual void Run();
+
+ void Add(const Function& f) const;
+ RawFunction* RemoveOrNull() const;
+
+ Isolate* isolate_;
+ bool running_;
+ bool* done_;
+ Monitor* monitor_;
+ Monitor* done_monitor_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(BackgroundCompiler);
+};
+
} // namespace dart
#endif // VM_COMPILER_H_
diff --git a/runtime/vm/constant_propagator.cc b/runtime/vm/constant_propagator.cc
index 37e81b6..6ccc307 100644
--- a/runtime/vm/constant_propagator.cc
+++ b/runtime/vm/constant_propagator.cc
@@ -1020,7 +1020,7 @@
if (IsConstant(value) && value.IsInteger()) {
SetValue(instr, Double::Handle(I,
Double::New(Integer::Cast(value).AsDoubleValue(), Heap::kOld)));
- } else if (IsNonConstant(value)) {
+ } else if (!IsUnknown(value)) {
SetValue(instr, non_constant_);
}
}
@@ -1031,7 +1031,7 @@
if (IsConstant(value) && value.IsInteger()) {
SetValue(instr, Double::Handle(I,
Double::New(Integer::Cast(value).AsDoubleValue(), Heap::kOld)));
- } else if (IsNonConstant(value)) {
+ } else if (!IsUnknown(value)) {
SetValue(instr, non_constant_);
}
}
@@ -1042,7 +1042,7 @@
if (IsConstant(value) && value.IsInteger()) {
SetValue(instr, Double::Handle(I,
Double::New(Integer::Cast(value).AsDoubleValue(), Heap::kOld)));
- } else if (IsNonConstant(value)) {
+ } else if (!IsUnknown(value)) {
SetValue(instr, non_constant_);
}
}
diff --git a/runtime/vm/coverage.cc b/runtime/vm/coverage.cc
index 82e7b54..65dc7e1 100644
--- a/runtime/vm/coverage.cc
+++ b/runtime/vm/coverage.cc
@@ -142,8 +142,7 @@
CoverageFilter* filter,
bool as_call_sites) {
Thread* thread = Thread::Current();
- Isolate* isolate = thread->isolate();
- if (cls.EnsureIsFinalized(isolate) != Error::null()) {
+ if (cls.EnsureIsFinalized(thread) != Error::null()) {
// Only classes that have been finalized do have a meaningful list of
// functions.
return;
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index fcb7dbc..1d9105d 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -233,7 +233,7 @@
Isolate::DisableIsolateCreation();
// Send the OOB Kill message to all remaining application isolates.
- Isolate::KillAllIsolates();
+ Isolate::KillAllIsolates(Isolate::kInternalKillMsg);
// Shutdown the service isolate.
ServiceIsolate::Shutdown();
@@ -281,7 +281,6 @@
// Initialize the new isolate.
Thread* T = Thread::Current();
Isolate* I = T->isolate();
- TIMERSCOPE(T, time_isolate_initialization);
TimelineDurationScope tds(I, I->GetIsolateStream(), "InitializeIsolate");
tds.SetNumArguments(1);
tds.CopyArgument(0, "isolateName", I->name());
@@ -364,7 +363,7 @@
I->class_table()->Print();
}
- ServiceIsolate::MaybeInjectVMServiceLibrary(I);
+ ServiceIsolate::MaybeMakeServiceIsolate(I);
ServiceIsolate::SendIsolateStartupMessage();
I->debugger()->NotifyIsolateCreated();
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index b55cdb0..473a665 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -747,6 +747,13 @@
}
+DART_EXPORT bool Dart_IsVMRestartRequest(Dart_Handle handle) {
+ DARTSCOPE(Thread::Current());
+ const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
+ return (obj.IsUnwindError() && UnwindError::Cast(obj).is_vm_restart());
+}
+
+
DART_EXPORT const char* Dart_GetError(Dart_Handle handle) {
DARTSCOPE(Thread::Current());
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
@@ -1378,7 +1385,6 @@
#endif // defined(DART_NO_SNAPSHOT).
// We exit the API scope entered above.
Dart_ExitScope();
- START_TIMER(I, time_total_runtime);
return Api::CastIsolate(I);
}
*error = strdup(error_obj.ToErrorCString());
@@ -1399,7 +1405,6 @@
HandleScope handle_scope(T);
Dart::RunShutdownCallback();
}
- STOP_TIMER(I, time_total_runtime);
Dart::ShutdownIsolate();
}
@@ -1506,7 +1511,6 @@
intptr_t* isolate_snapshot_size) {
ASSERT(FLAG_load_deferred_eagerly);
DARTSCOPE(Thread::Current());
- TIMERSCOPE(T, time_creating_snapshot);
if (vm_isolate_snapshot_buffer != NULL &&
vm_isolate_snapshot_size == NULL) {
RETURN_NULL_ERROR(vm_isolate_snapshot_size);
@@ -1547,7 +1551,6 @@
uint8_t** buffer,
intptr_t* size) {
DARTSCOPE(Thread::Current());
- TIMERSCOPE(T, time_creating_snapshot);
if (buffer == NULL) {
RETURN_NULL_ERROR(buffer);
}
@@ -1678,7 +1681,7 @@
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE_SCOPE(isolate);
CHECK_CALLBACK_STATE(isolate);
- if (!isolate->message_handler()->HandleNextMessage()) {
+ if (isolate->message_handler()->HandleNextMessage() != MessageHandler::kOK) {
Dart_Handle error = Api::NewHandle(isolate,
isolate->object_store()->sticky_error());
isolate->object_store()->clear_sticky_error();
@@ -1694,8 +1697,10 @@
CHECK_CALLBACK_STATE(isolate);
ASSERT(isolate->GetAndClearResumeRequest() == false);
- isolate->message_handler()->HandleOOBMessages();
- return isolate->GetAndClearResumeRequest();
+ MessageHandler::MessageStatus status =
+ isolate->message_handler()->HandleOOBMessages();
+ bool resume = isolate->GetAndClearResumeRequest();
+ return (status != MessageHandler::kOK) || resume;
}
@@ -3908,7 +3913,7 @@
RETURN_TYPE_ERROR(I, type, Type);
}
const Class& cls = Class::Handle(Z, type_obj.type_class());
- const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(I));
+ const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(T));
if (!error.IsNull()) {
// An error occurred, return error object.
return Api::NewHandle(I, error.raw());
@@ -3933,7 +3938,7 @@
RETURN_NULL_ERROR(native_fields);
}
const Class& cls = Class::Handle(Z, type_obj.type_class());
- const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(I));
+ const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(T));
if (!error.IsNull()) {
// An error occurred, return error object.
return Api::NewHandle(I, error.raw());
@@ -4058,9 +4063,6 @@
Dart_Handle* arguments) {
DARTSCOPE(Thread::Current());
CHECK_CALLBACK_STATE(I);
- // TODO(turnidge): This is a bit simplistic. It overcounts when
- // other operations (gc, compilation) are active.
- TIMERSCOPE(T, time_dart_execution);
const String& function_name = Api::UnwrapStringHandle(I, name);
if (function_name.IsNull()) {
@@ -5059,7 +5061,6 @@
intptr_t line_offset,
intptr_t column_offset) {
DARTSCOPE(Thread::Current());
- TIMERSCOPE(T, time_script_loading);
const String& url_str = Api::UnwrapStringHandle(I, url);
if (url_str.IsNull()) {
RETURN_TYPE_ERROR(I, url, String);
@@ -5083,6 +5084,7 @@
CURRENT_FUNC);
}
CHECK_CALLBACK_STATE(I);
+ CHECK_COMPILATION_ALLOWED(I);
NoHeapGrowthControlScope no_growth_control;
@@ -5103,7 +5105,6 @@
DART_EXPORT Dart_Handle Dart_LoadScriptFromSnapshot(const uint8_t* buffer,
intptr_t buffer_len) {
DARTSCOPE(Thread::Current());
- TIMERSCOPE(T, time_script_loading);
StackZone zone(T);
if (buffer == NULL) {
RETURN_NULL_ERROR(buffer);
@@ -5127,6 +5128,7 @@
CURRENT_FUNC, library_url.ToCString());
}
CHECK_CALLBACK_STATE(I);
+ CHECK_COMPILATION_ALLOWED(I);
ASSERT(snapshot->kind() == Snapshot::kScript);
ScriptSnapshotReader reader(snapshot->content(), snapshot->length(), T);
@@ -5303,7 +5305,6 @@
intptr_t line_offset,
intptr_t column_offset) {
DARTSCOPE(Thread::Current());
- TIMERSCOPE(T, time_script_loading);
const String& url_str = Api::UnwrapStringHandle(I, url);
if (url_str.IsNull()) {
RETURN_TYPE_ERROR(I, url, String);
@@ -5321,6 +5322,7 @@
CURRENT_FUNC);
}
CHECK_CALLBACK_STATE(I);
+ CHECK_COMPILATION_ALLOWED(I);
NoHeapGrowthControlScope no_growth_control;
@@ -5378,6 +5380,7 @@
RETURN_TYPE_ERROR(I, prefix, String);
}
CHECK_CALLBACK_STATE(I);
+ CHECK_COMPILATION_ALLOWED(I);
const String& prefix_symbol = String::Handle(Z, Symbols::New(prefix_vm));
const Namespace& import_ns = Namespace::Handle(Z,
@@ -5405,7 +5408,6 @@
intptr_t line_offset,
intptr_t column_offset) {
DARTSCOPE(Thread::Current());
- TIMERSCOPE(T, time_script_loading);
const Library& lib = Api::UnwrapLibraryHandle(I, library);
if (lib.IsNull()) {
RETURN_TYPE_ERROR(I, library, Library);
@@ -5427,6 +5429,7 @@
CURRENT_FUNC);
}
CHECK_CALLBACK_STATE(I);
+ CHECK_COMPILATION_ALLOWED(I);
NoHeapGrowthControlScope no_growth_control;
@@ -5443,7 +5446,6 @@
Dart_Handle url,
Dart_Handle patch_source) {
DARTSCOPE(Thread::Current());
- TIMERSCOPE(T, time_script_loading);
const Library& lib = Api::UnwrapLibraryHandle(I, library);
if (lib.IsNull()) {
RETURN_TYPE_ERROR(I, library, Library);
@@ -5457,6 +5459,7 @@
RETURN_TYPE_ERROR(I, patch_source, String);
}
CHECK_CALLBACK_STATE(I);
+ CHECK_COMPILATION_ALLOWED(I);
NoHeapGrowthControlScope no_growth_control;
@@ -5680,6 +5683,8 @@
(stream_mask & DART_TIMELINE_STREAM_API) != 0);
isolate->GetCompilerStream()->set_enabled(
(stream_mask & DART_TIMELINE_STREAM_COMPILER) != 0);
+ isolate->GetDartStream()->set_enabled(
+ (stream_mask & DART_TIMELINE_STREAM_DART) != 0);
isolate->GetEmbedderStream()->set_enabled(
(stream_mask & DART_TIMELINE_STREAM_EMBEDDER) != 0);
isolate->GetGCStream()->set_enabled(
@@ -5694,6 +5699,8 @@
const bool api_enabled = (stream_mask & DART_TIMELINE_STREAM_API) != 0;
const bool compiler_enabled =
(stream_mask & DART_TIMELINE_STREAM_COMPILER) != 0;
+ const bool dart_enabled =
+ (stream_mask & DART_TIMELINE_STREAM_DART) != 0;
const bool embedder_enabled =
(stream_mask & DART_TIMELINE_STREAM_EMBEDDER) != 0;
const bool gc_enabled = (stream_mask & DART_TIMELINE_STREAM_GC) != 0;
@@ -5701,6 +5708,7 @@
(stream_mask & DART_TIMELINE_STREAM_ISOLATE) != 0;
Timeline::SetStreamAPIEnabled(api_enabled);
Timeline::SetStreamCompilerEnabled(compiler_enabled);
+ Timeline::SetStreamDartEnabled(dart_enabled);
Timeline::SetStreamEmbedderEnabled(embedder_enabled);
Timeline::SetStreamGCEnabled(gc_enabled);
Timeline::SetStreamIsolateEnabled(isolate_enabled);
@@ -5714,40 +5722,71 @@
// '[' + ']' + '\0'.
#define MINIMUM_OUTPUT_LENGTH 3
-static void StreamToConsumer(Dart_StreamConsumer consumer,
- void* user_data,
- char* output,
- intptr_t output_length) {
- if (output == NULL) {
- return;
- }
- if (output_length <= MINIMUM_OUTPUT_LENGTH) {
- return;
- }
+// Trims the '[' and ']' characters and, depending on whether or not more events
+// will follow, adjusts the last character of the string to either a '\0' or
+// ','.
+static char* TrimOutput(char* output,
+ intptr_t* output_length,
+ bool events_will_follow) {
+ ASSERT(output != NULL);
+ ASSERT(output_length != NULL);
+ ASSERT(*output_length > MINIMUM_OUTPUT_LENGTH);
// We expect the first character to be the opening of an array.
ASSERT(output[0] == '[');
// We expect the last character to be the closing of an array.
- ASSERT(output[output_length - 2] == ']');
+ ASSERT(output[*output_length - 2] == ']');
+ if (events_will_follow) {
+ // Replace array closing character (']') with ','.
+ output[*output_length - 2] = ',';
+ } else {
+ // Replace array closing character (']') with '\0'.
+ output[*output_length - 2] = '\0';
+ }
+ // Skip the array opening character ('[').
+ *output_length -= 2;
+ return &output[1];
+}
+
+
+static void StartStreamToConsumer(Dart_StreamConsumer consumer,
+ void* user_data,
+ const char* stream_name) {
// Start stream.
- const char* kStreamName = "timeline";
- const intptr_t kDataSize = 64 * KB;
consumer(Dart_StreamConsumer_kStart,
- kStreamName,
+ stream_name,
NULL,
0,
user_data);
+}
- // Stream out data. Skipping the array characters.
- // Replace array close with '\0'.
- output[output_length - 2] = '\0';
- intptr_t cursor = 1;
- output_length -= 1;
- intptr_t remaining = output_length - 1;
+static void FinishStreamToConsumer(Dart_StreamConsumer consumer,
+ void* user_data,
+ const char* stream_name) {
+ // Finish stream.
+ consumer(Dart_StreamConsumer_kFinish,
+ stream_name,
+ NULL,
+ 0,
+ user_data);
+}
+
+
+static void DataStreamToConsumer(Dart_StreamConsumer consumer,
+ void* user_data,
+ const char* output,
+ intptr_t output_length,
+ const char* stream_name) {
+ if (output == NULL) {
+ return;
+ }
+ const intptr_t kDataSize = 64 * KB;
+ intptr_t cursor = 0;
+ intptr_t remaining = output_length;
while (remaining >= kDataSize) {
consumer(Dart_StreamConsumer_kData,
- kStreamName,
- reinterpret_cast<uint8_t*>(&output[cursor]),
+ stream_name,
+ reinterpret_cast<const uint8_t*>(&output[cursor]),
kDataSize,
user_data);
cursor += kDataSize;
@@ -5756,8 +5795,8 @@
if (remaining > 0) {
ASSERT(remaining < kDataSize);
consumer(Dart_StreamConsumer_kData,
- kStreamName,
- reinterpret_cast<uint8_t*>(&output[cursor]),
+ stream_name,
+ reinterpret_cast<const uint8_t*>(&output[cursor]),
remaining,
user_data);
cursor += remaining;
@@ -5765,13 +5804,53 @@
}
ASSERT(cursor == output_length);
ASSERT(remaining == 0);
+}
- // Finish stream.
- consumer(Dart_StreamConsumer_kFinish,
- kStreamName,
- NULL,
- 0,
- user_data);
+
+static bool StreamTraceEvents(Dart_StreamConsumer consumer,
+ void* user_data,
+ JSONStream* js,
+ const char* dart_events) {
+ ASSERT(js != NULL);
+ // Steal output from JSONStream.
+ char* output = NULL;
+ intptr_t output_length = 0;
+ js->Steal(const_cast<const char**>(&output), &output_length);
+
+ const bool output_vm = output_length > MINIMUM_OUTPUT_LENGTH;
+ const bool output_dart = dart_events != NULL;
+
+ if (!output_vm && !output_dart) {
+ // We stole the JSONStream's output buffer, free it.
+ free(output);
+ // Nothing will be emitted.
+ return false;
+ }
+
+ // Start the stream.
+ StartStreamToConsumer(consumer, user_data, "timeline");
+
+ // Send events from the VM.
+ if (output_vm) {
+ // Add one for the '\0' character.
+ output_length++;
+ char* trimmed_output = TrimOutput(output, &output_length, output_dart);
+ DataStreamToConsumer(consumer, user_data,
+ trimmed_output, output_length, "timeline");
+ }
+ // We stole the JSONStream's output buffer, free it.
+ free(output);
+
+ // Send events from dart.
+ if (output_dart) {
+ const intptr_t dart_events_len = strlen(dart_events) + 1; // +1 for '\0'.
+ DataStreamToConsumer(consumer, user_data,
+ dart_events, dart_events_len, "timeline");
+ }
+
+ // Finish the stream.
+ FinishStreamToConsumer(consumer, user_data, "timeline");
+ return true;
}
@@ -5787,25 +5866,18 @@
// Nothing has been recorded.
return false;
}
+ Thread* T = Thread::Current();
+ StackZone zone(T);
// Reclaim all blocks cached by isolate.
Timeline::ReclaimIsolateBlocks();
JSONStream js;
IsolateTimelineEventFilter filter(isolate);
timeline_recorder->PrintTraceEvent(&js, &filter);
-
- // Copy output.
- char* output = NULL;
- intptr_t output_length = 0;
- js.Steal(const_cast<const char**>(&output), &output_length);
- if (output != NULL) {
- // Add one for the '\0' character.
- output_length++;
- StreamToConsumer(consumer, user_data, output, output_length);
- // We stole the JSONStream's output buffer, free it.
- free(output);
- return output_length > MINIMUM_OUTPUT_LENGTH;
- }
- return false;
+ const char* dart_events =
+ DartTimelineEventIterator::PrintTraceEvents(timeline_recorder,
+ zone.GetZone(),
+ isolate);
+ return StreamTraceEvents(consumer, user_data, &js, dart_events);
}
@@ -5819,26 +5891,18 @@
// Nothing has been recorded.
return false;
}
-
+ Thread* T = Thread::Current();
+ StackZone zone(T);
// Reclaim all blocks cached in the system.
Timeline::ReclaimAllBlocks();
JSONStream js;
TimelineEventFilter filter;
timeline_recorder->PrintTraceEvent(&js, &filter);
-
- // Copy output.
- char* output = NULL;
- intptr_t output_length = 0;
- js.Steal(const_cast<const char**>(&output), &output_length);
- if (output != NULL) {
- // Add one for the '\0' character.
- output_length++;
- StreamToConsumer(consumer, user_data, output, output_length);
- // We stole the JSONStream's output buffer, free it.
- free(output);
- return output_length > MINIMUM_OUTPUT_LENGTH;
- }
- return false;
+ const char* dart_events =
+ DartTimelineEventIterator::PrintTraceEvents(timeline_recorder,
+ zone.GetZone(),
+ NULL);
+ return StreamTraceEvents(consumer, user_data, &js, dart_events);
}
@@ -5950,14 +6014,16 @@
DART_EXPORT Dart_Handle Dart_Precompile(
- Dart_QualifiedFunctionName entry_points[]) {
+ Dart_QualifiedFunctionName entry_points[],
+ bool reset_fields) {
DARTSCOPE(Thread::Current());
Dart_Handle result = Api::CheckAndFinalizePendingClasses(I);
if (::Dart_IsError(result)) {
return result;
}
CHECK_CALLBACK_STATE(I);
- const Error& error = Error::Handle(Precompiler::CompileAll(entry_points));
+ const Error& error = Error::Handle(Precompiler::CompileAll(entry_points,
+ reset_fields));
if (!error.IsNull()) {
return Api::NewHandle(I, error.raw());
}
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index 742f80c..2f635d3 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -316,6 +316,12 @@
return reinterpret_cast<Dart_Handle>(Api::AcquiredError(isolate)); \
} \
+#define CHECK_COMPILATION_ALLOWED(isolate) \
+ if (!isolate->compilation_allowed()) { \
+ return Api::NewError("%s: Cannot load after Dart_Precompile", \
+ CURRENT_FUNC); \
+ } \
+
#define ASSERT_CALLBACK_STATE(isolate) \
ASSERT(isolate->no_callback_scope_depth() == 0)
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 1d111e8..34c5cb5 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -9378,7 +9378,7 @@
static void AppendStreamConsumer(Dart_StreamConsumer_State state,
const char* stream_name,
- uint8_t* buffer,
+ const uint8_t* buffer,
intptr_t buffer_length,
void* user_data) {
if (state == Dart_StreamConsumer_kFinish) {
@@ -9446,6 +9446,99 @@
}
+TEST_CASE(Timeline_Dart_TimelineGetTraceOnlyDartEvents) {
+ const char* kScriptChars =
+ "import 'dart:developer';\n"
+ ""
+ "main() {\n"
+ " Timeline.startSync('DART_NAME');\n"
+ " Timeline.finishSync();\n"
+ "}\n";
+
+ Dart_Handle lib =
+ TestCase::LoadTestScript(kScriptChars, NULL);
+
+ const char* buffer = NULL;
+ intptr_t buffer_length = 0;
+ bool success = false;
+
+ // Enable recording of the Dart stream.
+ Dart_TimelineSetRecordedStreams(DART_TIMELINE_STREAM_DART);
+
+ // Invoke main, which will add a new timeline event from Dart.
+ Dart_Handle result = Dart_Invoke(lib,
+ NewString("main"),
+ 0,
+ NULL);
+ EXPECT_VALID(result);
+
+ // Grab the trace.
+ AppendData data;
+ data.buffer = NULL;
+ data.buffer_length = 0;
+ success = Dart_TimelineGetTrace(AppendStreamConsumer, &data);
+ EXPECT(success);
+ buffer = reinterpret_cast<char*>(data.buffer);
+ buffer_length = data.buffer_length;
+ EXPECT(buffer_length > 0);
+ EXPECT(buffer != NULL);
+
+ // Heartbeat test.
+ EXPECT_SUBSTRING("\"cat\":\"Dart\"", buffer);
+ EXPECT_SUBSTRING("\"name\":\"DART_NAME\"", buffer);
+
+ // Free buffer allocated by AppendStreamConsumer
+ free(data.buffer);
+}
+
+
+TEST_CASE(Timeline_Dart_TimelineGetTraceWithDartEvents) {
+ const char* kScriptChars =
+ "import 'dart:developer';\n"
+ "\n"
+ "main() {\n"
+ " Timeline.startSync('DART_NAME');\n"
+ " Timeline.finishSync();\n"
+ "}\n";
+
+ Dart_Handle lib =
+ TestCase::LoadTestScript(kScriptChars, NULL);
+
+ const char* buffer = NULL;
+ intptr_t buffer_length = 0;
+ bool success = false;
+
+ // Enable recording of all streams.
+ Dart_TimelineSetRecordedStreams(DART_TIMELINE_STREAM_ALL);
+
+ // Invoke main, which will be compiled resulting in a compiler event in
+ // the timeline.
+ Dart_Handle result = Dart_Invoke(lib,
+ NewString("main"),
+ 0,
+ NULL);
+ EXPECT_VALID(result);
+
+ // Grab the trace.
+ AppendData data;
+ success = Dart_TimelineGetTrace(AppendStreamConsumer, &data);
+ EXPECT(success);
+ buffer = reinterpret_cast<char*>(data.buffer);
+ buffer_length = data.buffer_length;
+ EXPECT(buffer_length > 0);
+ EXPECT(buffer != NULL);
+
+ // Heartbeat test.
+ EXPECT_SUBSTRING("\"cat\":\"Compiler\"", buffer);
+ EXPECT_SUBSTRING("\"name\":\"CompileFunction\"", buffer);
+ EXPECT_SUBSTRING("\"function\":\"::_main\"", buffer);
+ EXPECT_SUBSTRING("\"cat\":\"Dart\"", buffer);
+ EXPECT_SUBSTRING("\"name\":\"DART_NAME\"", buffer);
+
+ // Free buffer allocated by AppendStreamConsumer
+ free(data.buffer);
+}
+
TEST_CASE(Timeline_Dart_TimelineGetTraceGlobalOverride) {
const char* kScriptChars =
"foo() => 'a';\n"
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 0b61458..5e4dfd9 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -310,9 +310,16 @@
if (ServiceNeedsDebuggerEvent(event->type()) && event->IsPauseEvent()) {
// If we were paused, notify the service that we have resumed.
- ServiceEvent service_event(event->isolate(), ServiceEvent::kResume);
- service_event.set_top_frame(event->top_frame());
- Service::HandleEvent(&service_event);
+ const Error& error =
+ Error::Handle(isolate_, isolate_->object_store()->sticky_error());
+ ASSERT(error.IsNull() || error.IsUnwindError());
+
+ // Only send a resume event when the isolate is not unwinding.
+ if (!error.IsUnwindError()) {
+ ServiceEvent service_event(event->isolate(), ServiceEvent::kResume);
+ service_event.set_top_frame(event->top_frame());
+ Service::HandleEvent(&service_event);
+ }
}
}
@@ -350,9 +357,6 @@
OS::Print("[!] Embedder api: terminating isolate:\n"
"\tisolate: %s\n", isolate_->name());
}
- // TODO(turnidge): We should give the message handler a way to
- // detect when an isolate is unwinding.
- isolate_->message_handler()->set_pause_on_exit(false);
const String& msg =
String::Handle(String::New("isolate terminated by embedder"));
return UnwindError::New(msg);
@@ -362,6 +366,7 @@
// If any error occurred while in the debug message loop, return it here.
const Error& error =
Error::Handle(isolate_, isolate_->object_store()->sticky_error());
+ ASSERT(error.IsNull() || error.IsUnwindError());
isolate_->object_store()->clear_sticky_error();
return error.raw();
}
@@ -1956,7 +1961,7 @@
continue;
}
// Parse class definition if not done yet.
- error = cls.EnsureIsFinalized(isolate_);
+ error = cls.EnsureIsFinalized(Thread::Current());
if (!error.IsNull()) {
// Ignore functions in this class.
// TODO(hausner): Should we propagate this error? How?
@@ -2776,7 +2781,7 @@
// Use the isolate's control port as the isolate_id for debugging.
// This port will be used as a unique ID to represent the isolate in the
// debugger wire protocol messages.
- isolate_id_ = isolate->main_port();
+ isolate_id_ = isolate_->main_port();
initialized_ = true;
}
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 9f99503..8230ac7 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -132,7 +132,7 @@
// exception handler. Once found, set the pc, sp and fp so that execution
// can continue in that frame. Sets 'needs_stacktrace' if there is no
// cath-all handler or if a stack-trace is specified in the catch.
-static bool FindExceptionHandler(Isolate* isolate,
+static bool FindExceptionHandler(Thread* thread,
uword* handler_pc,
uword* handler_sp,
uword* handler_fp,
@@ -146,7 +146,7 @@
uword temp_handler_pc = kUwordMax;
while (!frame->IsEntryFrame()) {
if (frame->IsDartFrame()) {
- if (frame->FindExceptionHandler(isolate,
+ if (frame->FindExceptionHandler(thread,
&temp_handler_pc,
needs_stacktrace,
&is_catch_all)) {
@@ -311,7 +311,7 @@
if (use_preallocated_stacktrace) {
stacktrace ^= isolate->object_store()->preallocated_stack_trace();
PreallocatedStacktraceBuilder frame_builder(stacktrace);
- handler_exists = FindExceptionHandler(isolate,
+ handler_exists = FindExceptionHandler(thread,
&handler_pc,
&handler_sp,
&handler_fp,
@@ -327,7 +327,7 @@
// Find the exception handler and determine if the handler needs a
// stacktrace.
- handler_exists = FindExceptionHandler(isolate,
+ handler_exists = FindExceptionHandler(thread,
&handler_pc,
&handler_sp,
&handler_fp,
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 2884abf..ee6bdfd 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -46,6 +46,7 @@
"Inlining interval diagnostics");
DEFINE_FLAG(bool, use_megamorphic_stub, true, "Out of line megamorphic lookup");
+DECLARE_FLAG(bool, background_compilation);
DECLARE_FLAG(bool, code_comments);
DECLARE_FLAG(bool, deoptimize_alot);
DECLARE_FLAG(int, deoptimize_every);
@@ -71,10 +72,17 @@
DECLARE_FLAG(bool, warn_on_javascript_compatibility);
DECLARE_FLAG(bool, precompile_collect_closures);
DECLARE_FLAG(bool, print_stop_message);
+DECLARE_FLAG(bool, lazy_dispatchers);
+DECLARE_FLAG(bool, interpret_irregexp);
+DECLARE_FLAG(bool, enable_mirrors);
+DECLARE_FLAG(bool, link_natives_lazily);
-
-static void NooptModeHandler(bool value) {
+static void PrecompilationModeHandler(bool value) {
if (value) {
+#if defined(TARGET_ARCH_IA32)
+ FATAL("Precompilation not supported on IA32");
+#endif
+
FLAG_always_megamorphic_calls = true;
FLAG_polymorphic_with_deopt = false;
FLAG_optimization_counter_threshold = -1;
@@ -99,29 +107,7 @@
// Calling the PrintStopMessage stub is not supported in precompiled code
// since it is done at places where no pool pointer is loaded.
FLAG_print_stop_message = false;
- }
-}
-
-// --noopt disables optimizer and tunes unoptimized code to run as fast
-// as possible.
-DEFINE_FLAG_HANDLER(NooptModeHandler,
- noopt,
- "Run fast unoptimized code only.");
-
-
-DECLARE_FLAG(bool, lazy_dispatchers);
-DECLARE_FLAG(bool, interpret_irregexp);
-DECLARE_FLAG(bool, enable_mirrors);
-DECLARE_FLAG(bool, link_natives_lazily);
-
-static void PrecompileModeHandler(bool value) {
- if (value) {
-#if defined(TARGET_ARCH_IA32)
- FATAL("Precompilation not supported on IA32");
-#endif
-
- NooptModeHandler(true);
FLAG_lazy_dispatchers = false;
FLAG_interpret_irregexp = true;
FLAG_enable_mirrors = false;
@@ -129,12 +115,16 @@
FLAG_link_natives_lazily = true;
FLAG_fields_may_be_reset = true;
FLAG_allow_absolute_addresses = false;
+
+ // Background compilation relies on two-stage compilation pipeline,
+ // while precompilation has only one.
+ FLAG_background_compilation = false;
}
}
-DEFINE_FLAG_HANDLER(PrecompileModeHandler,
- precompile,
+DEFINE_FLAG_HANDLER(PrecompilationModeHandler,
+ precompilation,
"Precompilation mode");
@@ -1039,9 +1029,8 @@
}
-// Returns 'true' if code generation for this function is complete, i.e.,
-// no fall-through to regular code is needed.
-void FlowGraphCompiler::TryIntrinsify() {
+// Returns 'true' if regular code generation should be skipped.
+bool FlowGraphCompiler::TryIntrinsify() {
// Intrinsification skips arguments checks, therefore disable if in checked
// mode.
if (FLAG_intrinsify && !isolate()->flags().type_checks()) {
@@ -1058,8 +1047,9 @@
// Reading from a mutable double box requires allocating a fresh double.
if (load_node.field().guarded_cid() == kDynamicCid) {
GenerateInlinedGetter(load_node.field().Offset());
+ return true;
}
- return;
+ return false;
}
if (parsed_function().function().kind() == RawFunction::kImplicitSetter) {
// An implicit setter must have a specific AST structure.
@@ -1072,7 +1062,7 @@
*sequence_node.NodeAt(0)->AsStoreInstanceFieldNode();
if (store_node.field().guarded_cid() == kDynamicCid) {
GenerateInlinedSetter(store_node.field().Offset());
- return;
+ return true;
}
}
}
@@ -1089,6 +1079,7 @@
// before any deoptimization point.
ASSERT(!intrinsic_slow_path_label_.IsBound());
assembler()->Bind(&intrinsic_slow_path_label_);
+ return false;
}
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index 3151009..1451776 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -328,7 +328,8 @@
// Bail out of the flow graph compiler. Does not return to the caller.
void Bailout(const char* reason);
- void TryIntrinsify();
+ // Returns 'true' if regular code generation should be skipped.
+ bool TryIntrinsify();
void GenerateRuntimeCall(intptr_t token_pos,
intptr_t deopt_id,
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index e8b2cde..9299a95 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -1020,7 +1020,10 @@
void FlowGraphCompiler::CompileGraph() {
InitCompiler();
- TryIntrinsify();
+ if (TryIntrinsify()) {
+ // Skip regular code generation.
+ return;
+ }
EmitFrameEntry();
ASSERT(assembler()->constant_pool_allowed());
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index 76da180..86167ac 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -1022,7 +1022,10 @@
void FlowGraphCompiler::CompileGraph() {
InitCompiler();
- TryIntrinsify();
+ if (TryIntrinsify()) {
+ // Skip regular code generation.
+ return;
+ }
EmitFrameEntry();
ASSERT(assembler()->constant_pool_allowed());
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 385a30c..2794ff5 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -751,6 +751,8 @@
Location value = defn->locs()->out(0);
if (value.IsRegister()) {
__ pushl(value.reg());
+ } else if (value.IsConstant()) {
+ __ PushObject(value.constant());
} else {
ASSERT(value.IsStackSlot());
__ pushl(value.ToStackSlotAddress());
@@ -1028,7 +1030,10 @@
void FlowGraphCompiler::CompileGraph() {
InitCompiler();
- TryIntrinsify();
+ if (TryIntrinsify()) {
+ // Skip regular code generation.
+ return;
+ }
EmitFrameEntry();
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 0cc605c..93ec487 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -1040,7 +1040,10 @@
void FlowGraphCompiler::CompileGraph() {
InitCompiler();
- TryIntrinsify();
+ if (TryIntrinsify()) {
+ // Skip regular code generation.
+ return;
+ }
EmitFrameEntry();
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 7d407f0..4247722 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -741,6 +741,8 @@
Location value = defn->locs()->out(0);
if (value.IsRegister()) {
__ pushq(value.reg());
+ } else if (value.IsConstant()) {
+ __ PushObject(value.constant());
} else {
ASSERT(value.IsStackSlot());
__ pushq(value.ToStackSlotAddress());
@@ -1028,7 +1030,10 @@
void FlowGraphCompiler::CompileGraph() {
InitCompiler();
- TryIntrinsify();
+ if (TryIntrinsify()) {
+ // Skip regular code generation.
+ return;
+ }
EmitFrameEntry();
ASSERT(assembler()->constant_pool_allowed());
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 888017e..9de736b 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -2306,10 +2306,10 @@
// Using field class
-static RawField* GetField(intptr_t class_id, const String& field_name) {
- Isolate* isolate = Isolate::Current();
- Class& cls = Class::Handle(isolate, isolate->class_table()->At(class_id));
- Field& field = Field::Handle(isolate);
+RawField* FlowGraphOptimizer::GetField(intptr_t class_id,
+ const String& field_name) {
+ Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id));
+ Field& field = Field::Handle(Z);
while (!cls.IsNull()) {
field = cls.LookupInstanceField(field_name);
if (!field.IsNull()) {
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index 0df970b..d0ae717 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -260,6 +260,8 @@
void InstanceCallNoopt(InstanceCallInstr* instr);
+ RawField* GetField(intptr_t class_id, const String& field_name);
+
Thread* thread() const { return flow_graph_->thread(); }
Isolate* isolate() const { return flow_graph_->isolate(); }
Zone* zone() const { return flow_graph_->zone(); }
diff --git a/runtime/vm/gc_marker.cc b/runtime/vm/gc_marker.cc
index 42ee7fe..2c53a07 100644
--- a/runtime/vm/gc_marker.cc
+++ b/runtime/vm/gc_marker.cc
@@ -595,7 +595,7 @@
StackZone stack_zone(Thread::Current());
Zone* zone = stack_zone.GetZone();
SkippedCodeFunctions* skipped_code_functions =
- collect_code_ ? new(zone) SkippedCodeFunctions() : NULL;
+ collect_code_ ? new(zone) SkippedCodeFunctions() : NULL;
MarkingVisitor visitor(isolate_, heap_, page_space_, marking_stack_,
delay_set_, skipped_code_functions);
// Phase 1: Populate and drain marking stack in task.
diff --git a/runtime/vm/gc_marker.h b/runtime/vm/gc_marker.h
index c01a6e8..e2f8293 100644
--- a/runtime/vm/gc_marker.h
+++ b/runtime/vm/gc_marker.h
@@ -6,6 +6,7 @@
#define VM_GC_MARKER_H_
#include "vm/allocation.h"
+#include "vm/os_thread.h" // Mutex.
namespace dart {
diff --git a/runtime/vm/heap.cc b/runtime/vm/heap.cc
index f599742..670c868 100644
--- a/runtime/vm/heap.cc
+++ b/runtime/vm/heap.cc
@@ -334,7 +334,6 @@
switch (space) {
case kNew: {
RecordBeforeGC(kNew, reason);
- TimerScope timer(true, &(isolate()->timer_list().time_gc()), thread);
VMTagScope tagScope(thread, VMTag::kGCNewSpaceTagId);
TimelineDurationScope tds(thread,
isolate()->GetGCStream(),
@@ -354,7 +353,6 @@
case kOld:
case kCode: {
RecordBeforeGC(kOld, reason);
- TimerScope timer(true, &(isolate()->timer_list().time_gc()), thread);
VMTagScope tagScope(thread, VMTag::kGCOldSpaceTagId);
TimelineDurationScope tds(thread,
isolate()->GetGCStream(),
@@ -395,7 +393,6 @@
Thread* thread = Thread::Current();
{
RecordBeforeGC(kNew, kFull);
- TimerScope timer(true, &(isolate()->timer_list().time_gc()), thread);
VMTagScope tagScope(thread, VMTag::kGCNewSpaceTagId);
TimelineDurationScope tds(thread,
isolate()->GetGCStream(),
@@ -409,7 +406,6 @@
}
{
RecordBeforeGC(kOld, kFull);
- TimerScope timer(true, &(isolate()->timer_list().time_gc()), thread);
VMTagScope tagScope(thread, VMTag::kGCOldSpaceTagId);
TimelineDurationScope tds(thread,
isolate()->GetGCStream(),
@@ -457,6 +453,16 @@
}
+void Heap::UpdateGlobalMaxUsed() {
+ ASSERT(isolate_ != NULL);
+ // We are accessing the used in words count for both new and old space
+ // without synchronizing. The value of this metric is approximate.
+ isolate_->GetHeapGlobalUsedMaxMetric()->SetValue(
+ (UsedInWords(Heap::kNew) * kWordSize) +
+ (UsedInWords(Heap::kOld) * kWordSize));
+}
+
+
void Heap::SetGrowthControlState(bool state) {
old_space_.SetGrowthControlState(state);
}
@@ -572,8 +578,8 @@
void Heap::PrintSizes() const {
- OS::PrintErr("New space (%" Pd "k of %" Pd "k) "
- "Old space (%" Pd "k of %" Pd "k)\n",
+ OS::PrintErr("New space (%" Pd64 "k of %" Pd64 "k) "
+ "Old space (%" Pd64 "k of %" Pd64 "k)\n",
(UsedInWords(kNew) / KBInWords),
(CapacityInWords(kNew) / KBInWords),
(UsedInWords(kOld) / KBInWords),
@@ -581,21 +587,23 @@
}
-intptr_t Heap::UsedInWords(Space space) const {
+int64_t Heap::UsedInWords(Space space) const {
return space == kNew ? new_space_.UsedInWords() : old_space_.UsedInWords();
}
-intptr_t Heap::CapacityInWords(Space space) const {
+int64_t Heap::CapacityInWords(Space space) const {
return space == kNew ? new_space_.CapacityInWords() :
old_space_.CapacityInWords();
}
-intptr_t Heap::ExternalInWords(Space space) const {
+
+int64_t Heap::ExternalInWords(Space space) const {
return space == kNew ? new_space_.ExternalInWords() :
old_space_.ExternalInWords();
}
+
int64_t Heap::GCTimeInMicros(Space space) const {
if (space == kNew) {
return new_space_.gc_time_micros();
@@ -779,4 +787,16 @@
heap->SetGrowthControlState(current_growth_controller_state_);
}
+
+WritableVMIsolateScope::WritableVMIsolateScope(Thread* thread)
+ : StackResource(thread) {
+ Dart::vm_isolate()->heap()->WriteProtect(false);
+}
+
+
+WritableVMIsolateScope::~WritableVMIsolateScope() {
+ ASSERT(Dart::vm_isolate()->heap()->UsedInWords(Heap::kNew) == 0);
+ Dart::vm_isolate()->heap()->WriteProtect(true);
+}
+
} // namespace dart
diff --git a/runtime/vm/heap.h b/runtime/vm/heap.h
index 8feb555..4639c26 100644
--- a/runtime/vm/heap.h
+++ b/runtime/vm/heap.h
@@ -133,7 +133,8 @@
void SetGrowthControlState(bool state);
bool GrowthControlState();
- // Protect access to the heap.
+ // Protect access to the heap. Note: Code pages are made
+ // executable/non-executable when 'read_only' is true/false, respectively.
void WriteProtect(bool read_only);
void WriteProtectCode(bool read_only) {
old_space_.WriteProtectCode(read_only);
@@ -157,9 +158,9 @@
void PrintSizes() const;
// Return amount of memory used and capacity in a space, excluding external.
- intptr_t UsedInWords(Space space) const;
- intptr_t CapacityInWords(Space space) const;
- intptr_t ExternalInWords(Space space) const;
+ int64_t UsedInWords(Space space) const;
+ int64_t CapacityInWords(Space space) const;
+ int64_t ExternalInWords(Space space) const;
// Return the amount of GCing in microseconds.
int64_t GCTimeInMicros(Space space) const;
@@ -221,6 +222,8 @@
bool gc_in_progress();
+ void UpdateGlobalMaxUsed();
+
static bool IsAllocatableInNewSpace(intptr_t size) {
return size <= kNewAllocatableSize;
}
@@ -358,6 +361,14 @@
DISALLOW_COPY_AND_ASSIGN(NoHeapGrowthControlScope);
};
+
+// Note: During this scope, the code pages are non-executable.
+class WritableVMIsolateScope : StackResource {
+ public:
+ explicit WritableVMIsolateScope(Thread* thread);
+ ~WritableVMIsolateScope();
+};
+
} // namespace dart
#endif // VM_HEAP_H_
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index c691b85..1387730 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -237,8 +237,8 @@
static void PrintUse(BufferFormatter* f, const Definition& definition) {
if (definition.HasSSATemp()) {
if (definition.HasPairRepresentation()) {
- f->Print("v%" Pd ", v%" Pd "", definition.ssa_temp_index(),
- definition.ssa_temp_index() + 1);
+ f->Print("(v%" Pd ", v%" Pd ")", definition.ssa_temp_index(),
+ definition.ssa_temp_index() + 1);
} else {
f->Print("v%" Pd "", definition.ssa_temp_index());
}
diff --git a/runtime/vm/instructions_ia32.h b/runtime/vm/instructions_ia32.h
index 9cf5243..33d648f 100644
--- a/runtime/vm/instructions_ia32.h
+++ b/runtime/vm/instructions_ia32.h
@@ -62,44 +62,32 @@
};
-template<class P>
-class CallOrJumpPattern : public InstructionPattern<P> {
+class CallPattern : public InstructionPattern<CallPattern> {
public:
+ explicit CallPattern(uword pc) : InstructionPattern(pc) {}
uword TargetAddress() const {
ASSERT(this->IsValid());
return this->start() +
- P::pattern_length_in_bytes() +
+ CallPattern::pattern_length_in_bytes() +
*reinterpret_cast<uword*>(this->start() + 1);
}
void SetTargetAddress(uword new_target) const {
ASSERT(this->IsValid());
*reinterpret_cast<uword*>(this->start() + 1) =
- new_target - this->start() - P::pattern_length_in_bytes();
+ new_target - this->start() - CallPattern::pattern_length_in_bytes();
CPU::FlushICache(this->start() + 1, kWordSize);
}
- protected:
- explicit CallOrJumpPattern(uword pc) : InstructionPattern<P>(pc) {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CallOrJumpPattern);
-};
-
-
-class CallPattern : public CallOrJumpPattern<CallPattern> {
- public:
- explicit CallPattern(uword pc) : CallOrJumpPattern(pc) {}
-
static int pattern_length_in_bytes() { return kLengthInBytes; }
static const int* pattern() {
static const int kCallPattern[kLengthInBytes] = {0xE8, -1, -1, -1, -1};
return kCallPattern;
}
+
private:
static const int kLengthInBytes = 5;
-
DISALLOW_COPY_AND_ASSIGN(CallPattern);
};
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 62d8bef..e0bfb7f 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -151,15 +151,19 @@
const intptr_t kNumInputs = 0;
return LocationSummary::Make(zone,
kNumInputs,
- Location::RequiresRegister(),
+ Assembler::IsSafe(value())
+ ? Location::Constant(this)
+ : Location::RequiresRegister(),
LocationSummary::kNoCall);
}
void ConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// The register allocator drops constant definitions that have no uses.
- if (!locs()->out(0).IsInvalid()) {
- Register result = locs()->out(0).reg();
+ Location out = locs()->out(0);
+ ASSERT(out.IsRegister() || out.IsConstant() || out.IsInvalid());
+ if (out.IsRegister()) {
+ Register result = out.reg();
__ LoadObjectSafely(result, value());
}
}
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index b58e4d1..ea5e685 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -238,15 +238,19 @@
const intptr_t kNumInputs = 0;
return LocationSummary::Make(zone,
kNumInputs,
- Location::RequiresRegister(),
+ Assembler::IsSafe(value())
+ ? Location::Constant(this)
+ : Location::RequiresRegister(),
LocationSummary::kNoCall);
}
void ConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// The register allocator drops constant definitions that have no uses.
- if (!locs()->out(0).IsInvalid()) {
- Register result = locs()->out(0).reg();
+ Location out = locs()->out(0);
+ ASSERT(out.IsRegister() || out.IsConstant() || out.IsInvalid());
+ if (out.IsRegister()) {
+ Register result = out.reg();
__ LoadObject(result, value());
}
}
diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc
index 76e9b63..bc1e24b 100644
--- a/runtime/vm/intrinsifier.cc
+++ b/runtime/vm/intrinsifier.cc
@@ -36,12 +36,13 @@
#if defined(DART_NO_SNAPSHOT)
void Intrinsifier::InitializeState() {
- Isolate* isolate = Isolate::Current();
- Library& lib = Library::Handle(isolate);
- Class& cls = Class::Handle(isolate);
- Function& func = Function::Handle(isolate);
- String& str = String::Handle(isolate);
- Error& error = Error::Handle(isolate);
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ Library& lib = Library::Handle(zone);
+ Class& cls = Class::Handle(zone);
+ Function& func = Function::Handle(zone);
+ String& str = String::Handle(zone);
+ Error& error = Error::Handle(zone);
#define SETUP_FUNCTION(class_name, function_name, destination, fp) \
if (strcmp(#class_name, "::") == 0) { \
@@ -51,7 +52,7 @@
str = String::New(#class_name); \
cls = lib.LookupClassAllowPrivate(str); \
ASSERT(!cls.IsNull()); \
- error = cls.EnsureIsFinalized(isolate); \
+ error = cls.EnsureIsFinalized(thread); \
if (!error.IsNull()) { \
OS::PrintErr("%s\n", error.ToErrorCString()); \
} \
@@ -217,6 +218,8 @@
return kDoubleCid;
case kUnboxedFloat32x4:
return kFloat32x4Cid;
+ case kUnboxedUint32:
+ return kDynamicCid; // smi or mint.
default:
UNREACHABLE();
return kIllegalCid;
@@ -448,6 +451,60 @@
}
+bool Intrinsifier::Build_Uint32ArraySetIndexed(FlowGraph* flow_graph) {
+ GraphEntryInstr* graph_entry = flow_graph->graph_entry();
+ TargetEntryInstr* normal_entry = graph_entry->normal_entry();
+ BlockBuilder builder(flow_graph, normal_entry);
+
+ Definition* value = builder.AddParameter(1);
+ Definition* index = builder.AddParameter(2);
+ Definition* array = builder.AddParameter(3);
+
+ PrepareIndexedOp(&builder, array, index, TypedData::length_offset());
+
+ Definition* unboxed_value =
+ builder.AddUnboxInstr(kUnboxedUint32, new Value(value));
+
+ builder.AddInstruction(
+ new StoreIndexedInstr(new Value(array),
+ new Value(index),
+ new Value(unboxed_value),
+ kNoStoreBarrier,
+ 4, // index scale
+ kTypedDataUint32ArrayCid,
+ Isolate::kNoDeoptId,
+ builder.TokenPos()));
+ // Return null.
+ Definition* null_def = builder.AddNullDefinition();
+ builder.AddIntrinsicReturn(new Value(null_def));
+ return true;
+}
+
+
+bool Intrinsifier::Build_Uint32ArrayGetIndexed(FlowGraph* flow_graph) {
+ GraphEntryInstr* graph_entry = flow_graph->graph_entry();
+ TargetEntryInstr* normal_entry = graph_entry->normal_entry();
+ BlockBuilder builder(flow_graph, normal_entry);
+
+ Definition* index = builder.AddParameter(1);
+ Definition* array = builder.AddParameter(2);
+
+ PrepareIndexedOp(&builder, array, index, TypedData::length_offset());
+
+ Definition* unboxed_value = builder.AddDefinition(
+ new LoadIndexedInstr(new Value(array),
+ new Value(index),
+ 4, // index scale
+ kTypedDataUint32ArrayCid,
+ Isolate::kNoDeoptId,
+ builder.TokenPos()));
+ Definition* result = builder.AddDefinition(
+ BoxInstr::Create(kUnboxedUint32, new Value(unboxed_value)));
+ builder.AddIntrinsicReturn(new Value(result));
+ return true;
+}
+
+
bool Intrinsifier::Build_Float64ArraySetIndexed(FlowGraph* flow_graph) {
if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false;
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index 7bc19b9..dd6d509 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -35,56 +35,14 @@
intptr_t Intrinsifier::ParameterSlotFromSp() { return -1; }
-static intptr_t ComputeObjectArrayTypeArgumentsOffset() {
- const Library& core_lib = Library::Handle(Library::CoreLibrary());
- const Class& cls = Class::Handle(
- core_lib.LookupClassAllowPrivate(Symbols::_List()));
- ASSERT(!cls.IsNull());
- ASSERT(cls.NumTypeArguments() == 1);
- const intptr_t field_offset = cls.type_arguments_field_offset();
- ASSERT(field_offset != Class::kNoTypeArguments);
- return field_offset;
-}
-
-
// Intrinsify only for Smi value and index. Non-smi values need a store buffer
// update. Array length is always a Smi.
void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) {
- Label fall_through;
-
if (Isolate::Current()->flags().type_checks()) {
- const intptr_t type_args_field_offset =
- ComputeObjectArrayTypeArgumentsOffset();
- // Inline simple tests (Smi, null), fallthrough if not positive.
- Label checked_ok;
- __ ldr(R2, Address(SP, 0 * kWordSize)); // Value.
-
- // Null value is valid for any type.
- __ CompareObject(R2, Object::null_object());
- __ b(&checked_ok, EQ);
-
- __ ldr(R1, Address(SP, 2 * kWordSize)); // Array.
- __ ldr(R1, FieldAddress(R1, type_args_field_offset));
-
- // R1: Type arguments of array.
- __ CompareObject(R1, Object::null_object());
- __ b(&checked_ok, EQ);
-
- // Check if it's dynamic.
- // Get type at index 0.
- __ ldr(R0, FieldAddress(R1, TypeArguments::type_at_offset(0)));
- __ CompareObject(R0, Type::ZoneHandle(Type::DynamicType()));
- __ b(&checked_ok, EQ);
-
- // Check for int and num.
- __ tst(R2, Operand(kSmiTagMask)); // Value is Smi?
- __ b(&fall_through, NE); // Non-smi value.
- __ CompareObject(R0, Type::ZoneHandle(Type::IntType()));
- __ b(&checked_ok, EQ);
- __ CompareObject(R0, Type::ZoneHandle(Type::Number()));
- __ b(&fall_through, NE);
- __ Bind(&checked_ok);
+ return;
}
+
+ Label fall_through;
__ ldr(R1, Address(SP, 1 * kWordSize)); // Index.
__ tst(R1, Operand(kSmiTagMask));
// Index not Smi.
diff --git a/runtime/vm/intrinsifier_arm64.cc b/runtime/vm/intrinsifier_arm64.cc
index 3fd338a..4441fe2 100644
--- a/runtime/vm/intrinsifier_arm64.cc
+++ b/runtime/vm/intrinsifier_arm64.cc
@@ -33,56 +33,14 @@
intptr_t Intrinsifier::ParameterSlotFromSp() { return -1; }
-static intptr_t ComputeObjectArrayTypeArgumentsOffset() {
- const Library& core_lib = Library::Handle(Library::CoreLibrary());
- const Class& cls = Class::Handle(
- core_lib.LookupClassAllowPrivate(Symbols::_List()));
- ASSERT(!cls.IsNull());
- ASSERT(cls.NumTypeArguments() == 1);
- const intptr_t field_offset = cls.type_arguments_field_offset();
- ASSERT(field_offset != Class::kNoTypeArguments);
- return field_offset;
-}
-
-
// Intrinsify only for Smi value and index. Non-smi values need a store buffer
// update. Array length is always a Smi.
void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) {
- Label fall_through;
-
if (Isolate::Current()->flags().type_checks()) {
- const intptr_t type_args_field_offset =
- ComputeObjectArrayTypeArgumentsOffset();
- // Inline simple tests (Smi, null), fallthrough if not positive.
- Label checked_ok;
- __ ldr(R2, Address(SP, 0 * kWordSize)); // Value.
-
- // Null value is valid for any type.
- __ CompareObject(R2, Object::null_object());
- __ b(&checked_ok, EQ);
-
- __ ldr(R1, Address(SP, 2 * kWordSize)); // Array.
- __ ldr(R1, FieldAddress(R1, type_args_field_offset));
-
- // R1: Type arguments of array.
- __ CompareObject(R1, Object::null_object());
- __ b(&checked_ok, EQ);
-
- // Check if it's dynamic.
- // Get type at index 0.
- __ ldr(R0, FieldAddress(R1, TypeArguments::type_at_offset(0)));
- __ CompareObject(R0, Type::ZoneHandle(Type::DynamicType()));
- __ b(&checked_ok, EQ);
-
- // Check for int and num.
- __ tsti(R2, Immediate(Immediate(kSmiTagMask))); // Value is Smi?
- __ b(&fall_through, NE); // Non-smi value.
- __ CompareObject(R0, Type::ZoneHandle(Type::IntType()));
- __ b(&checked_ok, EQ);
- __ CompareObject(R0, Type::ZoneHandle(Type::Number()));
- __ b(&fall_through, NE);
- __ Bind(&checked_ok);
+ return;
}
+
+ Label fall_through;
__ ldr(R1, Address(SP, 1 * kWordSize)); // Index.
__ tsti(R1, Immediate(kSmiTagMask));
// Index not Smi.
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index 85234a3..7349e85 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -33,53 +33,14 @@
intptr_t Intrinsifier::ParameterSlotFromSp() { return -1; }
-static intptr_t ComputeObjectArrayTypeArgumentsOffset() {
- const Library& core_lib = Library::Handle(Library::CoreLibrary());
- const Class& cls = Class::Handle(
- core_lib.LookupClassAllowPrivate(Symbols::_List()));
- ASSERT(!cls.IsNull());
- ASSERT(cls.NumTypeArguments() == 1);
- const intptr_t field_offset = cls.type_arguments_field_offset();
- ASSERT(field_offset != Class::kNoTypeArguments);
- return field_offset;
-}
-
-
// Intrinsify only for Smi value and index. Non-smi values need a store buffer
// update. Array length is always a Smi.
void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) {
- Label fall_through;
-
if (Isolate::Current()->flags().type_checks()) {
- const intptr_t type_args_field_offset =
- ComputeObjectArrayTypeArgumentsOffset();
- // Inline simple tests (Smi, null), fallthrough if not positive.
- Label checked_ok;
- __ lw(T2, Address(SP, 0 * kWordSize)); // Value.
-
- // Null value is valid for any type.
- __ LoadObject(T7, Object::null_object());
- __ beq(T2, T7, &checked_ok);
-
- __ lw(T1, Address(SP, 2 * kWordSize)); // Array.
- __ lw(T1, FieldAddress(T1, type_args_field_offset));
-
- // T1: Type arguments of array.
- __ beq(T1, T7, &checked_ok);
-
- // Check if it's dynamic.
- // Get type at index 0.
- __ lw(T0, FieldAddress(T1, TypeArguments::type_at_offset(0)));
- __ BranchEqual(T0, Type::ZoneHandle(Type::DynamicType()), &checked_ok);
-
- // Check for int and num.
- __ andi(CMPRES1, T2, Immediate(kSmiTagMask));
- __ bne(CMPRES1, ZR, &fall_through); // Non-smi value.
-
- __ BranchEqual(T0, Type::ZoneHandle(Type::IntType()), &checked_ok);
- __ BranchNotEqual(T0, Type::ZoneHandle(Type::Number()), &fall_through);
- __ Bind(&checked_ok);
+ return;
}
+
+ Label fall_through;
__ lw(T1, Address(SP, 1 * kWordSize)); // Index.
__ andi(CMPRES1, T1, Immediate(kSmiTagMask));
// Index not Smi.
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index e489012..4598ddd 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -37,10 +37,11 @@
if (Isolate::Current()->flags().type_checks()) {
return;
}
+
+ Label fall_through;
__ movq(RDX, Address(RSP, + 1 * kWordSize)); // Value.
__ movq(RCX, Address(RSP, + 2 * kWordSize)); // Index.
__ movq(RAX, Address(RSP, + 3 * kWordSize)); // Array.
- Label fall_through;
__ testq(RCX, Immediate(kSmiTagMask));
__ j(NOT_ZERO, &fall_through);
// Range check.
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 9229d81..e542420 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -8,7 +8,9 @@
#include "include/dart_native_api.h"
#include "platform/assert.h"
#include "platform/json.h"
+#include "vm/class_finalizer.h"
#include "vm/code_observers.h"
+#include "vm/compiler.h"
#include "vm/compiler_stats.h"
#include "vm/coverage.h"
#include "vm/dart_api_message.h"
@@ -24,7 +26,6 @@
#include "vm/object_store.h"
#include "vm/object.h"
#include "vm/os_thread.h"
-#include "vm/parser.h"
#include "vm/port.h"
#include "vm/profiler.h"
#include "vm/reusable_handles.h"
@@ -177,7 +178,7 @@
const char* name() const;
void MessageNotify(Message::Priority priority);
- bool HandleMessage(Message* message);
+ MessageStatus HandleMessage(Message* message);
void NotifyPauseOnStart();
void NotifyPauseOnExit();
@@ -193,7 +194,7 @@
// processing of further events.
RawError* HandleLibMessage(const Array& message);
- bool ProcessUnhandledException(const Error& result);
+ MessageStatus ProcessUnhandledException(const Error& result);
Isolate* isolate_;
};
@@ -284,7 +285,8 @@
break;
}
case Isolate::kKillMsg:
- case Isolate::kInternalKillMsg: {
+ case Isolate::kInternalKillMsg:
+ case Isolate::kVMRestartMsg: {
// [ OOB, kKillMsg, terminate capability, priority ]
if (message.Length() != 4) return Error::null();
Object& obj = Object::Handle(I, message.At(3));
@@ -292,8 +294,8 @@
const intptr_t priority = Smi::Cast(obj).Value();
if (priority == Isolate::kImmediateAction) {
obj = message.At(2);
- // Signal that the isolate should stop execution.
if (I->VerifyTerminateCapability(obj)) {
+ // We will kill the current isolate by returning an UnwindError.
if (msg_type == Isolate::kKillMsg) {
const String& msg = String::Handle(String::New(
"isolate terminated by Isolate.kill"));
@@ -301,14 +303,22 @@
UnwindError::Handle(UnwindError::New(msg));
error.set_is_user_initiated(true);
return error.raw();
- } else {
- // TODO(turnidge): We should give the message handler a way
- // to detect when an isolate is unwinding.
- I->message_handler()->set_pause_on_start(false);
- I->message_handler()->set_pause_on_exit(false);
+ } else if (msg_type == Isolate::kInternalKillMsg) {
const String& msg = String::Handle(String::New(
"isolate terminated by vm"));
return UnwindError::New(msg);
+ } else if (msg_type == Isolate::kVMRestartMsg) {
+ // If this is the main isolate, this request to restart
+ // will be caught and handled in the embedder. Otherwise
+ // this unwind error will cause the isolate to exit.
+ const String& msg = String::Handle(String::New(
+ "isolate terminated for vm restart"));
+ const UnwindError& error =
+ UnwindError::Handle(UnwindError::New(msg));
+ error.set_is_vm_restart(true);
+ return error.raw();
+ } else {
+ UNREACHABLE();
}
} else {
return Error::null();
@@ -420,7 +430,8 @@
}
-bool IsolateMessageHandler::HandleMessage(Message* message) {
+MessageHandler::MessageStatus IsolateMessageHandler::HandleMessage(
+ Message* message) {
ASSERT(IsCurrentIsolate());
Thread* thread = Thread::Current();
StackZone stack_zone(thread);
@@ -430,10 +441,6 @@
tds.SetNumArguments(1);
tds.CopyArgument(0, "isolateName", I->name());
- // TODO(turnidge): Rework collection total dart execution. This can
- // overcount when other things (gc, compilation) are active.
- TIMERSCOPE(thread, time_dart_execution);
-
// If the message is in band we lookup the handler to dispatch to. If the
// receive port was closed, we drop the message without deserializing it.
// Illegal port is a special case for artificially enqueued isolate library
@@ -453,7 +460,7 @@
} else {
delete message;
}
- return true;
+ return kOK;
}
}
@@ -477,7 +484,7 @@
Instance& msg = Instance::Handle(zone);
msg ^= msg_obj.raw(); // Can't use Instance::Cast because may be null.
- bool success = true;
+ MessageStatus status = kOK;
if (message->IsOOB()) {
// OOB messages are expected to be fixed length arrays where the first
// element is a Smi describing the OOB destination. Messages that do not
@@ -495,7 +502,7 @@
case Message::kIsolateLibOOBMsg: {
const Error& error = Error::Handle(HandleLibMessage(oob_msg));
if (!error.IsNull()) {
- success = ProcessUnhandledException(error);
+ status = ProcessUnhandledException(error);
}
break;
}
@@ -522,7 +529,7 @@
(Smi::Cast(oob_tag).Value() == Message::kDelayedIsolateLibOOBMsg)) {
const Error& error = Error::Handle(HandleLibMessage(msg_arr));
if (!error.IsNull()) {
- success = ProcessUnhandledException(error);
+ status = ProcessUnhandledException(error);
}
}
}
@@ -531,22 +538,22 @@
const Object& result = Object::Handle(zone,
DartLibraryCalls::HandleMessage(msg_handler, msg));
if (result.IsError()) {
- success = ProcessUnhandledException(Error::Cast(result));
+ status = ProcessUnhandledException(Error::Cast(result));
} else {
ASSERT(result.IsNull());
}
}
delete message;
- if (success) {
+ if (status == kOK) {
const Object& result =
Object::Handle(zone, I->InvokePendingServiceExtensionCalls());
if (result.IsError()) {
- success = ProcessUnhandledException(Error::Cast(result));
+ status = ProcessUnhandledException(Error::Cast(result));
} else {
ASSERT(result.IsNull());
}
}
- return success;
+ return status;
}
@@ -590,7 +597,25 @@
}
-bool IsolateMessageHandler::ProcessUnhandledException(const Error& result) {
+static MessageHandler::MessageStatus StoreError(Isolate* isolate,
+ const Error& error) {
+ isolate->object_store()->set_sticky_error(error);
+ if (error.IsUnwindError()) {
+ const UnwindError& unwind = UnwindError::Cast(error);
+ if (!unwind.is_user_initiated()) {
+ if (unwind.is_vm_restart()) {
+ return MessageHandler::kRestart;
+ } else {
+ return MessageHandler::kShutdown;
+ }
+ }
+ }
+ return MessageHandler::kError;
+}
+
+
+MessageHandler::MessageStatus IsolateMessageHandler::ProcessUnhandledException(
+ const Error& result) {
// Notify the debugger about specific unhandled exceptions which are withheld
// when being thrown.
if (result.IsUnhandledException()) {
@@ -634,9 +659,9 @@
exc_str = String::New(result.ToErrorCString());
}
if (result.IsUnwindError()) {
- // Unwind errors are always fatal and don't notify listeners.
- I->object_store()->set_sticky_error(result);
- return false;
+ // When unwinding we don't notify error listeners and we ignore
+ // whether errors are fatal for the current isolate.
+ return StoreError(I, result);
} else {
bool has_listener = I->NotifyErrorListeners(exc_str, stacktrace_str);
if (I->ErrorsFatal()) {
@@ -645,10 +670,10 @@
} else {
I->object_store()->set_sticky_error(result);
}
- return false;
+ return kError;
}
}
- return true;
+ return kOK;
}
@@ -704,9 +729,15 @@
object##_handle_(NULL),
Isolate::Isolate(const Dart_IsolateFlags& api_flags)
- : vm_tag_(0),
+ : stack_limit_(0),
store_buffer_(new StoreBuffer()),
heap_(NULL),
+ vm_tag_(0),
+ user_tag_(0),
+ current_tag_(UserTag::null()),
+ default_tag_(UserTag::null()),
+ class_table_(),
+ single_step_(false),
thread_registry_(new ThreadRegistry()),
message_notify_callback_(NULL),
name_(NULL),
@@ -724,17 +755,14 @@
library_tag_handler_(NULL),
api_state_(NULL),
debugger_(NULL),
- single_step_(false),
resume_request_(false),
last_resume_timestamp_(OS::GetCurrentTimeMillis()),
has_compiled_(false),
flags_(),
random_(),
simulator_(NULL),
- timer_list_(),
deopt_id_(0),
mutex_(new Mutex()),
- stack_limit_(0),
saved_stack_limit_(0),
stack_base_(0),
stack_overflow_flags_(0),
@@ -746,6 +774,7 @@
gc_epilogue_callback_(NULL),
defer_finalization_count_(0),
deopt_context_(NULL),
+ background_compiler_(NULL),
compiler_stats_(NULL),
is_service_isolate_(false),
stacktrace_(NULL),
@@ -756,10 +785,9 @@
trace_buffer_(NULL),
profiler_data_(NULL),
tag_table_(GrowableObjectArray::null()),
- current_tag_(UserTag::null()),
- default_tag_(UserTag::null()),
collected_closures_(GrowableObjectArray::null()),
deoptimized_code_array_(GrowableObjectArray::null()),
+ background_compilation_queue_(GrowableObjectArray::null()),
pending_service_extension_calls_(GrowableObjectArray::null()),
registered_service_extension_handlers_(GrowableObjectArray::null()),
metrics_list_head_(NULL),
@@ -771,7 +799,7 @@
REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT)
reusable_handles_() {
flags_.CopyFrom(api_flags);
- set_vm_tag(VMTag::kEmbedderTagId);
+ Thread::Current()->set_vm_tag(VMTag::kEmbedderTagId);
set_user_tag(UserTags::kDefaultUserTag);
}
@@ -1308,13 +1336,7 @@
}
-static void StoreError(Isolate* isolate, const Object& obj) {
- ASSERT(obj.IsError());
- isolate->object_store()->set_sticky_error(Error::Cast(obj));
-}
-
-
-static bool RunIsolate(uword parameter) {
+static MessageHandler::MessageStatus RunIsolate(uword parameter) {
Isolate* isolate = reinterpret_cast<Isolate*>(parameter);
IsolateSpawnState* state = NULL;
Thread* thread = Thread::Current();
@@ -1348,15 +1370,19 @@
if (!ClassFinalizer::ProcessPendingClasses()) {
// Error is in sticky error already.
- return false;
+#if defined(DEBUG)
+ const Error& error =
+ Error::Handle(isolate->object_store()->sticky_error());
+ ASSERT(!error.IsUnwindError());
+#endif
+ return MessageHandler::kError;
}
Object& result = Object::Handle();
result = state->ResolveFunction();
bool is_spawn_uri = state->is_spawn_uri();
if (result.IsError()) {
- StoreError(isolate, result);
- return false;
+ return StoreError(isolate, Error::Cast(result));
}
ASSERT(result.IsFunction());
Function& func = Function::Handle(isolate);
@@ -1411,11 +1437,10 @@
result = DartEntry::InvokeFunction(entry_point, args);
if (result.IsError()) {
- StoreError(isolate, result);
- return false;
+ return StoreError(isolate, Error::Cast(result));
}
}
- return true;
+ return MessageHandler::kOK;
}
@@ -1474,8 +1499,9 @@
}
}
if ((interrupt_bits & kMessageInterrupt) != 0) {
- bool ok = message_handler()->HandleOOBMessages();
- if (!ok) {
+ MessageHandler::MessageStatus status =
+ message_handler()->HandleOOBMessages();
+ if (status != MessageHandler::kOK) {
// False result from HandleOOBMessages signals that the isolate should
// be terminating.
if (FLAG_trace_isolates) {
@@ -1483,8 +1509,8 @@
"\tisolate: %s\n", name());
}
const Error& error = Error::Handle(object_store()->sticky_error());
+ ASSERT(!error.IsNull() && error.IsUnwindError());
object_store()->clear_sticky_error();
- ASSERT(!error.IsNull());
return error.raw();
}
}
@@ -1596,9 +1622,6 @@
delete message_handler();
set_message_handler(NULL);
- // Dump all accumulated timer data for the isolate.
- timer_list_.ReportTimers();
-
// Before analyzing the isolate's timeline blocks- reclaim all cached blocks.
ReclaimTimelineBlocks();
@@ -1691,6 +1714,8 @@
}
#endif
+ BackgroundCompiler::Stop(background_compiler_);
+
// TODO(5411455): For now just make sure there are no current isolates
// as we are shutting down the isolate.
Thread::ExitIsolate();
@@ -1766,6 +1791,9 @@
// Visit array of closures pending precompilation.
visitor->VisitPointer(reinterpret_cast<RawObject**>(&collected_closures_));
+ visitor->VisitPointer(reinterpret_cast<RawObject**>(
+ &background_compilation_queue_));
+
// Visit the deoptimized code array which is stored in the isolate.
visitor->VisitPointer(
reinterpret_cast<RawObject**>(&deoptimized_code_array_));
@@ -1820,15 +1848,6 @@
}
int64_t start_time_millis = start_time() / kMicrosecondsPerMillisecond;
jsobj.AddPropertyTimeMillis("startTime", start_time_millis);
- IsolateSpawnState* state = spawn_state();
- if (state != NULL) {
- const Object& entry = Object::Handle(this, state->ResolveFunction());
- if (!entry.IsNull() && entry.IsFunction()) {
- Function& func = Function::Handle(this);
- func ^= entry.raw();
- jsobj.AddProperty("entry", func);
- }
- }
{
JSONObject jsheap(&jsobj, "_heaps");
heap()->PrintToJSONObject(Heap::kNew, &jsheap);
@@ -1866,7 +1885,6 @@
jsobj.AddProperty("rootLib", lib);
}
- timer_list().PrintTimersToJSONProperty(&jsobj);
{
JSONObject tagCounters(&jsobj, "_tagCounters");
vm_tag_counters()->PrintToJSONObject(&tagCounters);
@@ -1953,7 +1971,8 @@
void Isolate::ProfileIdle() {
- vm_tag_counters_.Increment(vm_tag());
+ // Currently we are only sampling the mutator thread.
+ vm_tag_counters_.Increment(VMTag::kIdleTagId);
}
@@ -1985,6 +2004,12 @@
}
+void Isolate::set_background_compilation_queue(
+ const GrowableObjectArray& value) {
+ background_compilation_queue_ = value.raw();
+}
+
+
void Isolate::TrackDeoptimizedCode(const Code& code) {
ASSERT(!code.IsNull());
const GrowableObjectArray& deoptimized_code =
@@ -2294,7 +2319,7 @@
}
-void Isolate::KillLocked() {
+void Isolate::KillLocked(LibMsgId msg_id) {
Dart_CObject kill_msg;
Dart_CObject* list_values[4];
kill_msg.type = Dart_CObject_kArray;
@@ -2308,7 +2333,7 @@
Dart_CObject msg_type;
msg_type.type = Dart_CObject_kInt32;
- msg_type.value.as_int32 = Isolate::kInternalKillMsg;
+ msg_type.value.as_int32 = msg_id;
list_values[1] = &msg_type;
Dart_CObject cap;
@@ -2339,10 +2364,11 @@
class IsolateKillerVisitor : public IsolateVisitor {
public:
- IsolateKillerVisitor() : target_(NULL) {}
+ explicit IsolateKillerVisitor(Isolate::LibMsgId msg_id)
+ : target_(NULL), msg_id_(msg_id) {}
- explicit IsolateKillerVisitor(Isolate* isolate)
- : target_(isolate) {
+ IsolateKillerVisitor(Isolate* isolate, Isolate::LibMsgId msg_id)
+ : target_(isolate), msg_id_(msg_id) {
ASSERT(isolate != Dart::vm_isolate());
}
@@ -2351,7 +2377,7 @@
void VisitIsolate(Isolate* isolate) {
ASSERT(isolate != NULL);
if (ShouldKill(isolate)) {
- isolate->KillLocked();
+ isolate->KillLocked(msg_id_);
}
}
@@ -2366,17 +2392,18 @@
}
Isolate* target_;
+ Isolate::LibMsgId msg_id_;
};
-void Isolate::KillAllIsolates() {
- IsolateKillerVisitor visitor;
+void Isolate::KillAllIsolates(LibMsgId msg_id) {
+ IsolateKillerVisitor visitor(msg_id);
VisitIsolates(&visitor);
}
-void Isolate::KillIfExists(Isolate* isolate) {
- IsolateKillerVisitor visitor(isolate);
+void Isolate::KillIfExists(Isolate* isolate, LibMsgId msg_id) {
+ IsolateKillerVisitor visitor(isolate, msg_id);
VisitIsolates(&visitor);
}
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 265960c..00406ed 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -27,6 +27,7 @@
class AbstractType;
class ApiState;
class Array;
+class BackgroundCompiler;
class Capability;
class CHA;
class Class;
@@ -129,6 +130,7 @@
// Internal message ids.
kInterruptMsg = 10, // Break in the debugger.
kInternalKillMsg = 11, // Like kill, but does not run exit listeners, etc.
+ kVMRestartMsg = 12, // Sent to isolates when vm is restarting.
};
// The different Isolate API message priorities for ping and kill messages.
enum LibMsgPriority {
@@ -217,9 +219,6 @@
ObjectStore* object_store() const { return object_store_; }
void set_object_store(ObjectStore* value) { object_store_ = value; }
- static intptr_t object_store_offset() {
- return OFFSET_OF(Isolate, object_store_);
- }
// DEPRECATED: Use Thread's methods instead. During migration, these default
// to using the mutator thread (which must also be the current thread).
@@ -241,21 +240,9 @@
mutator_thread_->set_top_exit_frame_info(value);
}
- uword vm_tag() const {
- return vm_tag_;
- }
- void set_vm_tag(uword tag) {
- vm_tag_ = tag;
- }
- static intptr_t vm_tag_offset() {
- return OFFSET_OF(Isolate, vm_tag_);
- }
-
ApiState* api_state() const { return api_state_; }
void set_api_state(ApiState* value) { api_state_ = value; }
- TimerList& timer_list() { return timer_list_; }
-
void set_init_callback_data(void* value) {
init_callback_data_ = value;
}
@@ -605,6 +592,13 @@
deopt_context_ = value;
}
+ BackgroundCompiler* background_compiler() const {
+ return background_compiler_;
+ }
+ void set_background_compiler(BackgroundCompiler* value) {
+ background_compiler_ = value;
+ }
+
void UpdateLastAllocationProfileAccumulatorResetTimestamp() {
last_allocationprofile_accumulator_reset_timestamp_ =
OS::GetCurrentTimeMillis();
@@ -701,6 +695,11 @@
}
void set_collected_closures(const GrowableObjectArray& value);
+ RawGrowableObjectArray* background_compilation_queue() const {
+ return background_compilation_queue_;
+ }
+ void set_background_compilation_queue(const GrowableObjectArray& value);
+
Metric* metrics_list_head() {
return metrics_list_head_;
}
@@ -768,8 +767,8 @@
bool is_service_isolate() const { return is_service_isolate_; }
- static void KillAllIsolates();
- static void KillIfExists(Isolate* isolate);
+ static void KillAllIsolates(LibMsgId msg_id);
+ static void KillIfExists(Isolate* isolate, LibMsgId msg_id);
static void DisableIsolateCreation();
static void EnableIsolateCreation();
@@ -786,7 +785,7 @@
bool is_vm_isolate = false);
// The isolates_list_monitor_ should be held when calling Kill().
- void KillLocked();
+ void KillLocked(LibMsgId msg_id);
void LowLevelShutdown();
void Shutdown();
@@ -832,11 +831,18 @@
template<class T> T* AllocateReusableHandle();
- uword vm_tag_;
+ // Accessed from generated code:
+ uword stack_limit_;
StoreBuffer* store_buffer_;
Heap* heap_;
- ThreadRegistry* thread_registry_;
+ uword vm_tag_;
+ uword user_tag_;
+ RawUserTag* current_tag_;
+ RawUserTag* default_tag_;
ClassTable class_table_;
+ bool single_step_;
+
+ ThreadRegistry* thread_registry_;
Dart_MessageNotifyCallback message_notify_callback_;
char* name_;
char* debugger_name_;
@@ -853,17 +859,14 @@
Dart_LibraryTagHandler library_tag_handler_;
ApiState* api_state_;
Debugger* debugger_;
- bool single_step_;
bool resume_request_;
int64_t last_resume_timestamp_;
bool has_compiled_;
Flags flags_;
Random random_;
Simulator* simulator_;
- TimerList timer_list_;
intptr_t deopt_id_;
Mutex* mutex_; // protects stack_limit_ and saved_stack_limit_.
- uword stack_limit_;
uword saved_stack_limit_;
uword stack_base_;
uword stack_overflow_flags_;
@@ -875,6 +878,7 @@
Dart_GcEpilogueCallback gc_epilogue_callback_;
intptr_t defer_finalization_count_;
DeoptContext* deopt_context_;
+ BackgroundCompiler* background_compiler_;
CompilerStats* compiler_stats_;
@@ -898,13 +902,12 @@
Mutex profiler_data_mutex_;
VMTagCounters vm_tag_counters_;
- uword user_tag_;
RawGrowableObjectArray* tag_table_;
- RawUserTag* current_tag_;
- RawUserTag* default_tag_;
+
RawGrowableObjectArray* collected_closures_;
RawGrowableObjectArray* deoptimized_code_array_;
+ RawGrowableObjectArray* background_compilation_queue_;
// We use 6 list entries for each pending service extension calls.
enum {
diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc
index f25add7..b5da5dd 100644
--- a/runtime/vm/json_stream.cc
+++ b/runtime/vm/json_stream.cc
@@ -292,23 +292,27 @@
void JSONStream::PrintValue(intptr_t i) {
+ EnsureIntegerIsRepresentableInJavaScript(static_cast<int64_t>(i));
PrintCommaIfNeeded();
buffer_.Printf("%" Pd "", i);
}
void JSONStream::PrintValue64(int64_t i) {
+ EnsureIntegerIsRepresentableInJavaScript(i);
PrintCommaIfNeeded();
buffer_.Printf("%" Pd64 "", i);
}
void JSONStream::PrintValueTimeMillis(int64_t millis) {
- PrintValue(static_cast<double>(millis));
+ EnsureIntegerIsRepresentableInJavaScript(millis);
+ PrintValue64(millis);
}
void JSONStream::PrintValueTimeMicros(int64_t micros) {
+ EnsureIntegerIsRepresentableInJavaScript(micros);
PrintValue64(micros);
}
@@ -452,21 +456,19 @@
void JSONStream::PrintProperty(const char* name, intptr_t i) {
- ASSERT(Utils::IsJavascriptInt(i));
PrintPropertyName(name);
PrintValue(i);
}
void JSONStream::PrintProperty64(const char* name, int64_t i) {
- ASSERT(Utils::IsJavascriptInt64(i));
PrintPropertyName(name);
PrintValue64(i);
}
void JSONStream::PrintPropertyTimeMillis(const char* name, int64_t millis) {
- PrintProperty(name, static_cast<double>(millis));
+ PrintProperty64(name, millis);
}
@@ -620,6 +622,17 @@
}
+void JSONStream::EnsureIntegerIsRepresentableInJavaScript(int64_t i) {
+#ifdef DEBUG
+ if (!Utils::IsJavascriptInt(i)) {
+ OS::Print("JSONStream::EnsureIntegerIsRepresentableInJavaScript failed on "
+ "%" Pd64 "\n", i);
+ UNREACHABLE();
+ }
+#endif
+}
+
+
void JSONStream::AddEscapedUTF8String(const char* s) {
if (s == NULL) {
return;
diff --git a/runtime/vm/json_stream.h b/runtime/vm/json_stream.h
index a6ae55f..78f6fdd 100644
--- a/runtime/vm/json_stream.h
+++ b/runtime/vm/json_stream.h
@@ -172,6 +172,9 @@
intptr_t nesting_level() const { return open_objects_; }
+ // Debug only fatal assertion.
+ static void EnsureIntegerIsRepresentableInJavaScript(int64_t i);
+
intptr_t open_objects_;
TextBuffer buffer_;
// Default service id zone.
diff --git a/runtime/vm/locations.h b/runtime/vm/locations.h
index 5e92c16..047b663 100644
--- a/runtime/vm/locations.h
+++ b/runtime/vm/locations.h
@@ -148,7 +148,7 @@
return (value_ & kLocationTagMask) == kConstantTag;
}
- static Location Constant(ConstantInstr* obj) {
+ static Location Constant(const ConstantInstr* obj) {
Location loc(reinterpret_cast<uword>(obj) | kConstantTag);
ASSERT(obj == loc.constant_instruction());
return loc;
diff --git a/runtime/vm/message_handler.cc b/runtime/vm/message_handler.cc
index ef8a71e..47ab4b9 100644
--- a/runtime/vm/message_handler.cc
+++ b/runtime/vm/message_handler.cc
@@ -6,6 +6,8 @@
#include "vm/dart.h"
#include "vm/lockers.h"
+#include "vm/object.h"
+#include "vm/object_store.h"
#include "vm/os.h"
#include "vm/port.h"
#include "vm/thread_interrupter.h"
@@ -35,6 +37,24 @@
};
+// static
+const char* MessageHandler::MessageStatusString(MessageStatus status) {
+ switch (status) {
+ case kOK:
+ return "OK";
+ case kError:
+ return "Error";
+ case kRestart:
+ return "Restart";
+ case kShutdown:
+ return "Shutdown";
+ default:
+ UNREACHABLE();
+ return "Illegal";
+ }
+}
+
+
MessageHandler::MessageHandler()
: queue_(new MessageQueue()),
oob_queue_(new MessageQueue()),
@@ -150,8 +170,16 @@
}
-bool MessageHandler::HandleMessages(bool allow_normal_messages,
- bool allow_multiple_normal_messages) {
+void MessageHandler::ClearOOBQueue() {
+ oob_queue_->Clear();
+}
+
+
+MessageHandler::MessageStatus MessageHandler::HandleMessages(
+ bool allow_normal_messages,
+ bool allow_multiple_normal_messages) {
+ // TODO(turnidge): Add assert that monitor_ is held here.
+
// If isolate() returns NULL StartIsolateScope does nothing.
StartIsolateScope start_isolate(isolate());
@@ -159,10 +187,10 @@
// an isolate to start handling messages.
ThreadInterrupter::WakeUp();
- // TODO(turnidge): Add assert that monitor_ is held here.
- bool result = true;
- Message::Priority min_priority = (allow_normal_messages && !paused()) ?
- Message::kNormalPriority : Message::kOOBPriority;
+ MessageStatus max_status = kOK;
+ Message::Priority min_priority = ((allow_normal_messages && !paused())
+ ? Message::kNormalPriority
+ : Message::kOOBPriority);
Message* message = DequeueMessage(min_priority);
while (message != NULL) {
intptr_t message_len = message->len();
@@ -179,38 +207,50 @@
monitor_.Exit();
Message::Priority saved_priority = message->priority();
Dart_Port saved_dest_port = message->dest_port();
- result = HandleMessage(message);
+ MessageStatus status = HandleMessage(message);
+ if (status > max_status) {
+ max_status = status;
+ }
message = NULL; // May be deleted by now.
monitor_.Enter();
if (FLAG_trace_isolates) {
- OS::Print("[.] Message handled:\n"
+ OS::Print("[.] Message handled (%s):\n"
"\tlen: %" Pd "\n"
"\thandler: %s\n"
"\tport: %" Pd64 "\n",
+ MessageStatusString(status),
message_len, name(), saved_dest_port);
}
- if (!result) {
- // If we hit an error, we're done processing messages.
+ // If we are shutting down, do not process any more messages.
+ if (status == kShutdown) {
+ ClearOOBQueue();
break;
}
+
// Some callers want to process only one normal message and then quit. At
// the same time it is OK to process multiple OOB messages.
if ((saved_priority == Message::kNormalPriority) &&
!allow_multiple_normal_messages) {
- break;
+ // We processed one normal message. Allow no more.
+ allow_normal_messages = false;
}
- // Reevaluate the minimum allowable priority as the paused state might
- // have changed as part of handling the message.
- min_priority = (allow_normal_messages && !paused()) ?
- Message::kNormalPriority : Message::kOOBPriority;
+ // Reevaluate the minimum allowable priority. The paused state
+ // may have changed as part of handling the message. We may also
+ // have encountered an error during message processsing.
+ //
+ // Even if we encounter an error, we still process pending OOB
+ // messages so that we don't lose the message notification.
+ min_priority = (((max_status == kOK) && allow_normal_messages && !paused())
+ ? Message::kNormalPriority
+ : Message::kOOBPriority);
message = DequeueMessage(min_priority);
}
- return result;
+ return max_status;
}
-bool MessageHandler::HandleNextMessage() {
+MessageHandler::MessageStatus MessageHandler::HandleNextMessage() {
// We can only call HandleNextMessage when this handler is not
// assigned to a thread pool.
MonitorLocker ml(&monitor_);
@@ -222,9 +262,9 @@
}
-bool MessageHandler::HandleOOBMessages() {
+MessageHandler::MessageStatus MessageHandler::HandleOOBMessages() {
if (!oob_message_handling_allowed_) {
- return true;
+ return kOK;
}
MonitorLocker ml(&monitor_);
#if defined(DEBUG)
@@ -240,29 +280,39 @@
}
+static bool ShouldPause(MessageHandler::MessageStatus status) {
+ // If we are restarting or shutting down, we do not want to honor
+ // pause_on_start or pause_on_exit.
+ return (status != MessageHandler::kRestart &&
+ status != MessageHandler::kShutdown);
+}
+
+
void MessageHandler::TaskCallback() {
ASSERT(Isolate::Current() == NULL);
- bool ok = true;
+ MessageStatus status = kOK;
bool run_end_callback = false;
{
+ // We will occasionally release and reacquire this monitor in this
+ // function. Whenever we reacquire the monitor we *must* process
+ // all pending OOB messages, or we may miss a request for vm
+ // shutdown.
MonitorLocker ml(&monitor_);
- // Initialize the message handler by running its start function,
- // if we have one. For an isolate, this will run the isolate's
- // main() function.
if (pause_on_start()) {
if (!paused_on_start_) {
- // Temporarily drop the lock when calling out to NotifyPauseOnStart.
- // This avoids a dead lock that can occur when this message handler
- // tries to post a message while a message is being posted to it.
+ // Temporarily release the monitor when calling out to
+ // NotifyPauseOnStart. This avoids a dead lock that can occur
+ // when this message handler tries to post a message while a
+ // message is being posted to it.
paused_on_start_ = true;
paused_timestamp_ = OS::GetCurrentTimeMillis();
monitor_.Exit();
NotifyPauseOnStart();
monitor_.Enter();
}
- // More messages may have come in while we released monitor_.
- HandleMessages(false, false);
- if (pause_on_start()) {
+ // More messages may have come in before we (re)acquired the monitor.
+ status = HandleMessages(false, false);
+ if (ShouldPause(status) && pause_on_start()) {
// Still paused.
ASSERT(oob_queue_->IsEmpty());
task_ = NULL; // No task in queue.
@@ -273,40 +323,49 @@
}
}
- if (start_callback_) {
- // Release the monitor_ temporarily while we call the start callback.
- // The monitor was acquired with the MonitorLocker above.
- monitor_.Exit();
- ok = start_callback_(callback_data_);
- ASSERT(Isolate::Current() == NULL);
- start_callback_ = NULL;
- monitor_.Enter();
+ if (status == kOK) {
+ if (start_callback_) {
+ // Initialize the message handler by running its start function,
+ // if we have one. For an isolate, this will run the isolate's
+ // main() function.
+ //
+ // Release the monitor_ temporarily while we call the start callback.
+ monitor_.Exit();
+ status = start_callback_(callback_data_);
+ ASSERT(Isolate::Current() == NULL);
+ start_callback_ = NULL;
+ monitor_.Enter();
+ }
+
+ // Handle any pending messages for this message handler.
+ if (status != kShutdown) {
+ status = HandleMessages((status == kOK), true);
+ }
}
- // Handle any pending messages for this message handler.
- if (ok) {
- ok = HandleMessages(true, true);
- }
-
- if (!ok || !HasLivePorts()) {
- if (pause_on_exit()) {
+ // The isolate exits when it encounters an error or when it no
+ // longer has live ports.
+ if (status != kOK || !HasLivePorts()) {
+ if (ShouldPause(status) && pause_on_exit()) {
if (!paused_on_exit_) {
if (FLAG_trace_service_pause_events) {
OS::PrintErr("Isolate %s paused before exiting. "
"Use the Observatory to release it.\n", name());
}
- // Temporarily drop the lock when calling out to NotifyPauseOnExit.
- // This avoids a dead lock that can occur when this message handler
- // tries to post a message while a message is being posted to it.
+ // Temporarily release the monitor when calling out to
+ // NotifyPauseOnExit. This avoids a dead lock that can
+ // occur when this message handler tries to post a message
+ // while a message is being posted to it.
paused_on_exit_ = true;
paused_timestamp_ = OS::GetCurrentTimeMillis();
monitor_.Exit();
NotifyPauseOnExit();
monitor_.Enter();
+
+ // More messages may have come in while we released the monitor.
+ HandleMessages(false, false);
}
- // More messages may have come in while we released monitor_.
- HandleMessages(false, false);
- if (pause_on_exit()) {
+ if (ShouldPause(status) && pause_on_exit()) {
// Still paused.
ASSERT(oob_queue_->IsEmpty());
task_ = NULL; // No task in queue.
@@ -317,10 +376,18 @@
}
}
if (FLAG_trace_isolates) {
- OS::Print("[-] Stopping message handler (%s):\n"
- "\thandler: %s\n",
- (ok ? "no live ports" : "error"),
- name());
+ if (status != kOK && isolate() != NULL) {
+ const Error& error =
+ Error::Handle(isolate()->object_store()->sticky_error());
+ OS::Print("[-] Stopping message handler (%s):\n"
+ "\thandler: %s\n"
+ "\terror: %s\n",
+ MessageStatusString(status), name(), error.ToCString());
+ } else {
+ OS::Print("[-] Stopping message handler (%s):\n"
+ "\thandler: %s\n",
+ MessageStatusString(status), name());
+ }
}
pool_ = NULL;
run_end_callback = true;
diff --git a/runtime/vm/message_handler.h b/runtime/vm/message_handler.h
index 4a939ae..f4d907c 100644
--- a/runtime/vm/message_handler.h
+++ b/runtime/vm/message_handler.h
@@ -18,13 +18,21 @@
MessageHandler();
public:
+ enum MessageStatus {
+ kOK, // We successfully handled a message.
+ kError, // We encountered an error handling a message.
+ kRestart, // The VM is restarting.
+ kShutdown, // The VM is shutting down.
+ };
+ static const char* MessageStatusString(MessageStatus status);
+
virtual ~MessageHandler();
// Allow subclasses to provide a handler name.
virtual const char* name() const;
typedef uword CallbackData;
- typedef bool (*StartCallback)(CallbackData data);
+ typedef MessageStatus (*StartCallback)(CallbackData data);
typedef void (*EndCallback)(CallbackData data);
// Runs this message handler on the thread pool.
@@ -46,13 +54,13 @@
// or RunBlocking).
//
// Returns true on success.
- bool HandleNextMessage();
+ MessageStatus HandleNextMessage();
// Handles any OOB messages for this message handler. Can be used
// even if the message handler is running on the thread pool.
//
// Returns true on success.
- bool HandleOOBMessages();
+ MessageStatus HandleOOBMessages();
// Returns true if there are pending OOB messages for this message
// handler.
@@ -179,7 +187,7 @@
// Handles a single message. Provided by subclass.
//
// Returns true on success.
- virtual bool HandleMessage(Message* message) = 0;
+ virtual MessageStatus HandleMessage(Message* message) = 0;
virtual void NotifyPauseOnStart() {}
virtual void NotifyPauseOnExit() {}
@@ -199,9 +207,11 @@
// messages from the queue_.
Message* DequeueMessage(Message::Priority min_priority);
+ void ClearOOBQueue();
+
// Handles any pending messages.
- bool HandleMessages(bool allow_normal_messages,
- bool allow_multiple_normal_messages);
+ MessageStatus HandleMessages(bool allow_normal_messages,
+ bool allow_multiple_normal_messages);
Monitor monitor_; // Protects all fields in MessageHandler.
MessageQueue* queue_;
diff --git a/runtime/vm/message_handler_test.cc b/runtime/vm/message_handler_test.cc
index 7bfcb9a..ae7edab 100644
--- a/runtime/vm/message_handler_test.cc
+++ b/runtime/vm/message_handler_test.cc
@@ -39,7 +39,7 @@
message_count_(0),
start_called_(false),
end_called_(false),
- result_(true) {
+ results_(NULL) {
}
~TestMessageHandler() {
@@ -50,18 +50,23 @@
notify_count_++;
}
- bool HandleMessage(Message* message) {
+ MessageStatus HandleMessage(Message* message) {
// For testing purposes, keep a list of the ports
// for all messages we receive.
AddPortToBuffer(message->dest_port());
delete message;
message_count_++;
- return result_;
+ MessageStatus status = kOK;
+ if (results_ != NULL) {
+ status = results_[0];
+ results_++;
+ }
+ return status;
}
- bool Start() {
+ MessageStatus Start() {
start_called_ = true;
- return true;
+ return kOK;
}
void End() {
@@ -75,7 +80,7 @@
bool start_called() const { return start_called_; }
bool end_called() const { return end_called_; }
- void set_result(bool result) { result_ = result; }
+ void set_results(MessageStatus* results) { results_ = results; }
private:
void AddPortToBuffer(Dart_Port port) {
@@ -101,13 +106,13 @@
int message_count_;
bool start_called_;
bool end_called_;
- bool result_;
+ MessageStatus* results_;
DISALLOW_COPY_AND_ASSIGN(TestMessageHandler);
};
-bool TestStartFunction(uword data) {
+MessageHandler::MessageStatus TestStartFunction(uword data) {
return (reinterpret_cast<TestMessageHandler*>(data))->Start();
}
@@ -232,7 +237,7 @@
handler_peer.PostMessage(oob_message2);
// We handle both oob messages and a single normal message.
- EXPECT(handler.HandleNextMessage());
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
EXPECT_EQ(3, handler.message_count());
Dart_Port* ports = handler.port_buffer();
EXPECT_EQ(port2, ports[0]);
@@ -242,6 +247,75 @@
}
+UNIT_TEST_CASE(MessageHandler_HandleNextMessage_ProcessOOBAfterError) {
+ TestMessageHandler handler;
+ MessageHandler::MessageStatus results[] = {
+ MessageHandler::kError, // oob_message1
+ MessageHandler::kOK, // oob_message2
+ MessageHandler::kOK, // unused
+ };
+ handler.set_results(results);
+ MessageHandlerTestPeer handler_peer(&handler);
+ Dart_Port port1 = PortMap::CreatePort(&handler);
+ Dart_Port port2 = PortMap::CreatePort(&handler);
+ Dart_Port port3 = PortMap::CreatePort(&handler);
+ Message* message1 = new Message(port1, NULL, 0, Message::kNormalPriority);
+ handler_peer.PostMessage(message1);
+ Message* oob_message1 = new Message(port2, NULL, 0, Message::kOOBPriority);
+ handler_peer.PostMessage(oob_message1);
+ Message* oob_message2 = new Message(port3, NULL, 0, Message::kOOBPriority);
+ handler_peer.PostMessage(oob_message2);
+
+ // When we get an error, we continue processing oob messages but
+ // stop handling normal messages.
+ EXPECT_EQ(MessageHandler::kError, handler.HandleNextMessage());
+ EXPECT_EQ(2, handler.message_count());
+ Dart_Port* ports = handler.port_buffer();
+ EXPECT_EQ(port2, ports[0]); // oob_message1, error
+ EXPECT_EQ(port3, ports[1]); // oob_message2, ok
+ handler_peer.CloseAllPorts();
+}
+
+
+UNIT_TEST_CASE(MessageHandler_HandleNextMessage_Shutdown) {
+ TestMessageHandler handler;
+ MessageHandler::MessageStatus results[] = {
+ MessageHandler::kOK, // oob_message1
+ MessageHandler::kShutdown, // oob_message2
+ MessageHandler::kOK, // unused
+ MessageHandler::kOK, // unused
+ };
+ handler.set_results(results);
+ MessageHandlerTestPeer handler_peer(&handler);
+ Dart_Port port1 = PortMap::CreatePort(&handler);
+ Dart_Port port2 = PortMap::CreatePort(&handler);
+ Dart_Port port3 = PortMap::CreatePort(&handler);
+ Dart_Port port4 = PortMap::CreatePort(&handler);
+ Message* message1 = new Message(port1, NULL, 0, Message::kNormalPriority);
+ handler_peer.PostMessage(message1);
+ Message* oob_message1 = new Message(port2, NULL, 0, Message::kOOBPriority);
+ handler_peer.PostMessage(oob_message1);
+ Message* oob_message2 = new Message(port3, NULL, 0, Message::kOOBPriority);
+ handler_peer.PostMessage(oob_message2);
+ Message* oob_message3 = new Message(port4, NULL, 0, Message::kOOBPriority);
+ handler_peer.PostMessage(oob_message3);
+
+ // When we get a shutdown message, we stop processing all messages.
+ EXPECT_EQ(MessageHandler::kShutdown, handler.HandleNextMessage());
+ EXPECT_EQ(2, handler.message_count());
+ Dart_Port* ports = handler.port_buffer();
+ EXPECT_EQ(port2, ports[0]); // oob_message1, ok
+ EXPECT_EQ(port3, ports[1]); // oob_message2, shutdown
+ {
+ // The oob queue has been cleared. oob_message3 is gone.
+ MessageHandler::AcquiredQueues aq;
+ handler.AcquireQueues(&aq);
+ EXPECT(aq.oob_queue()->Length() == 0);
+ }
+ handler_peer.CloseAllPorts();
+}
+
+
UNIT_TEST_CASE(MessageHandler_HandleOOBMessages) {
TestMessageHandler handler;
MessageHandlerTestPeer handler_peer(&handler);
@@ -259,7 +333,7 @@
handler_peer.PostMessage(oob_message2);
// We handle both oob messages but no normal messages.
- EXPECT(handler.HandleOOBMessages());
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleOOBMessages());
EXPECT_EQ(2, handler.message_count());
Dart_Port* ports = handler.port_buffer();
EXPECT_EQ(port3, ports[0]);
diff --git a/runtime/vm/method_recognizer.h b/runtime/vm/method_recognizer.h
index a931290..5e8e576 100644
--- a/runtime/vm/method_recognizer.h
+++ b/runtime/vm/method_recognizer.h
@@ -130,8 +130,6 @@
V(_Uint16Array, []=, Uint16ArraySetIndexed, 1594961463) \
V(_Int32Array, [], Int32ArrayGetIndexed, 2052925823) \
V(_Int32Array, []=, Int32ArraySetIndexed, 504626978) \
- V(_Uint32Array, [], Uint32ArrayGetIndexed, 1034114777) \
- V(_Uint32Array, []=, Uint32ArraySetIndexed, 918159348) \
V(_Int64Array, [], Int64ArrayGetIndexed, 297668331) \
V(_Int64Array, []=, Int64ArraySetIndexed, 36465128) \
V(_Float32x4Array, [], Float32x4ArrayGetIndexed, 35821240) \
@@ -278,6 +276,8 @@
V(_Uint8Array, []=, Uint8ArraySetIndexed, 447309008) \
V(_ExternalUint8Array, [], ExternalUint8ArrayGetIndexed, 1293647140) \
V(_ExternalUint8Array, []=, ExternalUint8ArraySetIndexed, 1593599192) \
+ V(_Uint32Array, [], Uint32ArrayGetIndexed, 1034114777) \
+ V(_Uint32Array, []=, Uint32ArraySetIndexed, 918159348) \
V(_Float64Array, []=, Float64ArraySetIndexed, 887301703) \
V(_Float64Array, [], Float64ArrayGetIndexed, 1959896670) \
V(_TypedList, get:length, TypedDataLength, 522684521) \
diff --git a/runtime/vm/metrics.cc b/runtime/vm/metrics.cc
index 79038fb..0e15c0f 100644
--- a/runtime/vm/metrics.cc
+++ b/runtime/vm/metrics.cc
@@ -276,6 +276,12 @@
}
+int64_t MetricHeapUsed::Value() const {
+ ASSERT(isolate() == Isolate::Current());
+ return isolate()->heap()->UsedInWords(Heap::kNew) * kWordSize +
+ isolate()->heap()->UsedInWords(Heap::kOld) * kWordSize;
+}
+
int64_t MetricIsolateCount::Value() const {
return Isolate::IsolateListLength();
}
@@ -307,4 +313,30 @@
}
}
+
+MaxMetric::MaxMetric()
+ : Metric() {
+ set_value(kMinInt64);
+}
+
+
+void MaxMetric::SetValue(int64_t new_value) {
+ if (new_value > value()) {
+ set_value(new_value);
+ }
+}
+
+
+MinMetric::MinMetric()
+ : Metric() {
+ set_value(kMaxInt64);
+}
+
+
+void MinMetric::SetValue(int64_t new_value) {
+ if (new_value < value()) {
+ set_value(new_value);
+ }
+}
+
} // namespace dart
diff --git a/runtime/vm/metrics.h b/runtime/vm/metrics.h
index 03cead2..9fde2d8 100644
--- a/runtime/vm/metrics.h
+++ b/runtime/vm/metrics.h
@@ -15,14 +15,20 @@
// Metrics for each isolate.
#define ISOLATE_METRIC_LIST(V) \
V(MetricHeapOldUsed, HeapOldUsed, "heap.old.used", kByte) \
+ V(MaxMetric, HeapOldUsedMax, "heap.old.used.max", kByte) \
V(MetricHeapOldCapacity, HeapOldCapacity, "heap.old.capacity", kByte) \
+ V(MaxMetric, HeapOldCapacityMax, "heap.old.capacity.max", kByte) \
V(MetricHeapOldExternal, HeapOldExternal, "heap.old.external", kByte) \
V(MetricHeapNewUsed, HeapNewUsed, "heap.new.used", kByte) \
+ V(MaxMetric, HeapNewUsedMax, "heap.new.used.max", kByte) \
V(MetricHeapNewCapacity, HeapNewCapacity, "heap.new.capacity", kByte) \
+ V(MaxMetric, HeapNewCapacityMax, "heap.new.capacity.max", kByte) \
V(MetricHeapNewExternal, HeapNewExternal, "heap.new.external", kByte) \
+ V(MetricHeapUsed, HeapGlobalUsed, "heap.global.used", kByte) \
+ V(MaxMetric, HeapGlobalUsedMax, "heap.global.used.max", kByte) \
#define VM_METRIC_LIST(V) \
- V(MetricIsolateCount, IsolateCount, "vm.isolate.count", kCounter) \
+ V(MetricIsolateCount, IsolateCount, "vm.isolate.count", kCounter)
class Metric {
public:
@@ -102,6 +108,26 @@
};
+// A Metric class that reports the maximum value observed.
+// Initial maximum is kMinInt64.
+class MaxMetric : public Metric {
+ public:
+ MaxMetric();
+
+ void SetValue(int64_t new_value);
+};
+
+
+// A Metric class that reports the minimum value observed.
+// Initial minimum is kMaxInt64.
+class MinMetric : public Metric {
+ public:
+ MinMetric();
+
+ void SetValue(int64_t new_value);
+};
+
+
class MetricHeapOldUsed : public Metric {
protected:
virtual int64_t Value() const;
@@ -144,6 +170,11 @@
};
+class MetricHeapUsed : public Metric {
+ protected:
+ virtual int64_t Value() const;
+};
+
} // namespace dart
#endif // VM_METRICS_H_
diff --git a/runtime/vm/mirrors_api_impl.cc b/runtime/vm/mirrors_api_impl.cc
index 3d83d44..cb3b93f 100644
--- a/runtime/vm/mirrors_api_impl.cc
+++ b/runtime/vm/mirrors_api_impl.cc
@@ -83,7 +83,7 @@
if (obj.IsType()) {
const Class& cls = Class::Handle(Z, Type::Cast(obj).type_class());
- const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(I));
+ const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(T));
if (!error.IsNull()) {
return Api::NewHandle(I, error.raw());
}
diff --git a/runtime/vm/native_entry.h b/runtime/vm/native_entry.h
index 0123b47..25dee39 100644
--- a/runtime/vm/native_entry.h
+++ b/runtime/vm/native_entry.h
@@ -88,7 +88,7 @@
#define GET_NATIVE_ARGUMENT(type, name, value) \
const Instance& __##name##_instance__ = \
Instance::CheckedHandle(zone, value); \
- type& name = type::Handle(isolate); \
+ type& name = type::Handle(zone); \
if (!__##name##_instance__.IsNull()) { \
if (!__##name##_instance__.Is##type()) { \
const Array& __args__ = Array::Handle(Array::New(1)); \
diff --git a/runtime/vm/native_entry_test.cc b/runtime/vm/native_entry_test.cc
index 6d48368..6929913 100644
--- a/runtime/vm/native_entry_test.cc
+++ b/runtime/vm/native_entry_test.cc
@@ -56,7 +56,6 @@
// Arg0-4: 5 smis or null.
// Result: a smi representing the sum of all non-null arguments.
void TestNonNullSmiSum(Dart_NativeArguments args) {
- Isolate* isolate = Isolate::Current(); // Used by GET_NATIVE_ARGUMENT.
int64_t result = 0;
int arg_count = Dart_GetNativeArgumentCount(args);
// Test the lower level macro GET_NATIVE_ARGUMENT.
diff --git a/runtime/vm/native_message_handler.cc b/runtime/vm/native_message_handler.cc
index da869e2..8f8d7a6 100644
--- a/runtime/vm/native_message_handler.cc
+++ b/runtime/vm/native_message_handler.cc
@@ -32,7 +32,8 @@
#endif
-bool NativeMessageHandler::HandleMessage(Message* message) {
+MessageHandler::MessageStatus NativeMessageHandler::HandleMessage(
+ Message* message) {
if (message->IsOOB()) {
// We currently do not use OOB messages for native ports.
UNREACHABLE();
@@ -45,7 +46,7 @@
Dart_CObject* object = reader.ReadMessage();
(*func())(message->dest_port(), object);
delete message;
- return true;
+ return kOK;
}
} // namespace dart
diff --git a/runtime/vm/native_message_handler.h b/runtime/vm/native_message_handler.h
index 777cb7f..9a34c77 100644
--- a/runtime/vm/native_message_handler.h
+++ b/runtime/vm/native_message_handler.h
@@ -21,7 +21,7 @@
const char* name() const { return name_; }
Dart_NativeMessageHandler func() const { return func_; }
- bool HandleMessage(Message* message);
+ MessageStatus HandleMessage(Message* message);
#if defined(DEBUG)
// Check that it is safe to access this handler.
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 11cd82b..87f3f10 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -951,12 +951,14 @@
cls = isolate->object_store()->one_byte_string_class();
cls.set_name(Symbols::OneByteString());
- // Make the VM isolate read-only after setting all objects as marked.
- PremarkingVisitor premarker(isolate);
- isolate->heap()->WriteProtect(false);
- ASSERT(isolate->heap()->UsedInWords(Heap::kNew) == 0);
- isolate->heap()->IterateOldObjects(&premarker);
- isolate->heap()->WriteProtect(true);
+ {
+ ASSERT(isolate == Dart::vm_isolate());
+ WritableVMIsolateScope scope(Thread::Current());
+ PremarkingVisitor premarker(isolate);
+ ASSERT(isolate->heap()->UsedInWords(Heap::kNew) == 0);
+ isolate->heap()->IterateOldObjects(&premarker);
+ // Make the VM isolate read-only again after setting all objects as marked.
+ }
}
@@ -1058,7 +1060,6 @@
RawError* Object::Init(Isolate* isolate) {
Thread* thread = Thread::Current();
ASSERT(isolate == thread->isolate());
- TIMERSCOPE(thread, time_bootstrap);
TimelineDurationScope tds(isolate,
isolate->GetIsolateStream(),
"Object::Init");
@@ -1761,10 +1762,22 @@
intptr_t class_id,
intptr_t size,
bool is_vm_object) {
- uword initial_value = (class_id == kInstructionsCid)
- ? Assembler::GetBreakInstructionFiller() : reinterpret_cast<uword>(null_);
+ const uword break_instruction_value = Assembler::GetBreakInstructionFiller();
+ const uword null_value = reinterpret_cast<uword>(null_);
+ const bool is_instructions = class_id == kInstructionsCid;
+ uword initial_value =
+ is_instructions ? break_instruction_value : null_value;
uword cur = address;
uword end = address + size;
+ if (is_instructions) {
+ // Fill the header with null. The remainder of the Instructions object will
+ // be filled with the break_instruction_value.
+ uword header_end = address + Instructions::HeaderSize();
+ while (cur < header_end) {
+ *reinterpret_cast<uword*>(cur) = null_value;
+ cur += kWordSize;
+ }
+ }
while (cur < end) {
*reinterpret_cast<uword*>(cur) = initial_value;
cur += kWordSize;
@@ -1830,7 +1843,7 @@
}
const Class& cls = Class::Handle(class_table->At(cls_id));
if (cls.TraceAllocation(isolate)) {
- Profiler::RecordAllocation(isolate, cls_id);
+ Profiler::RecordAllocation(thread, cls_id);
}
NoSafepointScope no_safepoint;
InitializeObject(address, cls_id, size, (isolate == Dart::vm_isolate()));
@@ -2197,8 +2210,9 @@
intptr_t Class::FindFunctionIndex(const Function& needle) const {
- Isolate* isolate = Isolate::Current();
- if (EnsureIsFinalized(isolate) != Error::null()) {
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ if (EnsureIsFinalized(thread) != Error::null()) {
return -1;
}
REUSABLE_ARRAY_HANDLESCOPE(isolate);
@@ -2250,8 +2264,9 @@
intptr_t Class::FindImplicitClosureFunctionIndex(const Function& needle) const {
- Isolate* isolate = Isolate::Current();
- if (EnsureIsFinalized(isolate) != Error::null()) {
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ if (EnsureIsFinalized(thread) != Error::null()) {
return -1;
}
REUSABLE_ARRAY_HANDLESCOPE(isolate);
@@ -2281,8 +2296,9 @@
intptr_t Class::FindInvocationDispatcherFunctionIndex(
const Function& needle) const {
- Isolate* isolate = Isolate::Current();
- if (EnsureIsFinalized(isolate) != Error::null()) {
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ if (EnsureIsFinalized(thread) != Error::null()) {
return -1;
}
REUSABLE_ARRAY_HANDLESCOPE(isolate);
@@ -2419,13 +2435,14 @@
}
-intptr_t Class::NumTypeParameters(Isolate* isolate) const {
+intptr_t Class::NumTypeParameters(Thread* thread) const {
if (IsMixinApplication() && !is_mixin_type_applied()) {
ClassFinalizer::ApplyMixinType(*this);
}
if (type_parameters() == TypeArguments::null()) {
return 0;
}
+ Isolate* isolate = thread->isolate();
REUSABLE_TYPE_ARGUMENTS_HANDLESCOPE(isolate);
TypeArguments& type_params = isolate->TypeArgumentsHandle();
type_params = type_parameters();
@@ -3017,16 +3034,17 @@
// Ensure that top level parsing of the class has been done.
// TODO(24109): Migrate interface to Thread*.
-RawError* Class::EnsureIsFinalized(Isolate* isolate) const {
+RawError* Class::EnsureIsFinalized(Thread* thread) const {
// Finalized classes have already been parsed.
if (is_finalized()) {
return Error::null();
}
- ASSERT(isolate != NULL);
- const Error& error = Error::Handle(isolate, Compiler::CompileClass(*this));
+ ASSERT(thread != NULL);
+ const Error& error = Error::Handle(
+ thread->zone(), Compiler::CompileClass(*this));
if (!error.IsNull()) {
- ASSERT(isolate == Thread::Current()->isolate());
- if (Thread::Current()->long_jump_base() != NULL) {
+ ASSERT(thread == Thread::Current());
+ if (thread->long_jump_base() != NULL) {
Report::LongJump(error);
UNREACHABLE();
}
@@ -3074,8 +3092,9 @@
intptr_t Class::FindFieldIndex(const Field& needle) const {
- Isolate* isolate = Isolate::Current();
- if (EnsureIsFinalized(isolate) != Error::null()) {
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ if (EnsureIsFinalized(thread) != Error::null()) {
return -1;
}
REUSABLE_ARRAY_HANDLESCOPE(isolate);
@@ -3688,8 +3707,9 @@
intptr_t Class::FindCanonicalTypeIndex(const Type& needle) const {
- Isolate* isolate = Isolate::Current();
- if (EnsureIsFinalized(isolate) != Error::null()) {
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ if (EnsureIsFinalized(thread) != Error::null()) {
return -1;
}
if (needle.raw() == CanonicalType()) {
@@ -3752,11 +3772,9 @@
if (existing_stub.IsNull()) {
return;
}
- ASSERT(!CodePatcher::IsEntryPatched(existing_stub));
- // Patch the stub so that the next caller will regenerate the stub.
- CodePatcher::PatchEntry(
- existing_stub,
- Code::Handle(StubCode::FixAllocationStubTarget_entry()->code()));
+ ASSERT(!existing_stub.IsDisabled());
+ // Change the stub so that the next caller will regenerate the stub.
+ existing_stub.DisableStubCode();
// Disassociate the existing stub from class.
StorePointer(&raw_ptr()->allocation_stub_, Code::null());
}
@@ -4087,8 +4105,9 @@
RawFunction* Class::LookupFunction(const String& name, MemberKind kind) const {
- Isolate* isolate = Isolate::Current();
- if (EnsureIsFinalized(isolate) != Error::null()) {
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ if (EnsureIsFinalized(thread) != Error::null()) {
return Function::null();
}
REUSABLE_ARRAY_HANDLESCOPE(isolate);
@@ -4134,8 +4153,9 @@
RawFunction* Class::LookupFunctionAllowPrivate(const String& name,
MemberKind kind) const {
- Isolate* isolate = Isolate::Current();
- if (EnsureIsFinalized(isolate) != Error::null()) {
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ if (EnsureIsFinalized(thread) != Error::null()) {
return Function::null();
}
REUSABLE_ARRAY_HANDLESCOPE(isolate);
@@ -4172,8 +4192,9 @@
RawFunction* Class::LookupAccessorFunction(const char* prefix,
intptr_t prefix_length,
const String& name) const {
- Isolate* isolate = Isolate::Current();
- if (EnsureIsFinalized(isolate) != Error::null()) {
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ if (EnsureIsFinalized(thread) != Error::null()) {
return Function::null();
}
REUSABLE_ARRAY_HANDLESCOPE(isolate);
@@ -4200,8 +4221,9 @@
RawFunction* Class::LookupFunctionAtToken(intptr_t token_pos) const {
// TODO(hausner): we can shortcut the negative case if we knew the
// beginning and end token position of the class.
- Isolate* isolate = Isolate::Current();
- if (EnsureIsFinalized(isolate) != Error::null()) {
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ if (EnsureIsFinalized(thread) != Error::null()) {
return Function::null();
}
Function& func = Function::Handle(isolate);
@@ -4239,8 +4261,9 @@
RawField* Class::LookupField(const String& name, MemberKind kind) const {
- Isolate* isolate = Isolate::Current();
- if (EnsureIsFinalized(isolate) != Error::null()) {
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ if (EnsureIsFinalized(thread) != Error::null()) {
return Field::null();
}
REUSABLE_ARRAY_HANDLESCOPE(isolate);
@@ -4313,7 +4336,7 @@
return;
}
- const Error& err = Error::Handle(EnsureIsFinalized(Isolate::Current()));
+ const Error& err = Error::Handle(EnsureIsFinalized(Thread::Current()));
if (!err.IsNull()) {
jsobj.AddProperty("error", err);
}
@@ -5313,9 +5336,7 @@
ToFullyQualifiedCString(),
current_code.EntryPoint());
}
- // Patch entry of the optimized code.
- CodePatcher::PatchEntry(
- current_code, Code::Handle(StubCode::FixCallersTarget_entry()->code()));
+ current_code.DisableDartCode();
const Error& error = Error::Handle(zone,
Compiler::EnsureUnoptimizedCode(thread, *this));
if (!error.IsNull()) {
@@ -5323,7 +5344,7 @@
}
const Code& unopt_code = Code::Handle(zone, unoptimized_code());
AttachCode(unopt_code);
- CodePatcher::RestoreEntry(unopt_code);
+ unopt_code.Enable();
isolate->TrackDeoptimizedCode(current_code);
}
@@ -5853,7 +5874,9 @@
"%" Pd " named passed, at most %" Pd " expected",
num_named_arguments,
NumOptionalNamedParameters());
- *error_message = String::New(message_buffer);
+ // Allocate in old space because it can be invoked in background
+ // optimizing compilation.
+ *error_message = String::New(message_buffer, Heap::kOld);
}
return false; // Too many named arguments.
}
@@ -5873,7 +5896,9 @@
num_opt_pos_params > 0 ? " positional" : "",
num_opt_pos_params > 0 ? "at most " : "",
num_pos_params - num_hidden_params);
- *error_message = String::New(message_buffer);
+ // Allocate in old space because it can be invoked in background
+ // optimizing compilation.
+ *error_message = String::New(message_buffer, Heap::kOld);
}
return false; // Too many fixed and/or positional arguments.
}
@@ -5890,7 +5915,9 @@
num_opt_pos_params > 0 ? " positional" : "",
num_opt_pos_params > 0 ? "at least " : "",
num_fixed_parameters() - num_hidden_params);
- *error_message = String::New(message_buffer);
+ // Allocate in old space because it can be invoked in background
+ // optimizing compilation.
+ *error_message = String::New(message_buffer, Heap::kOld);
}
return false; // Too few fixed and/or positional arguments.
}
@@ -5935,7 +5962,9 @@
kMessageBufferSize,
"no optional formal parameter named '%s'",
argument_name.ToCString());
- *error_message = String::New(message_buffer);
+ // Allocate in old space because it can be invoked in background
+ // optimizing compilation.
+ *error_message = String::New(message_buffer, Heap::kOld);
}
return false;
}
@@ -5981,7 +6010,9 @@
kMessageBufferSize,
"no optional formal parameter named '%s'",
argument_name.ToCString());
- *error_message = String::New(message_buffer);
+ // Allocate in old space because it can be invoked in background
+ // optimizing compilation.
+ *error_message = String::New(message_buffer, Heap::kOld);
}
return false;
}
@@ -7110,7 +7141,7 @@
Class& cls = Class::Handle(Owner());
ASSERT(!cls.IsNull());
Error& err = Error::Handle();
- err ^= cls.EnsureIsFinalized(Isolate::Current());
+ err ^= cls.EnsureIsFinalized(Thread::Current());
ASSERT(err.IsNull());
JSONObject jsobj(stream);
AddCommonObjectProperties(&jsobj, "Function", ref);
@@ -10240,6 +10271,11 @@
}
+RawLibrary* Library::VMServiceLibrary() {
+ return Isolate::Current()->object_store()->vmservice_library();
+}
+
+
const char* Library::ToCString() const {
const String& name = String::Handle(url());
return OS::SCreate(Thread::Current()->zone(),
@@ -10579,7 +10615,7 @@
THR_Print("Prefix '%s': disabling %s code for %s function '%s'\n",
String::Handle(prefix_.name()).ToCString(),
code.is_optimized() ? "optimized" : "unoptimized",
- CodePatcher::IsEntryPatched(code) ? "patched" : "unpatched",
+ code.IsDisabled() ? "'patched'" : "'unpatched'",
Function::Handle(code.function()).ToCString());
}
}
@@ -10833,7 +10869,7 @@
ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
while (it.HasNext()) {
cls = it.GetNextClass();
- error = cls.EnsureIsFinalized(Isolate::Current());
+ error = cls.EnsureIsFinalized(Thread::Current());
if (!error.IsNull()) {
return error.raw();
}
@@ -13285,6 +13321,24 @@
}
+void Code::DisableDartCode() const {
+ ASSERT(IsFunctionCode());
+ ASSERT(instructions() == active_instructions());
+ const Code& new_code =
+ Code::Handle(StubCode::FixCallersTarget_entry()->code());
+ set_active_instructions(new_code.instructions());
+}
+
+
+void Code::DisableStubCode() const {
+ASSERT(IsAllocationStubCode());
+ ASSERT(instructions() == active_instructions());
+ const Code& new_code =
+ Code::Handle(StubCode::FixAllocationStubTarget_entry()->code());
+ set_active_instructions(new_code.instructions());
+}
+
+
void Code::PrintJSONImpl(JSONStream* stream, bool ref) const {
JSONObject jsobj(stream);
AddCommonObjectProperties(&jsobj, "Code", ref);
@@ -14261,9 +14315,10 @@
space);
NoSafepointScope no_safepoint;
result ^= raw;
- result.StoreNonPointer(&result.raw_ptr()->is_user_initiated_, false);
}
result.set_message(message);
+ result.set_is_user_initiated(false);
+ result.set_is_vm_restart(false);
return result.raw();
}
@@ -14278,6 +14333,11 @@
}
+void UnwindError::set_is_vm_restart(bool value) const {
+ StoreNonPointer(&raw_ptr()->is_vm_restart_, value);
+}
+
+
const char* UnwindError::ToErrorCString() const {
const String& msg_str = String::Handle(message());
return msg_str.ToCString();
@@ -14295,6 +14355,8 @@
jsobj.AddProperty("kind", "TerminationError");
jsobj.AddServiceId(*this);
jsobj.AddProperty("message", ToErrorCString());
+ jsobj.AddProperty("_is_user_initiated", is_user_initiated());
+ jsobj.AddProperty("_is_vm_restart", is_vm_restart());
}
@@ -14418,9 +14480,12 @@
if (!CheckAndCanonicalizeFields(error_str)) {
return Instance::null();
}
- Instance& result = Instance::Handle();
- const Class& cls = Class::Handle(this->clazz());
- Array& constants = Array::Handle(cls.constants());
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ Isolate* isolate = thread->isolate();
+ Instance& result = Instance::Handle(zone);
+ const Class& cls = Class::Handle(zone, this->clazz());
+ Array& constants = Array::Handle(zone, cls.constants());
const intptr_t constants_len = constants.Length();
// Linear search to see whether this value is already present in the
// list of canonicalized constants.
@@ -14439,7 +14504,23 @@
// The value needs to be added to the list. Grow the list if
// it is full.
result ^= this->raw();
- if (result.IsNew()) {
+ if (result.IsNew() ||
+ (result.InVMHeap() && (isolate != Dart::vm_isolate()))) {
+ /**
+ * When a snapshot is generated on a 64 bit architecture and then read
+ * into a 32 bit architecture, values which are Smi on the 64 bit
+ * architecture could potentially be converted to Mint objects, however
+ * since Smi values do not have any notion of canonical bits we lose
+ * that information when the object becomes a Mint.
+ * Some of these values could be literal values and end up in the
+ * VM isolate heap. Later when these values are referenced in a
+ * constant list we try to ensure that all the objects in the list
+ * are canonical and try to canonicalize them. When these Mint objects
+ * are encountered they do not have the canonical bit set and
+ * canonicalizing them won't work as the VM heap is read only now.
+ * In these cases we clone the object into the isolate and then
+ * canonicalize it.
+ */
// Create a canonical object in old space.
result ^= Object::Clone(result, Heap::kOld);
}
@@ -14503,8 +14584,7 @@
}
Isolate* isolate = Isolate::Current();
const Class& cls = Class::Handle(isolate, clazz());
- TypeArguments& type_arguments =
- TypeArguments::Handle(isolate);
+ TypeArguments& type_arguments = TypeArguments::Handle(isolate);
if (cls.NumTypeArguments() > 0) {
type_arguments = GetTypeArguments();
ASSERT(type_arguments.IsNull() || type_arguments.IsCanonical());
@@ -14630,8 +14710,8 @@
RawInstance* Instance::New(const Class& cls, Heap::Space space) {
- Isolate* isolate = Isolate::Current();
- if (cls.EnsureIsFinalized(isolate) != Error::null()) {
+ Thread* thread = Thread::Current();
+ if (cls.EnsureIsFinalized(thread) != Error::null()) {
return Instance::null();
}
intptr_t instance_size = cls.instance_size();
@@ -15611,18 +15691,19 @@
if (arguments() == other_type.arguments()) {
return true;
}
- Isolate* isolate = Isolate::Current();
- const Class& cls = Class::Handle(isolate, type_class());
- const intptr_t num_type_params = cls.NumTypeParameters(isolate);
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ const Class& cls = Class::Handle(zone, type_class());
+ const intptr_t num_type_params = cls.NumTypeParameters(thread);
if (num_type_params == 0) {
// Shortcut unnecessary handle allocation below.
return true;
}
const intptr_t num_type_args = cls.NumTypeArguments();
const intptr_t from_index = num_type_args - num_type_params;
- const TypeArguments& type_args = TypeArguments::Handle(isolate, arguments());
+ const TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
const TypeArguments& other_type_args = TypeArguments::Handle(
- isolate, other_type.arguments());
+ zone, other_type.arguments());
if (type_args.IsNull()) {
// Ignore from_index.
return other_type_args.IsRaw(0, num_type_args);
@@ -15642,8 +15723,8 @@
// depend solely on the type parameters that were just verified to match.
ASSERT(type_args.Length() >= (from_index + num_type_params));
ASSERT(other_type_args.Length() >= (from_index + num_type_params));
- AbstractType& type_arg = AbstractType::Handle(isolate);
- AbstractType& other_type_arg = AbstractType::Handle(isolate);
+ AbstractType& type_arg = AbstractType::Handle(zone);
+ AbstractType& other_type_arg = AbstractType::Handle(zone);
for (intptr_t i = 0; i < from_index; i++) {
type_arg = type_args.TypeAt(i);
other_type_arg = other_type_args.TypeAt(i);
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 934697e..6a7076a 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -854,10 +854,10 @@
return Handle(I->current_zone(), raw_ptr);
}
static PassiveObject& Handle(RawObject* raw_ptr) {
- return Handle(Isolate::Current(), raw_ptr);
+ return Handle(Thread::Current()->zone(), raw_ptr);
}
static PassiveObject& Handle() {
- return Handle(Isolate::Current(), Object::null());
+ return Handle(Thread::Current()->zone(), Object::null());
}
static PassiveObject& Handle(Zone* zone) {
return Handle(zone, Object::null());
@@ -993,9 +993,9 @@
return raw_ptr()->type_parameters_;
}
void set_type_parameters(const TypeArguments& value) const;
- intptr_t NumTypeParameters(Isolate* isolate) const;
+ intptr_t NumTypeParameters(Thread* thread) const;
intptr_t NumTypeParameters() const {
- return NumTypeParameters(Isolate::Current());
+ return NumTypeParameters(Thread::Current());
}
static intptr_t type_parameters_offset() {
return OFFSET_OF(RawClass, type_parameters_);
@@ -1331,7 +1331,7 @@
const Array& param_names,
const Array& param_values) const;
- RawError* EnsureIsFinalized(Isolate* isolate) const;
+ RawError* EnsureIsFinalized(Thread* thread) const;
// Allocate a class used for VM internal objects.
template <class FakeObject> static RawClass* New();
@@ -3491,6 +3491,7 @@
static RawLibrary* NativeWrappersLibrary();
static RawLibrary* ProfilerLibrary();
static RawLibrary* TypedDataLibrary();
+ static RawLibrary* VMServiceLibrary();
// Eagerly compile all classes and functions in the library.
static RawError* CompileAll();
@@ -4353,6 +4354,20 @@
bool IsStubCode() const;
bool IsFunctionCode() const;
+ void DisableDartCode() const;
+
+ void DisableStubCode() const;
+
+ void Enable() const {
+ if (!IsDisabled()) return;
+ ASSERT(instructions() != active_instructions());
+ set_active_instructions(instructions());
+ }
+
+ bool IsDisabled() const {
+ return instructions() != active_instructions();
+ }
+
private:
void set_state_bits(intptr_t bits) const;
@@ -4813,6 +4828,9 @@
bool is_user_initiated() const { return raw_ptr()->is_user_initiated_; }
void set_is_user_initiated(bool value) const;
+ bool is_vm_restart() const { return raw_ptr()->is_vm_restart_; }
+ void set_is_vm_restart(bool value) const;
+
RawString* message() const { return raw_ptr()->message_; }
static intptr_t InstanceSize() {
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 8c32a4a..88c77eb 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -71,6 +71,7 @@
profiler_library_(Library::null()),
root_library_(Library::null()),
typed_data_library_(Library::null()),
+ vmservice_library_(Library::null()),
libraries_(GrowableObjectArray::null()),
pending_classes_(GrowableObjectArray::null()),
pending_functions_(GrowableObjectArray::null()),
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index fda986d..805b9b1 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -32,6 +32,7 @@
kMirrors,
kProfiler,
kTypedData,
+ kVMService,
};
~ObjectStore();
@@ -265,6 +266,7 @@
RawLibrary* mirrors_library() const { return mirrors_library_; }
RawLibrary* profiler_library() const { return profiler_library_; }
RawLibrary* typed_data_library() const { return typed_data_library_; }
+ RawLibrary* vmservice_library() const { return vmservice_library_; }
void set_bootstrap_library(BootstrapLibraryId index, const Library& value) {
switch (index) {
@@ -301,6 +303,9 @@
case kTypedData:
typed_data_library_ = value.raw();
break;
+ case kVMService:
+ vmservice_library_ = value.raw();
+ break;
default:
UNREACHABLE();
}
@@ -520,6 +525,7 @@
RawLibrary* profiler_library_;
RawLibrary* root_library_;
RawLibrary* typed_data_library_;
+ RawLibrary* vmservice_library_;
RawGrowableObjectArray* libraries_;
RawGrowableObjectArray* pending_classes_;
RawGrowableObjectArray* pending_functions_;
diff --git a/runtime/vm/os_macos.cc b/runtime/vm/os_macos.cc
index 9821221..a447e41 100644
--- a/runtime/vm/os_macos.cc
+++ b/runtime/vm/os_macos.cc
@@ -15,6 +15,9 @@
#include <sys/time.h> // NOLINT
#include <sys/resource.h> // NOLINT
#include <unistd.h> // NOLINT
+#if defined(TARGET_OS_IOS)
+#include <sys/sysctl.h>
+#endif
#include "platform/utils.h"
#include "vm/isolate.h"
@@ -91,7 +94,7 @@
struct timeval boottime;
int mib[2] = {CTL_KERN, KERN_BOOTTIME};
size_t size = sizeof(boottime);
- int kr = sysctl(mib, arraysize(mib), &boottime, &size, NULL, 0);
+ int kr = sysctl(mib, sizeof(mib) / sizeof(mib[0]), &boottime, &size, NULL, 0);
ASSERT(KERN_SUCCESS == kr);
int64_t now = GetCurrentTimeMicros();
int64_t origin = boottime.tv_sec * kMicrosecondsPerSecond;
diff --git a/runtime/vm/pages.cc b/runtime/vm/pages.cc
index b8341e4..da7ec80 100644
--- a/runtime/vm/pages.cc
+++ b/runtime/vm/pages.cc
@@ -136,7 +136,6 @@
prot = VirtualMemory::kReadOnly;
}
} else {
- // TODO(23217): Should this really make all pages non-executable?
prot = VirtualMemory::kReadWrite;
}
bool status = memory_->Protect(prot);
@@ -170,6 +169,9 @@
FLAG_old_gen_growth_time_ratio),
gc_time_micros_(0),
collections_(0) {
+ // We aren't holding the lock but no one can reference us yet.
+ UpdateMaxCapacityLocked();
+ UpdateMaxUsed();
}
@@ -533,6 +535,32 @@
}
+void PageSpace::UpdateMaxCapacityLocked() {
+ if (heap_ == NULL) {
+ // Some unit tests.
+ return;
+ }
+ ASSERT(heap_ != NULL);
+ ASSERT(heap_->isolate() != NULL);
+ Isolate* isolate = heap_->isolate();
+ isolate->GetHeapOldCapacityMaxMetric()->SetValue(
+ static_cast<int64_t>(usage_.capacity_in_words) * kWordSize);
+}
+
+
+void PageSpace::UpdateMaxUsed() {
+ if (heap_ == NULL) {
+ // Some unit tests.
+ return;
+ }
+ ASSERT(heap_ != NULL);
+ ASSERT(heap_->isolate() != NULL);
+ Isolate* isolate = heap_->isolate();
+ isolate->GetHeapOldUsedMaxMetric()->SetValue(
+ UsedInWords() * kWordSize);
+}
+
+
bool PageSpace::Contains(uword addr) const {
for (ExclusivePageIterator it(this); !it.Done(); it.Advance()) {
if (it.page()->Contains(addr)) {
@@ -648,9 +676,9 @@
space.AddProperty("name", "old");
space.AddProperty("vmName", "PageSpace");
space.AddProperty("collections", collections());
- space.AddProperty("used", UsedInWords() * kWordSize);
- space.AddProperty("capacity", CapacityInWords() * kWordSize);
- space.AddProperty("external", ExternalInWords() * kWordSize);
+ space.AddProperty64("used", UsedInWords() * kWordSize);
+ space.AddProperty64("capacity", CapacityInWords() * kWordSize);
+ space.AddProperty64("external", ExternalInWords() * kWordSize);
space.AddProperty("time", MicrosecondsToSeconds(gc_time_micros()));
if (collections() > 0) {
int64_t run_time = OS::GetCurrentTimeMicros() - isolate->start_time();
@@ -918,6 +946,11 @@
freelist_[HeapPage::kExecutable].Print();
}
+ UpdateMaxUsed();
+ if (heap_ != NULL) {
+ heap_->UpdateGlobalMaxUsed();
+ }
+
isolate->thread_registry()->ResumeAllThreads();
// Done, reset the task count.
diff --git a/runtime/vm/pages.h b/runtime/vm/pages.h
index e67bc81..39ef84e 100644
--- a/runtime/vm/pages.h
+++ b/runtime/vm/pages.h
@@ -218,8 +218,8 @@
NeedsExternalGC();
}
- intptr_t UsedInWords() const { return usage_.used_in_words; }
- intptr_t CapacityInWords() const {
+ int64_t UsedInWords() const { return usage_.used_in_words; }
+ int64_t CapacityInWords() const {
MutexLocker ml(pages_lock_);
return usage_.capacity_in_words;
}
@@ -230,8 +230,13 @@
void IncreaseCapacityInWordsLocked(intptr_t increase_in_words) {
DEBUG_ASSERT(pages_lock_->IsOwnedByCurrentThread());
usage_.capacity_in_words += increase_in_words;
+ UpdateMaxCapacityLocked();
}
- intptr_t ExternalInWords() const {
+
+ void UpdateMaxCapacityLocked();
+ void UpdateMaxUsed();
+
+ int64_t ExternalInWords() const {
return usage_.external_in_words;
}
SpaceUsage GetCurrentUsage() const {
@@ -277,7 +282,8 @@
(ExternalInWords() > max_external_in_words_);
}
- // TODO(koda): Unify protection handling.
+ // Note: Code pages are made executable/non-executable when 'read_only' is
+ // true/false, respectively.
void WriteProtect(bool read_only);
void WriteProtectCode(bool read_only);
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index a84b79e..a33c4cc 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -44,7 +44,6 @@
DEFINE_FLAG(bool, load_deferred_eagerly, false,
"Load deferred libraries eagerly.");
DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations.");
-DEFINE_FLAG(bool, supermixin, false, "Allow super calls in mixins.");
DEFINE_FLAG(bool, warn_mixin_typedef, true, "Warning on legacy mixin typedef.");
DEFINE_FLAG(bool, link_natives_lazily, false, "Link native calls lazily");
@@ -11982,10 +11981,7 @@
ASSERT(!func.IsNull());
ASSERT(func.kind() == RawFunction::kImplicitStaticFinalGetter);
Object& const_value = Object::Handle(Z);
- {
- PAUSETIMERSCOPE(T, time_compilation);
- const_value = DartEntry::InvokeFunction(func, Object::empty_array());
- }
+ const_value = DartEntry::InvokeFunction(func, Object::empty_array());
if (const_value.IsError()) {
const Error& error = Error::Cast(const_value);
if (error.IsUnhandledException()) {
@@ -12064,11 +12060,7 @@
const Array& args_descriptor = Array::Handle(Z,
ArgumentsDescriptor::New(num_arguments, arguments->names()));
Object& result = Object::Handle(Z);
- {
- PAUSETIMERSCOPE(T, time_compilation);
- result = DartEntry::InvokeFunction(
- constructor, arg_values, args_descriptor);
- }
+ result = DartEntry::InvokeFunction(constructor, arg_values, args_descriptor);
if (result.IsError()) {
// An exception may not occur in every parse attempt, i.e., the
// generated AST is not deterministic. Therefore mark the function as
@@ -13559,10 +13551,7 @@
// Call interpolation function.
Object& result = Object::Handle(Z);
- {
- PAUSETIMERSCOPE(T, time_compilation);
- result = DartEntry::InvokeFunction(func, interpolate_arg);
- }
+ result = DartEntry::InvokeFunction(func, interpolate_arg);
if (result.IsUnhandledException()) {
ReportError("%s", Error::Cast(result).ToErrorCString());
}
@@ -13853,16 +13842,6 @@
ReportError("class '%s' does not have a superclass",
String::Handle(Z, current_class().Name()).ToCString());
}
- if (!FLAG_supermixin) {
- if (current_class().IsMixinApplication()) {
- const Type& mixin_type = Type::Handle(Z, current_class().mixin());
- if (mixin_type.type_class() == current_function().origin()) {
- ReportError("method of mixin class '%s' may not refer to 'super'",
- String::Handle(Z, Class::Handle(Z,
- current_function().origin()).Name()).ToCString());
- }
- }
- }
const intptr_t super_pos = TokenPos();
ConsumeToken();
if (CurrentToken() == Token::kPERIOD) {
diff --git a/runtime/vm/port_test.cc b/runtime/vm/port_test.cc
index 34272d1..165d19c 100644
--- a/runtime/vm/port_test.cc
+++ b/runtime/vm/port_test.cc
@@ -38,7 +38,7 @@
notify_count++;
}
- bool HandleMessage(Message* message) { return true; }
+ MessageStatus HandleMessage(Message* message) { return kOK; }
int notify_count;
};
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index b40f5fa..b08183f 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -4,6 +4,7 @@
#include "vm/precompiler.h"
+#include "vm/code_patcher.h"
#include "vm/compiler.h"
#include "vm/isolate.h"
#include "vm/log.h"
@@ -29,10 +30,11 @@
RawError* Precompiler::CompileAll(
- Dart_QualifiedFunctionName embedder_entry_points[]) {
+ Dart_QualifiedFunctionName embedder_entry_points[],
+ bool reset_fields) {
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
- Precompiler precompiler(Thread::Current());
+ Precompiler precompiler(Thread::Current(), reset_fields);
precompiler.DoCompileAll(embedder_entry_points);
return Error::null();
} else {
@@ -44,10 +46,11 @@
}
-Precompiler::Precompiler(Thread* thread) :
+Precompiler::Precompiler(Thread* thread, bool reset_fields) :
thread_(thread),
zone_(thread->zone()),
isolate_(thread->isolate()),
+ reset_fields_(reset_fields),
changed_(false),
function_count_(0),
class_count_(0),
@@ -104,7 +107,7 @@
ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
while (it.HasNext()) {
cls = it.GetNextClass();
- error_ = cls.EnsureIsFinalized(I);
+ error_ = cls.EnsureIsFinalized(thread_);
if (!error_.IsNull()) {
Jump(error_);
}
@@ -326,6 +329,8 @@
DropUncompiledFunctions();
// TODO(rmacnak): DropEmptyClasses();
+
+ BindStaticCalls();
}
@@ -443,6 +448,12 @@
AddClass(cls);
if (field.has_initializer()) {
+ // Should not be in the middle of initialization while precompiling.
+ ASSERT(value.raw() != Object::transition_sentinel().raw());
+
+ const bool is_initialized = value.raw() != Object::sentinel().raw();
+ if (is_initialized && !reset_fields_) return;
+
if (field.HasPrecompiledInitializer()) return;
if (FLAG_trace_precompiler) {
@@ -683,4 +694,74 @@
}
}
+
+void Precompiler::BindStaticCalls() {
+ Library& lib = Library::Handle(Z);
+ Class& cls = Class::Handle(Z);
+ Array& functions = Array::Handle(Z);
+ Function& function = Function::Handle(Z);
+ GrowableObjectArray& closures = GrowableObjectArray::Handle(Z);
+
+ for (intptr_t i = 0; i < libraries_.Length(); i++) {
+ lib ^= libraries_.At(i);
+ ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
+ while (it.HasNext()) {
+ cls = it.GetNextClass();
+ if (cls.IsDynamicClass()) {
+ continue; // class 'dynamic' is in the read-only VM isolate.
+ }
+
+ functions = cls.functions();
+ for (intptr_t j = 0; j < functions.Length(); j++) {
+ function ^= functions.At(j);
+ BindStaticCalls(function);
+ }
+
+ closures = cls.closures();
+ if (!closures.IsNull()) {
+ for (intptr_t j = 0; j < closures.Length(); j++) {
+ function ^= closures.At(j);
+ BindStaticCalls(function);
+ }
+ }
+ }
+ }
+}
+
+
+void Precompiler::BindStaticCalls(const Function& function) {
+ ASSERT(function.HasCode());
+
+ const Code& code = Code::Handle(Z, function.CurrentCode());
+
+ const Array& table = Array::Handle(Z, code.static_calls_target_table());
+ Smi& pc_offset = Smi::Handle(Z);
+ Function& target = Function::Handle(Z);
+ Code& target_code = Code::Handle(Z);
+
+ for (intptr_t i = 0; i < table.Length(); i += Code::kSCallTableEntryLength) {
+ pc_offset ^= table.At(i + Code::kSCallTableOffsetEntry);
+ target ^= table.At(i + Code::kSCallTableFunctionEntry);
+ if (target.IsNull()) {
+ target_code ^= table.At(i + Code::kSCallTableCodeEntry);
+ ASSERT(!target_code.IsNull());
+ ASSERT(!target_code.IsFunctionCode());
+ // Allocation stub or AllocateContext or AllocateArray or ...
+ } else {
+ // Static calls initially call the CallStaticFunction stub because
+ // their target might not be compiled yet. After tree shaking, all
+ // static call targets are compiled.
+ // Cf. runtime entry PatchStaticCall called from CallStaticFunction stub.
+ ASSERT(target.HasCode());
+ target_code ^= target.CurrentCode();
+ CodePatcher::PatchStaticCallAt(pc_offset.Value() + code.EntryPoint(),
+ code, target_code);
+ }
+ }
+
+ // We won't patch static calls anymore, so drop the static call table to save
+ // space.
+ code.set_static_calls_target_table(Object::empty_array());
+}
+
} // namespace dart
diff --git a/runtime/vm/precompiler.h b/runtime/vm/precompiler.h
index 1692eda..3106984 100644
--- a/runtime/vm/precompiler.h
+++ b/runtime/vm/precompiler.h
@@ -79,10 +79,11 @@
class Precompiler : public ValueObject {
public:
static RawError* CompileAll(
- Dart_QualifiedFunctionName embedder_entry_points[]);
+ Dart_QualifiedFunctionName embedder_entry_points[],
+ bool reset_fields);
private:
- explicit Precompiler(Thread* thread);
+ Precompiler(Thread* thread, bool reset_fields);
void DoCompileAll(Dart_QualifiedFunctionName embedder_entry_points[]);
void ClearAllCode();
@@ -103,6 +104,8 @@
void CheckForNewDynamicFunctions();
void DropUncompiledFunctions();
+ void BindStaticCalls();
+ void BindStaticCalls(const Function& function);
Thread* thread() const { return thread_; }
Zone* zone() const { return zone_; }
@@ -112,6 +115,8 @@
Zone* zone_;
Isolate* isolate_;
+ const bool reset_fields_;
+
bool changed_;
intptr_t function_count_;
intptr_t class_count_;
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 98fd63d..079b350 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -165,7 +165,7 @@
return;
}
Thread* thread = Thread::Current();
- thread->SetThreadInterrupter(RecordSampleInterruptCallback, isolate);
+ thread->SetThreadInterrupter(RecordSampleInterruptCallback, thread);
ThreadInterrupter::WakeUp();
}
@@ -850,33 +850,35 @@
}
-// Is |isolate| executing Dart code?
-static bool ExecutingDart(Isolate* isolate) {
- ASSERT(isolate != NULL);
- return (isolate->top_exit_frame_info() == 0) &&
- (isolate->vm_tag() == VMTag::kDartTagId);
+// Is |thread| executing Dart code?
+static bool ExecutingDart(Thread* thread) {
+ ASSERT(thread != NULL);
+ return (thread->top_exit_frame_info() == 0) &&
+ (thread->vm_tag() == VMTag::kDartTagId);
}
-// Has |isolate| exited Dart code?
-static bool ExitedDart(Isolate* isolate) {
- return (isolate->top_exit_frame_info() != 0) &&
- (isolate->vm_tag() != VMTag::kDartTagId);
+// Has |thread| exited Dart code?
+static bool ExitedDart(Thread* thread) {
+ return (thread->top_exit_frame_info() != 0) &&
+ (thread->vm_tag() != VMTag::kDartTagId);
}
// Get |isolate|'s stack boundary and verify that |sp| and |fp| are within
// it. Return |false| if anything looks suspicious.
-static bool GetAndValidateIsolateStackBounds(Isolate* isolate,
+static bool GetAndValidateIsolateStackBounds(Thread* thread,
uintptr_t sp,
uintptr_t fp,
uword* stack_lower,
uword* stack_upper) {
+ ASSERT(thread != NULL);
+ Isolate* isolate = thread->isolate();
ASSERT(isolate != NULL);
ASSERT(stack_lower != NULL);
ASSERT(stack_upper != NULL);
#if defined(USING_SIMULATOR)
- const bool in_dart_code = ExecutingDart(isolate);
+ const bool in_dart_code = ExecutingDart(thread);
if (in_dart_code) {
Simulator* simulator = isolate->simulator();
*stack_lower = simulator->StackBase();
@@ -948,14 +950,15 @@
}
-static Sample* SetupSample(Isolate* isolate,
+static Sample* SetupSample(Thread* thread,
SampleBuffer* sample_buffer,
ThreadId tid) {
- ASSERT(isolate != NULL);
+ ASSERT(thread != NULL);
+ Isolate* isolate = thread->isolate();
ASSERT(sample_buffer != NULL);
Sample* sample = sample_buffer->ReserveSample();
sample->Init(isolate, OS::GetCurrentTimeMicros(), tid);
- uword vm_tag = isolate->vm_tag();
+ uword vm_tag = thread->vm_tag();
#if defined(USING_SIMULATOR)
// When running in the simulator, the runtime entry function address
// (stored as the vm tag) is the address of a redirect function.
@@ -993,12 +996,14 @@
}
#endif
-void Profiler::RecordAllocation(Isolate* isolate, intptr_t cid) {
+void Profiler::RecordAllocation(Thread* thread, intptr_t cid) {
+ ASSERT(thread != NULL);
+ Isolate* isolate = thread->isolate();
if (!CheckIsolate(isolate)) {
return;
}
- const bool exited_dart_code = ExitedDart(isolate);
+ const bool exited_dart_code = ExitedDart(thread);
SampleBuffer* sample_buffer = GetSampleBuffer(isolate);
if (sample_buffer == NULL) {
@@ -1020,7 +1025,7 @@
return;
}
- if (!GetAndValidateIsolateStackBounds(isolate,
+ if (!GetAndValidateIsolateStackBounds(thread,
sp,
fp,
&stack_lower,
@@ -1029,7 +1034,7 @@
return;
}
- Sample* sample = SetupSample(isolate,
+ Sample* sample = SetupSample(thread,
sample_buffer,
OSThread::GetCurrentThreadId());
sample->SetAllocationCid(cid);
@@ -1043,7 +1048,7 @@
sp);
native_stack_walker.walk();
} else if (exited_dart_code) {
- Sample* sample = SetupSample(isolate,
+ Sample* sample = SetupSample(thread,
sample_buffer,
OSThread::GetCurrentThreadId());
sample->SetAllocationCid(cid);
@@ -1054,7 +1059,7 @@
} else {
// Fall back.
uintptr_t pc = GetProgramCounter();
- Sample* sample = SetupSample(isolate,
+ Sample* sample = SetupSample(thread,
sample_buffer,
OSThread::GetCurrentThreadId());
sample->SetAllocationCid(cid);
@@ -1067,7 +1072,8 @@
void Profiler::RecordSampleInterruptCallback(
const InterruptedThreadState& state,
void* data) {
- Isolate* isolate = reinterpret_cast<Isolate*>(data);
+ Thread* thread = reinterpret_cast<Thread*>(data);
+ Isolate* isolate = thread->isolate();
if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) {
// No isolate.
return;
@@ -1080,8 +1086,8 @@
return;
}
- const bool exited_dart_code = ExitedDart(isolate);
- const bool in_dart_code = ExecutingDart(isolate);
+ const bool exited_dart_code = ExitedDart(thread);
+ const bool in_dart_code = ExecutingDart(thread);
uintptr_t sp = 0;
uintptr_t fp = state.fp;
@@ -1118,7 +1124,7 @@
uword stack_lower = 0;
uword stack_upper = 0;
- if (!GetAndValidateIsolateStackBounds(isolate,
+ if (!GetAndValidateIsolateStackBounds(thread,
sp,
fp,
&stack_lower,
@@ -1131,7 +1137,7 @@
// know that our initial stack and frame pointers are within the boundary.
// Setup sample.
- Sample* sample = SetupSample(isolate,
+ Sample* sample = SetupSample(thread,
sample_buffer,
OSThread::GetCurrentThreadId());
// Increment counter for vm tag.
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index fc5ecae..3f32901 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -44,7 +44,7 @@
return sample_buffer_;
}
- static void RecordAllocation(Isolate* isolate, intptr_t cid);
+ static void RecordAllocation(Thread* thread, intptr_t cid);
private:
static bool initialized_;
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index b6f14f0..288584a 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -1471,6 +1471,7 @@
return reinterpret_cast<RawObject**>(&ptr()->message_);
}
bool is_user_initiated_;
+ bool is_vm_restart_;
};
@@ -1612,11 +1613,12 @@
class RawMint : public RawInteger {
RAW_HEAP_OBJECT_IMPLEMENTATION(Mint);
- int64_t value_;
+ ALIGN8 int64_t value_;
friend class Api;
friend class SnapshotReader;
};
+COMPILE_ASSERT(sizeof(RawMint) == 16);
class RawBigint : public RawInteger {
@@ -1633,11 +1635,12 @@
class RawDouble : public RawNumber {
RAW_HEAP_OBJECT_IMPLEMENTATION(Double);
- double value_;
+ ALIGN8 double value_;
friend class Api;
friend class SnapshotReader;
};
+COMPILE_ASSERT(sizeof(RawDouble) == 16);
class RawString : public RawInstance {
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index d3ec50e..aa2d0d0 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -1306,14 +1306,18 @@
intptr_t length = reader->Read<intptr_t>();
- ObjectPool& result =
- ObjectPool::ZoneHandle(reader->zone(),
- NEW_OBJECT_WITH_LEN(ObjectPool, length));
- reader->AddBackRef(object_id, &result, kIsDeserialized);
+ ObjectPool* result =
+ reinterpret_cast<ObjectPool*>(reader->GetBackRef(object_id));
+ if (result == NULL) {
+ result =
+ &(ObjectPool::ZoneHandle(reader->zone(),
+ NEW_OBJECT_WITH_LEN(ObjectPool, length)));
+ reader->AddBackRef(object_id, result, kIsDeserialized);
+ }
const TypedData& info_array =
TypedData::Handle(reader->NewTypedData(kTypedDataInt8ArrayCid, length));
- result.set_info_array(info_array);
+ result->set_info_array(info_array);
NoSafepointScope no_safepoint;
for (intptr_t i = 0; i < length; i++) {
@@ -1323,19 +1327,19 @@
switch (entry_type) {
case ObjectPool::kTaggedObject: {
(*reader->PassiveObjectHandle()) =
- reader->ReadObjectImpl(kAsInlinedObject);
- result.SetObjectAt(i, *(reader->PassiveObjectHandle()));
+ reader->ReadObjectImpl(kAsReference);
+ result->SetObjectAt(i, *(reader->PassiveObjectHandle()));
break;
}
case ObjectPool::kImmediate: {
intptr_t raw_value = reader->Read<intptr_t>();
- result.SetRawValueAt(i, raw_value);
+ result->SetRawValueAt(i, raw_value);
break;
}
case ObjectPool::kNativeEntry: {
// Read nothing. Initialize with the lazy link entry.
uword new_entry = NativeEntry::LinkNativeCallEntry();
- result.SetRawValueAt(i, static_cast<intptr_t>(new_entry));
+ result->SetRawValueAt(i, static_cast<intptr_t>(new_entry));
break;
}
default:
@@ -1343,7 +1347,7 @@
}
}
- return result.raw();
+ return result->raw();
}
@@ -1372,7 +1376,14 @@
Entry& entry = ptr()->data()[i];
switch (entry_type) {
case ObjectPool::kTaggedObject: {
- writer->WriteObjectImpl(entry.raw_obj_, kAsInlinedObject);
+ if (entry.raw_obj_ == StubCode::CallNativeCFunction_entry()->code()) {
+ // Natives can run while precompiling, becoming linked and switching
+ // their stub. Reset to the initial stub used for lazy-linking.
+ writer->WriteObjectImpl(
+ StubCode::CallBootstrapCFunction_entry()->code(), kAsReference);
+ } else {
+ writer->WriteObjectImpl(entry.raw_obj_, kAsReference);
+ }
break;
}
case ObjectPool::kImmediate: {
@@ -1720,7 +1731,7 @@
// Set all the object fields.
READ_OBJECT_FIELDS(result,
result.raw()->from(), result.raw()->to(),
- kAsInlinedObject);
+ kAsReference);
return result.raw();
}
@@ -1743,7 +1754,7 @@
writer->Write<uint32_t>(ptr()->state_bits_);
// Write out all the object pointer fields.
- SnapshotWriterVisitor visitor(writer, kAsInlinedObject);
+ SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
}
diff --git a/runtime/vm/scavenger.cc b/runtime/vm/scavenger.cc
index e223803..f526af1 100644
--- a/runtime/vm/scavenger.cc
+++ b/runtime/vm/scavenger.cc
@@ -415,13 +415,18 @@
if (to_ == NULL) {
FATAL("Out of memory.\n");
}
-
// Setup local fields.
top_ = FirstObjectStart();
resolved_top_ = top_;
end_ = to_->end();
survivor_end_ = FirstObjectStart();
+
+ UpdateMaxHeapCapacity();
+ UpdateMaxHeapUsage();
+ if (heap_ != NULL) {
+ heap_->UpdateGlobalMaxUsed();
+ }
}
@@ -459,6 +464,7 @@
// isolate to finish scavenge, etc.).
FATAL("Out of memory.\n");
}
+ UpdateMaxHeapCapacity();
top_ = FirstObjectStart();
resolved_top_ = top_;
end_ = to_->end();
@@ -500,6 +506,10 @@
}
#endif // defined(DEBUG)
from->Delete();
+ UpdateMaxHeapUsage();
+ if (heap_ != NULL) {
+ heap_->UpdateGlobalMaxUsed();
+ }
if (invoke_api_callbacks && (isolate->gc_epilogue_callback() != NULL)) {
(isolate->gc_epilogue_callback())();
}
@@ -705,6 +715,33 @@
}
+void Scavenger::UpdateMaxHeapCapacity() {
+ if (heap_ == NULL) {
+ // Some unit tests.
+ return;
+ }
+ ASSERT(to_ != NULL);
+ ASSERT(heap_ != NULL);
+ Isolate* isolate = heap_->isolate();
+ ASSERT(isolate != NULL);
+ isolate->GetHeapNewCapacityMaxMetric()->SetValue(
+ to_->size_in_words() * kWordSize);
+}
+
+
+void Scavenger::UpdateMaxHeapUsage() {
+ if (heap_ == NULL) {
+ // Some unit tests.
+ return;
+ }
+ ASSERT(to_ != NULL);
+ ASSERT(heap_ != NULL);
+ Isolate* isolate = heap_->isolate();
+ ASSERT(isolate != NULL);
+ isolate->GetHeapNewUsedMaxMetric()->SetValue(UsedInWords() * kWordSize);
+}
+
+
uword Scavenger::ProcessWeakProperty(RawWeakProperty* raw_weak,
ScavengerVisitor* visitor) {
// The fate of the weak property is determined by its key.
@@ -901,9 +938,9 @@
} else {
space.AddProperty("avgCollectionPeriodMillis", 0.0);
}
- space.AddProperty("used", UsedInWords() * kWordSize);
- space.AddProperty("capacity", CapacityInWords() * kWordSize);
- space.AddProperty("external", ExternalInWords() * kWordSize);
+ space.AddProperty64("used", UsedInWords() * kWordSize);
+ space.AddProperty64("capacity", CapacityInWords() * kWordSize);
+ space.AddProperty64("external", ExternalInWords() * kWordSize);
space.AddProperty("time", MicrosecondsToSeconds(gc_time_micros()));
}
diff --git a/runtime/vm/scavenger.h b/runtime/vm/scavenger.h
index 00b5706..af3f129 100644
--- a/runtime/vm/scavenger.h
+++ b/runtime/vm/scavenger.h
@@ -164,13 +164,13 @@
static intptr_t top_offset() { return OFFSET_OF(Scavenger, top_); }
static intptr_t end_offset() { return OFFSET_OF(Scavenger, end_); }
- intptr_t UsedInWords() const {
+ int64_t UsedInWords() const {
return (top_ - FirstObjectStart()) >> kWordSizeLog2;
}
- intptr_t CapacityInWords() const {
+ int64_t CapacityInWords() const {
return to_->size_in_words();
}
- intptr_t ExternalInWords() const {
+ int64_t ExternalInWords() const {
return external_size_ >> kWordSizeLog2;
}
SpaceUsage GetCurrentUsage() const {
@@ -268,19 +268,22 @@
return end_ < to_->end();
}
+ void UpdateMaxHeapCapacity();
+ void UpdateMaxHeapUsage();
+
void ProcessWeakTables();
intptr_t NewSizeInWords(intptr_t old_size_in_words) const;
- SemiSpace* to_;
-
- Heap* heap_;
-
// Current allocation top and end. These values are being accessed directly
// from generated code.
uword top_;
uword end_;
+ SemiSpace* to_;
+
+ Heap* heap_;
+
// A pointer to the first unscanned object. Scanning completes when
// this value meets the allocation top.
uword resolved_top_;
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 1dc403b..70d9e43 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -672,9 +672,9 @@
writer.WriteMessage(list);
intptr_t len = writer.BytesWritten();
if (FLAG_trace_service) {
- OS::Print(
- "vm-service: Pushing event of type %s to stream %s (%s), len %" Pd "\n",
- event_type, stream_id, isolate->name(), len);
+ OS::Print("vm-service: Pushing ServiceEvent(isolate='%s', kind='%s',"
+ " len=%" Pd ") to stream %s\n",
+ isolate->name(), event_type, len, stream_id);
}
// TODO(turnidge): For now we ignore failure to send an event. Revisit?
PortMap::PostMessage(
@@ -770,9 +770,9 @@
if (isolate != NULL) {
isolate_name = isolate->name();
}
- OS::Print(
- "vm-service: Pushing event of type %s to stream %s (%s)\n",
- kind, stream_id, isolate_name);
+ OS::Print("vm-service: Pushing ServiceEvent(isolate='%s', kind='%s') "
+ "to stream %s\n",
+ isolate_name, kind, stream_id);
}
Dart_PostCObject(ServiceIsolate::Port(), &list_cobj);
@@ -2041,17 +2041,9 @@
}
-static const MethodParameter* add_breakpoint_params[] = {
- ISOLATE_PARAMETER,
- new IdParameter("scriptId", false),
- new IdParameter("scriptUri", false),
- new UIntParameter("line", true),
- new UIntParameter("column", false),
- NULL,
-};
-
-
-static bool AddBreakpoint(Isolate* isolate, JSONStream* js) {
+static bool AddBreakpointCommon(Isolate* isolate,
+ JSONStream* js,
+ const String& script_uri) {
const char* line_param = js->LookupParam("line");
intptr_t line = UIntParameter::Parse(line_param);
const char* col_param = js->LookupParam("column");
@@ -2064,28 +2056,6 @@
return true;
}
}
- const char* script_id_param = js->LookupParam("scriptId");
- const char* script_uri_param = js->LookupParam("scriptUri");
- if (script_id_param == NULL && script_uri_param == NULL) {
- js->PrintError(kInvalidParams,
- "%s expects the 'scriptId' or the 'scriptUri' parameter",
- js->method());
- return true;
- }
- String& script_uri = String::Handle(isolate);
- if (script_id_param != NULL) {
- Object& obj =
- Object::Handle(LookupHeapObject(isolate, script_id_param, NULL));
- if (obj.raw() == Object::sentinel().raw() || !obj.IsScript()) {
- PrintInvalidParamError(js, "scriptId");
- return true;
- }
- const Script& script = Script::Cast(obj);
- script_uri = script.url();
- }
- if (script_uri_param != NULL) {
- script_uri = String::New(script_uri_param);
- }
ASSERT(!script_uri.IsNull());
Breakpoint* bpt = NULL;
bpt = isolate->debugger()->SetBreakpointAtLineCol(script_uri, line, col);
@@ -2100,6 +2070,46 @@
}
+static const MethodParameter* add_breakpoint_params[] = {
+ ISOLATE_PARAMETER,
+ new IdParameter("scriptId", true),
+ new UIntParameter("line", true),
+ new UIntParameter("column", false),
+ NULL,
+};
+
+
+static bool AddBreakpoint(Isolate* isolate, JSONStream* js) {
+ const char* script_id_param = js->LookupParam("scriptId");
+ Object& obj =
+ Object::Handle(LookupHeapObject(isolate, script_id_param, NULL));
+ if (obj.raw() == Object::sentinel().raw() || !obj.IsScript()) {
+ PrintInvalidParamError(js, "scriptId");
+ return true;
+ }
+ const Script& script = Script::Cast(obj);
+ const String& script_uri = String::Handle(script.url());
+ ASSERT(!script_uri.IsNull());
+ return AddBreakpointCommon(isolate, js, script_uri);
+}
+
+
+static const MethodParameter* add_breakpoint_with_script_uri_params[] = {
+ ISOLATE_PARAMETER,
+ new IdParameter("scriptUri", true),
+ new UIntParameter("line", true),
+ new UIntParameter("column", false),
+ NULL,
+};
+
+
+static bool AddBreakpointWithScriptUri(Isolate* isolate, JSONStream* js) {
+ const char* script_uri_param = js->LookupParam("scriptUri");
+ const String& script_uri = String::Handle(String::New(script_uri_param));
+ return AddBreakpointCommon(isolate, js, script_uri);
+}
+
+
static const MethodParameter* add_breakpoint_at_entry_params[] = {
ISOLATE_PARAMETER,
new IdParameter("functionId", true),
@@ -2942,10 +2952,7 @@
jsobj.AddProperty("targetCPU", CPU::Id());
jsobj.AddProperty("hostCPU", HostCPUFeatures::hardware());
jsobj.AddProperty("version", Version::String());
- // Send pid as a string because it allows us to avoid any issues with
- // pids > 53-bits (when consumed by JavaScript).
- // TODO(johnmccutchan): Codify how integers are sent across the service.
- jsobj.AddPropertyF("pid", "%" Pd "", OS::ProcessId());
+ jsobj.AddProperty("pid", OS::ProcessId());
jsobj.AddProperty("_assertsEnabled", isolate->flags().asserts());
jsobj.AddProperty("_typeChecksEnabled", isolate->flags().type_checks());
int64_t start_time_millis = (Dart::vm_isolate()->start_time() /
@@ -2961,6 +2968,19 @@
}
+static const MethodParameter* restart_vm_params[] = {
+ NO_ISOLATE_PARAMETER,
+ NULL,
+};
+
+
+static bool RestartVM(Isolate* isolate, JSONStream* js) {
+ Isolate::KillAllIsolates(Isolate::kVMRestartMsg);
+ PrintSuccess(js);
+ return true;
+}
+
+
static const MethodParameter* set_exception_pause_info_params[] = {
ISOLATE_PARAMETER,
NULL,
@@ -3121,6 +3141,8 @@
NULL },
{ "addBreakpoint", AddBreakpoint,
add_breakpoint_params },
+ { "addBreakpointWithScriptUri", AddBreakpointWithScriptUri,
+ add_breakpoint_with_script_uri_params },
{ "addBreakpointAtEntry", AddBreakpointAtEntry,
add_breakpoint_at_entry_params },
{ "_addBreakpointAtActivation", AddBreakpointAtActivation,
@@ -3185,6 +3207,8 @@
pause_params },
{ "removeBreakpoint", RemoveBreakpoint,
remove_breakpoint_params },
+ { "_restartVM", RestartVM,
+ restart_vm_params },
{ "resume", Resume,
resume_params },
{ "_requestHeapSnapshot", RequestHeapSnapshot,
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index 69beec686..df05a47 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -25,6 +25,7 @@
- [Private RPCs, Types, and Properties](#private-rpcs-types-and-properties)
- [Public RPCs](#public-rpcs)
- [addBreakpoint](#addbreakpoint)
+ - [addBreakpointWithScriptUri](#addbreakpointwithscripturi)
- [addBreakpointAtEntry](#addbreakpointatentry)
- [evaluate](#evaluate)
- [evaluateInFrame](#evaluateinframe)
@@ -372,8 +373,7 @@
```
Breakpoint addBreakpoint(string isolateId,
- string scriptId [optional],
- string scriptUri [optional],
+ string scriptId,
int line,
int column [optional])
```
@@ -381,8 +381,41 @@
The _addBreakpoint_ RPC is used to add a breakpoint at a specific line
of some script.
-The _scriptId_ or _scriptUri_ parameter is used to specify the target
-script. One of these two parameters must always be provided.
+The _scriptId_ parameter is used to specify the target script.
+
+The _line_ parameter is used to specify the target line for the
+breakpoint. If there are multiple possible breakpoints on the target
+line, then the VM will place the breakpoint at the location which
+would execute soonest. If it is not possible to set a breakpoint at
+the target line, the breakpoint will be added at the next possible
+breakpoint location within the same function.
+
+The _column_ parameter may be optionally specified. This is useful
+for targeting a specific breakpoint on a line with multiple possible
+breakpoints.
+
+If no breakpoint is possible at that line, the _102_ (Cannot add
+breakpoint) error code is returned.
+
+Note that breakpoints are added and removed on a per-isolate basis.
+
+See [Breakpoint](#breakpoint).
+
+### addBreakpointWithScriptUri
+
+```
+Breakpoint addBreakpointWithScriptUri(string isolateId,
+ string scriptUri,
+ int line,
+ int column [optional])
+```
+
+The _addBreakpoint_ RPC is used to add a breakpoint at a specific line
+of some script. This RPC is useful when a script has not yet been
+assigned an id, for example, if a script is in a deferred library
+which has not yet been loaded.
+
+The _scriptUri_ parameter is used to specify the target script.
The _line_ parameter is used to specify the target line for the
breakpoint. If there are multiple possible breakpoints on the target
@@ -1655,11 +1688,6 @@
// running, this will be a resume event.
Event pauseEvent;
- // The entry function for this isolate.
- //
- // Guaranteed to be initialized when the IsolateRunnable event fires.
- @Function entry [optional];
-
// The root library for this isolate.
//
// Guaranteed to be initialized when the IsolateRunnable event fires.
@@ -2101,7 +2129,7 @@
string version;
// The process id for the VM.
- string pid;
+ int pid;
// The time that the VM started in milliseconds since the epoch.
//
@@ -2117,9 +2145,9 @@
version | comments
------- | --------
-1.0 draft 1 | initial revision
-1.1 | Describe protocol version 2.0.
-1.2 | Describe protocol version 3.0. Added UnresolvedSourceLocation. Added Sentinel return to getIsolate.
+1.0 | initial revision
+2.0 | Describe protocol version 2.0.
+3.0 | Describe protocol version 3.0. Added UnresolvedSourceLocation. Added Sentinel return to getIsolate. Add AddedBreakpointWithScriptUri. Removed Isolate.entry. The type of VM.pid was changed from string to int.
[discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc
index c07638f..4448820 100644
--- a/runtime/vm/service_isolate.cc
+++ b/runtime/vm/service_isolate.cc
@@ -31,95 +31,12 @@
DEFINE_FLAG(bool, trace_service_pause_events, false,
"Trace VM service isolate pause events.");
-struct ResourcesEntry {
- const char* path_;
- const char* resource_;
- int length_;
-};
-
-extern ResourcesEntry __service_resources_[];
-
-class Resources {
- public:
- static const int kNoSuchInstance = -1;
- static int ResourceLookup(const char* path, const char** resource) {
- ResourcesEntry* table = ResourceTable();
- for (int i = 0; table[i].path_ != NULL; i++) {
- const ResourcesEntry& entry = table[i];
- if (strcmp(path, entry.path_) == 0) {
- *resource = entry.resource_;
- ASSERT(entry.length_ > 0);
- return entry.length_;
- }
- }
- return kNoSuchInstance;
- }
-
- static const char* Path(int idx) {
- ASSERT(idx >= 0);
- ResourcesEntry* entry = At(idx);
- if (entry == NULL) {
- return NULL;
- }
- ASSERT(entry->path_ != NULL);
- return entry->path_;
- }
-
- static int Length(int idx) {
- ASSERT(idx >= 0);
- ResourcesEntry* entry = At(idx);
- if (entry == NULL) {
- return kNoSuchInstance;
- }
- ASSERT(entry->path_ != NULL);
- return entry->length_;
- }
-
- static const uint8_t* Resource(int idx) {
- ASSERT(idx >= 0);
- ResourcesEntry* entry = At(idx);
- if (entry == NULL) {
- return NULL;
- }
- return reinterpret_cast<const uint8_t*>(entry->resource_);
- }
-
- private:
- static ResourcesEntry* At(int idx) {
- ASSERT(idx >= 0);
- ResourcesEntry* table = ResourceTable();
- for (int i = 0; table[i].path_ != NULL; i++) {
- if (idx == i) {
- return &table[i];
- }
- }
- return NULL;
- }
-
- static ResourcesEntry* ResourceTable() {
- return &__service_resources_[0];
- }
-
- DISALLOW_ALLOCATION();
- DISALLOW_IMPLICIT_CONSTRUCTORS(Resources);
-};
-
-
static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) {
void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
return reinterpret_cast<uint8_t*>(new_ptr);
}
-static Dart_Port ExtractPort(Isolate* isolate, Dart_Handle receivePort) {
- const ReceivePort& rp = Api::UnwrapReceivePortHandle(isolate, receivePort);
- if (rp.IsNull()) {
- return ILLEGAL_PORT;
- }
- return rp.Id();
-}
-
-
// These must be kept in sync with service/constants.dart
#define VM_SERVICE_ISOLATE_EXIT_MESSAGE_ID 0
#define VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID 1
@@ -163,217 +80,6 @@
bool ServiceIsolate::shutting_down_ = false;
-class RegisterRunningIsolatesVisitor : public IsolateVisitor {
- public:
- explicit RegisterRunningIsolatesVisitor(Isolate* service_isolate)
- : IsolateVisitor(),
- register_function_(Function::Handle(service_isolate)),
- service_isolate_(service_isolate) {
- ASSERT(ServiceIsolate::IsServiceIsolate(Isolate::Current()));
- // Get library.
- const String& library_url = Symbols::DartVMService();
- ASSERT(!library_url.IsNull());
- const Library& library =
- Library::Handle(Library::LookupLibrary(library_url));
- ASSERT(!library.IsNull());
- // Get function.
- const String& function_name =
- String::Handle(String::New("_registerIsolate"));
- ASSERT(!function_name.IsNull());
- register_function_ = library.LookupFunctionAllowPrivate(function_name);
- ASSERT(!register_function_.IsNull());
- }
-
- virtual void VisitIsolate(Isolate* isolate) {
- ASSERT(ServiceIsolate::IsServiceIsolate(Isolate::Current()));
- if (ServiceIsolate::IsServiceIsolateDescendant(isolate) ||
- (isolate == Dart::vm_isolate())) {
- // We do not register the service (and descendants) or the vm-isolate.
- return;
- }
- // Setup arguments for call.
- Dart_Port port_id = isolate->main_port();
- const Integer& port_int = Integer::Handle(Integer::New(port_id));
- ASSERT(!port_int.IsNull());
- const SendPort& send_port = SendPort::Handle(SendPort::New(port_id));
- const String& name = String::Handle(String::New(isolate->name()));
- ASSERT(!name.IsNull());
- const Array& args = Array::Handle(Array::New(3));
- ASSERT(!args.IsNull());
- args.SetAt(0, port_int);
- args.SetAt(1, send_port);
- args.SetAt(2, name);
- Object& r = Object::Handle(service_isolate_);
- r = DartEntry::InvokeFunction(register_function_, args);
- if (FLAG_trace_service) {
- OS::Print("vm-service: Isolate %s %" Pd64 " registered.\n",
- name.ToCString(),
- port_id);
- }
- ASSERT(!r.IsError());
- }
-
- private:
- Function& register_function_;
- Isolate* service_isolate_;
-};
-
-
-
-class ServiceIsolateNatives : public AllStatic {
- public:
- static void SendIsolateServiceMessage(Dart_NativeArguments args) {
- NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
- Thread* thread = arguments->thread();
- StackZone stack_zone(thread);
- Zone* zone = stack_zone.GetZone(); // Used by GET_NON_NULL_NATIVE_ARGUMENT.
- HANDLESCOPE(thread);
- GET_NON_NULL_NATIVE_ARGUMENT(SendPort, sp, arguments->NativeArgAt(0));
- GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(1));
-
- // Set the type of the OOB message.
- message.SetAt(0, Smi::Handle(thread->zone(),
- Smi::New(Message::kServiceOOBMsg)));
-
- // Serialize message.
- uint8_t* data = NULL;
- MessageWriter writer(&data, &allocator, false);
- writer.WriteMessage(message);
-
- // TODO(turnidge): Throw an exception when the return value is false?
- bool result = PortMap::PostMessage(
- new Message(sp.Id(), data, writer.BytesWritten(),
- Message::kOOBPriority));
- arguments->SetReturn(Bool::Get(result));
- }
-
- static void SendRootServiceMessage(Dart_NativeArguments args) {
- NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
- Thread* thread = arguments->thread();
- StackZone stack_zone(thread);
- Zone* zone = stack_zone.GetZone(); // Used by GET_NON_NULL_NATIVE_ARGUMENT.
- HANDLESCOPE(thread);
- GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0));
- Service::HandleRootMessage(message);
- }
-
- static void OnStart(Dart_NativeArguments args) {
- NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
- Thread* thread = arguments->thread();
- Isolate* isolate = thread->isolate();
- StackZone zone(thread);
- HANDLESCOPE(thread);
- {
- if (FLAG_trace_service) {
- OS::Print("vm-service: Booting dart:vmservice library.\n");
- }
- // Boot the dart:vmservice library.
- Dart_EnterScope();
- Dart_Handle url_str =
- Dart_NewStringFromCString(Symbols::Name(Symbols::kDartVMServiceId));
- Dart_Handle library = Dart_LookupLibrary(url_str);
- ASSERT(Dart_IsLibrary(library));
- Dart_Handle result =
- Dart_Invoke(library, Dart_NewStringFromCString("boot"), 0, NULL);
- ASSERT(!Dart_IsError(result));
- Dart_Port port = ExtractPort(isolate, result);
- ASSERT(port != ILLEGAL_PORT);
- ServiceIsolate::SetServicePort(port);
- Dart_ExitScope();
- }
-
- {
- if (FLAG_trace_service) {
- OS::Print("vm-service: Registering running isolates.\n");
- }
- // Register running isolates with service.
- RegisterRunningIsolatesVisitor register_isolates(isolate);
- Isolate::VisitIsolates(®ister_isolates);
- }
- }
-
- static void OnExit(Dart_NativeArguments args) {
- NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
- Thread* thread = arguments->thread();
- StackZone zone(thread);
- HANDLESCOPE(thread);
- {
- if (FLAG_trace_service) {
- OS::Print("vm-service: processed exit message.\n");
- }
- }
- }
-
- static void ListenStream(Dart_NativeArguments args) {
- NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
- Thread* thread = arguments->thread();
- StackZone stack_zone(thread);
- Zone* zone = stack_zone.GetZone(); // Used by GET_NON_NULL_NATIVE_ARGUMENT.
- HANDLESCOPE(thread);
- GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0));
- bool result = Service::ListenStream(stream_id.ToCString());
- arguments->SetReturn(Bool::Get(result));
- }
-
- static void CancelStream(Dart_NativeArguments args) {
- NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
- Thread* thread = arguments->thread();
- StackZone stack_zone(thread);
- Zone* zone = stack_zone.GetZone(); // Used by GET_NON_NULL_NATIVE_ARGUMENT.
- HANDLESCOPE(thread);
- GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0));
- Service::CancelStream(stream_id.ToCString());
- }
-};
-
-
-struct ServiceNativeEntry {
- const char* name;
- int num_arguments;
- Dart_NativeFunction function;
-};
-
-
-static ServiceNativeEntry _ServiceNativeEntries[] = {
- {"VMService_SendIsolateServiceMessage", 2,
- ServiceIsolateNatives::SendIsolateServiceMessage},
- {"VMService_SendRootServiceMessage", 1,
- ServiceIsolateNatives::SendRootServiceMessage},
- {"VMService_OnStart", 0,
- ServiceIsolateNatives::OnStart },
- {"VMService_OnExit", 0,
- ServiceIsolateNatives::OnExit },
- {"VMService_ListenStream", 1,
- ServiceIsolateNatives::ListenStream },
- {"VMService_CancelStream", 1,
- ServiceIsolateNatives::CancelStream },
-};
-
-
-static Dart_NativeFunction ServiceNativeResolver(Dart_Handle name,
- int num_arguments,
- bool* auto_setup_scope) {
- const Object& obj = Object::Handle(Api::UnwrapHandle(name));
- if (!obj.IsString()) {
- return NULL;
- }
- const char* function_name = obj.ToCString();
- ASSERT(function_name != NULL);
- ASSERT(auto_setup_scope != NULL);
- *auto_setup_scope = true;
- intptr_t n = sizeof(_ServiceNativeEntries) /
- sizeof(_ServiceNativeEntries[0]);
- for (intptr_t i = 0; i < n; i++) {
- ServiceNativeEntry entry = _ServiceNativeEntries[i];
- if ((strcmp(function_name, entry.name) == 0) &&
- (num_arguments == entry.num_arguments)) {
- return entry.function;
- }
- }
- return NULL;
-}
-
-
bool ServiceIsolate::NameEquals(const char* name) {
ASSERT(name != NULL);
return strcmp(name, kName) == 0;
@@ -529,7 +235,7 @@
}
-void ServiceIsolate::MaybeInjectVMServiceLibrary(Isolate* I) {
+void ServiceIsolate::MaybeMakeServiceIsolate(Isolate* I) {
Thread* T = Thread::Current();
ASSERT(I == T->isolate());
ASSERT(I != NULL);
@@ -543,46 +249,6 @@
return;
}
SetServiceIsolate(I);
-
- StackZone zone(T);
- HANDLESCOPE(T);
-
- // Register dart:vmservice library.
- const String& url_str = String::Handle(Z, Symbols::DartVMService().raw());
- const Library& library = Library::Handle(Z, Library::New(url_str));
- library.Register();
- library.set_native_entry_resolver(ServiceNativeResolver);
-
- // Temporarily install our library tag handler.
- I->set_library_tag_handler(LibraryTagHandler);
-
- // Get script source.
- const char* resource = NULL;
- const char* path = "/vmservice.dart";
- intptr_t r = Resources::ResourceLookup(path, &resource);
- ASSERT(r != Resources::kNoSuchInstance);
- ASSERT(resource != NULL);
- const String& source_str = String::Handle(Z,
- String::FromUTF8(reinterpret_cast<const uint8_t*>(resource), r));
- ASSERT(!source_str.IsNull());
- const Script& script = Script::Handle(Z,
- Script::New(url_str, source_str, RawScript::kLibraryTag));
-
- // Compile script.
- Dart_EnterScope(); // Need to enter scope for tag handler.
- library.SetLoadInProgress();
- const Error& error = Error::Handle(Z, Compiler::Compile(library, script));
- if (!error.IsNull()) {
- OS::PrintErr("vm-service: Isolate creation error: %s\n",
- error.ToErrorCString());
- }
- ASSERT(error.IsNull());
- Dart_Handle result = Dart_FinalizeLoading(false);
- ASSERT(!Dart_IsError(result));
- Dart_ExitScope();
-
- // Uninstall our library tag handler.
- I->set_library_tag_handler(NULL);
}
@@ -770,7 +436,7 @@
MonitorLocker ml(monitor_);
shutting_down_ = true;
}
- Isolate::KillIfExists(isolate_);
+ Isolate::KillIfExists(isolate_, Isolate::kInternalKillMsg);
{
MonitorLocker ml(monitor_);
while (shutting_down_) {
@@ -805,50 +471,25 @@
}
-Dart_Handle ServiceIsolate::GetSource(const char* name) {
- ASSERT(name != NULL);
- int i = 0;
- while (true) {
- const char* path = Resources::Path(i);
- if (path == NULL) {
- break;
- }
- ASSERT(*path != '\0');
- // Skip the '/'.
- path++;
- if (strcmp(name, path) == 0) {
- const uint8_t* str = Resources::Resource(i);
- intptr_t length = Resources::Length(i);
- return Dart_NewStringFromUTF8(str, length);
- }
- i++;
+void ServiceIsolate::BootVmServiceLibrary() {
+ const Library& vmservice_library =
+ Library::Handle(Library::LookupLibrary(Symbols::DartVMService()));
+ ASSERT(!vmservice_library.IsNull());
+ const String& boot_function_name = String::Handle(String::New("boot"));
+ const Function& boot_function =
+ Function::Handle(
+ vmservice_library.LookupFunctionAllowPrivate(boot_function_name));
+ ASSERT(!boot_function.IsNull());
+ const Object& result =
+ Object::Handle(
+ DartEntry::InvokeFunction(boot_function, Object::empty_array()));
+ ASSERT(!result.IsNull());
+ Dart_Port port = ILLEGAL_PORT;
+ if (result.IsReceivePort()) {
+ port = ReceivePort::Cast(result).Id();
}
- FATAL1("vm-service: Could not find embedded source file: %s ", name);
- return Dart_Null();
-}
-
-
-Dart_Handle ServiceIsolate::LibraryTagHandler(Dart_LibraryTag tag,
- Dart_Handle library,
- Dart_Handle url) {
- if (tag == Dart_kCanonicalizeUrl) {
- // url is already canonicalized.
- return url;
- }
- if (tag != Dart_kSourceTag) {
- FATAL("ServiceIsolate::LibraryTagHandler encountered an unexpected tag.");
- }
- ASSERT(tag == Dart_kSourceTag);
- const char* url_string = NULL;
- Dart_Handle result = Dart_StringToCString(url, &url_string);
- if (Dart_IsError(result)) {
- return result;
- }
- Dart_Handle source = GetSource(url_string);
- if (Dart_IsError(source)) {
- return source;
- }
- return Dart_LoadSource(library, url, source, 0, 0);
+ ASSERT(port != ILLEGAL_PORT);
+ ServiceIsolate::SetServicePort(port);
}
} // namespace dart
diff --git a/runtime/vm/service_isolate.h b/runtime/vm/service_isolate.h
index 86433c9..a942ec1 100644
--- a/runtime/vm/service_isolate.h
+++ b/runtime/vm/service_isolate.h
@@ -32,6 +32,8 @@
static void SendServiceExitMessage();
static void Shutdown();
+ static void BootVmServiceLibrary();
+
private:
static void KillServiceIsolate();
@@ -42,15 +44,11 @@
static void ConstructExitMessageAndCache(Isolate* isolate);
static void FinishedExiting();
static void FinishedInitializing();
- static void MaybeInjectVMServiceLibrary(Isolate* isolate);
+ static void MaybeMakeServiceIsolate(Isolate* isolate);
static Dart_IsolateCreateCallback create_callback() {
return create_callback_;
}
- static Dart_Handle GetSource(const char* name);
- static Dart_Handle LibraryTagHandler(Dart_LibraryTag tag, Dart_Handle library,
- Dart_Handle url);
-
static Dart_IsolateCreateCallback create_callback_;
static uint8_t* exit_message_;
static intptr_t exit_message_length_;
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index 0bae8ad..406dfbb 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -29,7 +29,7 @@
free(_msg);
}
- bool HandleMessage(Message* message) {
+ MessageStatus HandleMessage(Message* message) {
if (_msg != NULL) {
free(_msg);
}
@@ -41,7 +41,7 @@
String& response = String::Handle();
response ^= response_obj.raw();
_msg = strdup(response.ToCString());
- return true;
+ return kOK;
}
const char* msg() const { return _msg; }
@@ -191,7 +191,7 @@
service_msg =
Eval(lib, "[0, port, '0', 'getObject', ['objectId'], ['code/0']]");
Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
EXPECT_SUBSTRING("\"error\"", handler.msg());
// The following test checks that a code object can be found only
@@ -201,7 +201,7 @@
compile_timestamp,
entry);
Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
EXPECT_SUBSTRING("\"type\":\"Code\"", handler.msg());
{
// Only perform a partial match.
@@ -222,7 +222,7 @@
compile_timestamp,
address);
Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
EXPECT_SUBSTRING("\"error\"", handler.msg());
// Request code object at (compile_timestamp - 1)-code.EntryPoint()
@@ -233,7 +233,7 @@
compile_timestamp - 1,
address);
Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
EXPECT_SUBSTRING("\"error\"", handler.msg());
// Request native code at address. Expect the null code object back.
@@ -242,7 +242,7 @@
"['objectId'], ['code/native-%" Px "']]",
address);
Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
// TODO(turnidge): It is pretty broken to return an Instance here. Fix.
EXPECT_SUBSTRING("\"kind\":\"Null\"",
handler.msg());
@@ -252,7 +252,7 @@
"['code/native%" Px "']]",
address);
Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
EXPECT_SUBSTRING("\"error\"", handler.msg());
}
@@ -295,7 +295,7 @@
service_msg = EvalF(lib, "[0, port, '0', 'getObject', "
"['objectId'], ['objects/%" Pd "']]", id);
Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
// Check type.
EXPECT_SUBSTRING("\"type\":\"Object\"", handler.msg());
@@ -357,7 +357,7 @@
service_msg = EvalF(lib, "[0, port, '0', 'getObject', "
"['objectId'], ['objects/%" Pd "']]", id);
Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
// Check type.
EXPECT_SUBSTRING("\"type\":\"Object\"", handler.msg());
EXPECT_SUBSTRING("\"_vmType\":\"PcDescriptors\"", handler.msg());
@@ -418,7 +418,7 @@
service_msg = EvalF(lib, "[0, port, '0', 'getObject', "
"['objectId'], ['objects/%" Pd "']]", id);
Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
// Check type.
EXPECT_SUBSTRING("\"type\":\"Object\"", handler.msg());
EXPECT_SUBSTRING("\"_vmType\":\"LocalVarDescriptors\"", handler.msg());
@@ -463,7 +463,7 @@
addr);
service_msg = Eval(lib, buf);
Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
EXPECT_SUBSTRING(ref ? "\"type\":\"@Instance\"" :
"\"type\":\"Instance\"",
handler.msg());
@@ -474,7 +474,7 @@
service_msg = Eval(lib, "[0, port, '0', '_getObjectByAddress', "
"['address'], ['7']]");
Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
// TODO(turnidge): Should this be a ServiceException instead?
EXPECT_SUBSTRING("{\"type\":\"Sentinel\",\"kind\":\"Free\","
"\"valueAsString\":\"<free>\"",
@@ -532,12 +532,12 @@
Array& service_msg = Array::Handle();
service_msg = Eval(lib, "[0, port, '\"', 'alpha', [], []]");
Service::HandleRootMessage(service_msg);
- handler.HandleNextMessage();
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"result\":alpha,\"id\":\"\\\"\"}",
handler.msg());
service_msg = Eval(lib, "[0, port, 1, 'beta', [], []]");
Service::HandleRootMessage(service_msg);
- handler.HandleNextMessage();
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"result\":beta,\"id\":1}",
handler.msg());
}
@@ -572,12 +572,12 @@
Array& service_msg = Array::Handle();
service_msg = Eval(lib, "[0, port, '0', 'alpha', [], []]");
Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"result\":alpha,\"id\":\"0\"}",
handler.msg());
service_msg = Eval(lib, "[0, port, '0', 'beta', [], []]");
Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"result\":beta,\"id\":\"0\"}",
handler.msg());
}
@@ -611,21 +611,21 @@
Array& service_msg = Array::Handle();
service_msg = Eval(lib, "[0, port, '0', '_getCpuProfile', [], []]");
Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
// Expect error (tags required).
EXPECT_SUBSTRING("\"error\"", handler.msg());
service_msg =
Eval(lib, "[0, port, '0', '_getCpuProfile', ['tags'], ['None']]");
Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
// Expect profile
EXPECT_SUBSTRING("\"type\":\"_CpuProfile\"", handler.msg());
service_msg =
Eval(lib, "[0, port, '0', '_getCpuProfile', ['tags'], ['Bogus']]");
Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
// Expect error.
EXPECT_SUBSTRING("\"error\"", handler.msg());
}
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 4b3fb8a..5419aaa 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -3868,7 +3868,7 @@
set_register(FP, static_cast<int32_t>(fp));
set_register(THR, reinterpret_cast<uword>(thread));
// Set the tag.
- isolate->set_vm_tag(VMTag::kDartTagId);
+ thread->set_vm_tag(VMTag::kDartTagId);
// Clear top exit frame.
isolate->set_top_exit_frame_info(0);
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index 3c7b99d..ac6fe18 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -3528,7 +3528,7 @@
set_register(NULL, FP, static_cast<int64_t>(fp));
set_register(NULL, THR, reinterpret_cast<int64_t>(thread));
// Set the tag.
- isolate->set_vm_tag(VMTag::kDartTagId);
+ thread->set_vm_tag(VMTag::kDartTagId);
// Clear top exit frame.
isolate->set_top_exit_frame_info(0);
diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc
index f8da783..a6bd8de 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -2476,7 +2476,7 @@
set_register(FP, static_cast<int32_t>(fp));
set_register(THR, reinterpret_cast<int32_t>(thread));
// Set the tag.
- isolate->set_vm_tag(VMTag::kDartTagId);
+ thread->set_vm_tag(VMTag::kDartTagId);
// Clear top exit frame.
isolate->set_top_exit_frame_info(0);
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 5875720..e4c757d 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -65,6 +65,7 @@
return class_id >= kNumPredefinedCids ||
class_id == kArrayCid ||
class_id == kImmutableArrayCid ||
+ class_id == kObjectPoolCid ||
RawObject::IsImplicitFieldClassId(class_id);
}
@@ -259,7 +260,7 @@
if (cls.IsNull()) {
SetReadException("Invalid object found in message.");
}
- cls.EnsureIsFinalized(isolate());
+ cls.EnsureIsFinalized(thread());
return cls.raw();
}
@@ -290,7 +291,7 @@
if (cls_.IsNull()) {
SetReadException("Expected a class name, but found an invalid name.");
}
- cls_.EnsureIsFinalized(isolate());
+ cls_.EnsureIsFinalized(thread());
str_ ^= ReadObjectImpl(kAsInlinedObject);
func ^= cls_.LookupFunctionAllowPrivate(str_);
}
@@ -327,7 +328,7 @@
OS::Print("Name of class not found %s\n", str_.ToCString());
SetReadException("Invalid Class object found in message.");
}
- cls_.EnsureIsFinalized(isolate());
+ cls_.EnsureIsFinalized(thread());
str_ ^= ReadObjectImpl(kAsInlinedObject);
func = cls_.LookupFunctionAllowPrivate(str_);
}
@@ -484,6 +485,16 @@
return array.raw();
}
+ if (class_id == kObjectPoolCid) {
+ ASSERT(kind_ == Snapshot::kFull);
+ // Read the length and allocate an object based on the len.
+ intptr_t len = Read<intptr_t>();
+ ObjectPool& pool = ObjectPool::ZoneHandle(zone(),
+ NewObjectPool(len));
+ AddBackRef(object_id, &pool, kIsNotDeserialized);
+
+ return pool.raw();
+ }
// For all other internal VM classes we read the object inline.
switch (class_id) {
@@ -2008,19 +2019,6 @@
}
-class WritableVMIsolateScope : StackResource {
- public:
- explicit WritableVMIsolateScope(Thread* thread) : StackResource(thread) {
- Dart::vm_isolate()->heap()->WriteProtect(false);
- }
-
- ~WritableVMIsolateScope() {
- ASSERT(Dart::vm_isolate()->heap()->UsedInWords(Heap::kNew) == 0);
- Dart::vm_isolate()->heap()->WriteProtect(true);
- }
-};
-
-
void FullSnapshotWriter::WriteFullSnapshot() {
if (!vm_isolate_is_symbolic_) {
// TODO(asiva): Don't mutate object headers during serialization.
@@ -2275,6 +2273,29 @@
return;
}
+ if (class_id == kObjectPoolCid) {
+ intptr_t tags = GetObjectTags(raw);
+
+ // Object is being referenced, add it to the forward ref list and mark
+ // it so that future references to this object in the snapshot will use
+ // this object id. Mark it as not having been serialized yet so that we
+ // will serialize the object when we go through the forward list.
+ forward_list_->MarkAndAddObject(raw, kIsNotSerialized);
+
+ RawObjectPool* rawpool = reinterpret_cast<RawObjectPool*>(raw);
+
+ // Write out the serialization header value for this object.
+ WriteInlinedObjectHeader(kOmittedObjectId);
+
+ // Write out the class information.
+ WriteVMIsolateObject(kObjectPoolCid);
+ WriteTags(tags);
+
+ // Write out the length field.
+ Write<intptr_t>(rawpool->ptr()->length_);
+
+ return;
+ }
// Add object to the forward ref list and mark it so that future references
// to this object in the snapshot will use this object id. Mark it as having
// been serialized so that we do not serialize the object when we go through
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index ff5f8a3..5f86c3b 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -203,10 +203,11 @@
}
-bool StackFrame::FindExceptionHandler(Isolate* isolate,
+bool StackFrame::FindExceptionHandler(Thread* thread,
uword* handler_pc,
bool* needs_stacktrace,
bool* has_catch_all) const {
+ Isolate* isolate = thread->isolate();
REUSABLE_CODE_HANDLESCOPE(isolate);
Code& code = reused_code_handle.Handle();
code = LookupDartCode();
diff --git a/runtime/vm/stack_frame.h b/runtime/vm/stack_frame.h
index 5dd0f14..2889a1e 100644
--- a/runtime/vm/stack_frame.h
+++ b/runtime/vm/stack_frame.h
@@ -77,7 +77,7 @@
RawFunction* LookupDartFunction() const;
RawCode* LookupDartCode() const;
- bool FindExceptionHandler(Isolate* isolate,
+ bool FindExceptionHandler(Thread* thread,
uword* handler_pc,
bool* needs_stacktrace,
bool* is_catch_all) const;
diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc
index df7773d..c42c21a 100644
--- a/runtime/vm/stub_code.cc
+++ b/runtime/vm/stub_code.cc
@@ -94,8 +94,9 @@
RawCode* StubCode::GetAllocationStubForClass(const Class& cls) {
- Isolate* isolate = Isolate::Current();
- const Error& error = Error::Handle(isolate, cls.EnsureIsFinalized(isolate));
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ const Error& error = Error::Handle(isolate, cls.EnsureIsFinalized(thread));
ASSERT(error.IsNull());
if (cls.id() == kArrayCid) {
return AllocateArray_entry()->code();
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 6c6f283..5acd669 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -45,9 +45,6 @@
__ EnterStubFrame();
- COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R7)) != 0);
- __ LoadIsolate(R7);
-
// Save exit frame information to enable stack walking as we are about
// to transition to Dart VM C++ code.
__ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset());
@@ -55,7 +52,7 @@
#if defined(DEBUG)
{ Label ok;
// Check that we are always entering from Dart code.
- __ LoadFromOffset(kWord, R6, R7, Isolate::vm_tag_offset());
+ __ LoadFromOffset(kWord, R6, THR, Thread::vm_tag_offset());
__ CompareImmediate(R6, VMTag::kDartTagId);
__ b(&ok, EQ);
__ Stop("Not coming from Dart code.");
@@ -63,8 +60,8 @@
}
#endif
- // Mark that the isolate is executing VM code.
- __ StoreToOffset(kWord, R5, R7, Isolate::vm_tag_offset());
+ // Mark that the thread is executing VM code.
+ __ StoreToOffset(kWord, R5, THR, Thread::vm_tag_offset());
// Reserve space for arguments and align frame before entering C++ world.
// NativeArguments are passed in registers.
@@ -94,9 +91,9 @@
// Call runtime or redirection via simulator.
__ blx(R5);
- // Mark that the isolate is executing Dart code.
+ // Mark that the thread is executing Dart code.
__ LoadImmediate(R2, VMTag::kDartTagId);
- __ StoreToOffset(kWord, R2, R7, Isolate::vm_tag_offset());
+ __ StoreToOffset(kWord, R2, THR, Thread::vm_tag_offset());
// Reset exit frame information in Isolate structure.
__ LoadImmediate(R2, 0);
@@ -140,9 +137,6 @@
__ EnterStubFrame();
- COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R7)) != 0);
- __ LoadIsolate(R7);
-
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
__ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset());
@@ -150,7 +144,7 @@
#if defined(DEBUG)
{ Label ok;
// Check that we are always entering from Dart code.
- __ LoadFromOffset(kWord, R6, R7, Isolate::vm_tag_offset());
+ __ LoadFromOffset(kWord, R6, THR, Thread::vm_tag_offset());
__ CompareImmediate(R6, VMTag::kDartTagId);
__ b(&ok, EQ);
__ Stop("Not coming from Dart code.");
@@ -158,8 +152,8 @@
}
#endif
- // Mark that the isolate is executing Native code.
- __ StoreToOffset(kWord, R5, R7, Isolate::vm_tag_offset());
+ // Mark that the thread is executing native code.
+ __ StoreToOffset(kWord, R5, THR, Thread::vm_tag_offset());
// Reserve space for the native arguments structure passed on the stack (the
// outgoing pointer parameter to the native arguments structure is passed in
@@ -197,9 +191,9 @@
__ ldr(LR, Address(THR, Thread::native_call_wrapper_entry_point_offset()));
__ blx(LR);
- // Mark that the isolate is executing Dart code.
+ // Mark that the thread is executing Dart code.
__ LoadImmediate(R2, VMTag::kDartTagId);
- __ StoreToOffset(kWord, R2, R7, Isolate::vm_tag_offset());
+ __ StoreToOffset(kWord, R2, THR, Thread::vm_tag_offset());
// Reset exit frame information in Isolate structure.
__ LoadImmediate(R2, 0);
@@ -224,9 +218,6 @@
__ EnterStubFrame();
- COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R7)) != 0);
- __ LoadIsolate(R7);
-
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
__ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset());
@@ -234,7 +225,7 @@
#if defined(DEBUG)
{ Label ok;
// Check that we are always entering from Dart code.
- __ LoadFromOffset(kWord, R6, R7, Isolate::vm_tag_offset());
+ __ LoadFromOffset(kWord, R6, THR, Thread::vm_tag_offset());
__ CompareImmediate(R6, VMTag::kDartTagId);
__ b(&ok, EQ);
__ Stop("Not coming from Dart code.");
@@ -242,8 +233,8 @@
}
#endif
- // Mark that the isolate is executing Native code.
- __ StoreToOffset(kWord, R5, R7, Isolate::vm_tag_offset());
+ // Mark that the thread is executing native code.
+ __ StoreToOffset(kWord, R5, THR, Thread::vm_tag_offset());
// Reserve space for the native arguments structure passed on the stack (the
// outgoing pointer parameter to the native arguments structure is passed in
@@ -278,9 +269,9 @@
// Call native function or redirection via simulator.
__ blx(R5);
- // Mark that the isolate is executing Dart code.
+ // Mark that the thread is executing Dart code.
__ LoadImmediate(R2, VMTag::kDartTagId);
- __ StoreToOffset(kWord, R2, R7, Isolate::vm_tag_offset());
+ __ StoreToOffset(kWord, R2, THR, Thread::vm_tag_offset());
// Reset exit frame information in Isolate structure.
__ LoadImmediate(R2, 0);
@@ -761,15 +752,14 @@
if (THR != R3) {
__ mov(THR, Operand(R3));
}
- __ LoadIsolate(R7);
// Save the current VMTag on the stack.
- __ LoadFromOffset(kWord, R5, R7, Isolate::vm_tag_offset());
+ __ LoadFromOffset(kWord, R5, THR, Thread::vm_tag_offset());
__ Push(R5);
- // Mark that the isolate is executing Dart code.
+ // Mark that the thread is executing Dart code.
__ LoadImmediate(R5, VMTag::kDartTagId);
- __ StoreToOffset(kWord, R5, R7, Isolate::vm_tag_offset());
+ __ StoreToOffset(kWord, R5, THR, Thread::vm_tag_offset());
// Save top resource and top exit frame info. Use R4-6 as temporary registers.
// StackFrameIterator reads the top exit frame info saved in this frame.
@@ -819,7 +809,6 @@
// Get rid of arguments pushed on the stack.
__ AddImmediate(SP, FP, kExitLinkSlotFromEntryFp * kWordSize);
- __ LoadIsolate(R7);
// Restore the saved top exit frame info and top resource back into the
// Isolate structure. Uses R5 as a temporary register for this.
__ Pop(R5);
@@ -829,7 +818,7 @@
// Restore the current VMTag from the stack.
__ Pop(R4);
- __ StoreToOffset(kWord, R4, R7, Isolate::vm_tag_offset());
+ __ StoreToOffset(kWord, R4, THR, Thread::vm_tag_offset());
// Restore C++ ABI callee-saved registers.
if (TargetCPUFeatures::vfp_supported()) {
@@ -1901,10 +1890,9 @@
__ ldr(THR, Address(SP, 4)); // Thread.
__ mov(FP, Operand(R2)); // Frame_pointer.
__ mov(SP, Operand(IP)); // Set Stack pointer.
- __ LoadIsolate(R3);
// Set the tag.
__ LoadImmediate(R2, VMTag::kDartTagId);
- __ StoreToOffset(kWord, R2, R3, Isolate::vm_tag_offset());
+ __ StoreToOffset(kWord, R2, THR, Thread::vm_tag_offset());
// Clear top exit frame.
__ LoadImmediate(R2, 0);
__ StoreToOffset(kWord, R2, THR, Thread::top_exit_frame_info_offset());
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index 41d4544..facc08c 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -46,9 +46,6 @@
__ Comment("CallToRuntimeStub");
__ EnterStubFrame();
- COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R28)) != 0);
- __ LoadIsolate(R28);
-
// Save exit frame information to enable stack walking as we are about
// to transition to Dart VM C++ code.
__ StoreToOffset(FP, THR, Thread::top_exit_frame_info_offset());
@@ -56,7 +53,7 @@
#if defined(DEBUG)
{ Label ok;
// Check that we are always entering from Dart code.
- __ LoadFromOffset(R8, R28, Isolate::vm_tag_offset());
+ __ LoadFromOffset(R8, THR, Thread::vm_tag_offset());
__ CompareImmediate(R8, VMTag::kDartTagId);
__ b(&ok, EQ);
__ Stop("Not coming from Dart code.");
@@ -64,8 +61,8 @@
}
#endif
- // Mark that the isolate is executing VM code.
- __ StoreToOffset(R5, R28, Isolate::vm_tag_offset());
+ // Mark that the thread is executing VM code.
+ __ StoreToOffset(R5, THR, Thread::vm_tag_offset());
// Reserve space for arguments and align frame before entering C++ world.
// NativeArguments are passed in registers.
@@ -115,9 +112,9 @@
__ mov(CSP, R26);
// Retval is next to 1st argument.
- // Mark that the isolate is executing Dart code.
+ // Mark that the thread is executing Dart code.
__ LoadImmediate(R2, VMTag::kDartTagId);
- __ StoreToOffset(R2, R28, Isolate::vm_tag_offset());
+ __ StoreToOffset(R2, THR, Thread::vm_tag_offset());
// Reset exit frame information in Isolate structure.
__ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset());
@@ -153,9 +150,6 @@
__ EnterStubFrame();
- COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R28)) != 0);
- __ LoadIsolate(R28);
-
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
__ StoreToOffset(FP, THR, Thread::top_exit_frame_info_offset());
@@ -163,7 +157,7 @@
#if defined(DEBUG)
{ Label ok;
// Check that we are always entering from Dart code.
- __ LoadFromOffset(R6, R28, Isolate::vm_tag_offset());
+ __ LoadFromOffset(R6, THR, Thread::vm_tag_offset());
__ CompareImmediate(R6, VMTag::kDartTagId);
__ b(&ok, EQ);
__ Stop("Not coming from Dart code.");
@@ -171,8 +165,8 @@
}
#endif
- // Mark that the isolate is executing Native code.
- __ StoreToOffset(R5, R28, Isolate::vm_tag_offset());
+ // Mark that the thread is executing native code.
+ __ StoreToOffset(R5, THR, Thread::vm_tag_offset());
// Reserve space for the native arguments structure passed on the stack (the
// outgoing pointer parameter to the native arguments structure is passed in
@@ -223,9 +217,9 @@
__ mov(SP, CSP);
__ mov(CSP, R26);
- // Mark that the isolate is executing Dart code.
+ // Mark that the thread is executing Dart code.
__ LoadImmediate(R2, VMTag::kDartTagId);
- __ StoreToOffset(R2, R28, Isolate::vm_tag_offset());
+ __ StoreToOffset(R2, THR, Thread::vm_tag_offset());
// Reset exit frame information in Isolate structure.
__ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset());
@@ -249,9 +243,6 @@
__ EnterStubFrame();
- COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R28)) != 0);
- __ LoadIsolate(R28);
-
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
__ StoreToOffset(FP, THR, Thread::top_exit_frame_info_offset());
@@ -259,7 +250,7 @@
#if defined(DEBUG)
{ Label ok;
// Check that we are always entering from Dart code.
- __ LoadFromOffset(R6, R28, Isolate::vm_tag_offset());
+ __ LoadFromOffset(R6, THR, Thread::vm_tag_offset());
__ CompareImmediate(R6, VMTag::kDartTagId);
__ b(&ok, EQ);
__ Stop("Not coming from Dart code.");
@@ -267,8 +258,8 @@
}
#endif
- // Mark that the isolate is executing Native code.
- __ StoreToOffset(R5, R28, Isolate::vm_tag_offset());
+ // Mark that the thread is executing native code.
+ __ StoreToOffset(R5, THR, Thread::vm_tag_offset());
// Reserve space for the native arguments structure passed on the stack (the
// outgoing pointer parameter to the native arguments structure is passed in
@@ -316,9 +307,9 @@
__ mov(SP, CSP);
__ mov(CSP, R26);
- // Mark that the isolate is executing Dart code.
+ // Mark that the thread is executing Dart code.
__ LoadImmediate(R2, VMTag::kDartTagId);
- __ StoreToOffset(R2, R28, Isolate::vm_tag_offset());
+ __ StoreToOffset(R2, THR, Thread::vm_tag_offset());
// Reset exit frame information in Isolate structure.
__ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset());
@@ -821,16 +812,14 @@
if (THR != R3) {
__ mov(THR, R3);
}
- // Load Isolate pointer into temporary register R5.
- __ LoadIsolate(R5);
// Save the current VMTag on the stack.
- __ LoadFromOffset(R4, R5, Isolate::vm_tag_offset());
+ __ LoadFromOffset(R4, THR, Thread::vm_tag_offset());
__ Push(R4);
- // Mark that the isolate is executing Dart code.
+ // Mark that the thread is executing Dart code.
__ LoadImmediate(R6, VMTag::kDartTagId);
- __ StoreToOffset(R6, R5, Isolate::vm_tag_offset());
+ __ StoreToOffset(R6, THR, Thread::vm_tag_offset());
// Save top resource and top exit frame info. Use R6 as a temporary register.
// StackFrameIterator reads the top exit frame info saved in this frame.
@@ -883,8 +872,6 @@
// Get rid of arguments pushed on the stack.
__ AddImmediate(SP, FP, kExitLinkSlotFromEntryFp * kWordSize);
- __ LoadIsolate(R28);
-
// Restore the saved top exit frame info and top resource back into the
// Isolate structure. Uses R6 as a temporary register for this.
__ Pop(R6);
@@ -894,7 +881,7 @@
// Restore the current VMTag from the stack.
__ Pop(R4);
- __ StoreToOffset(R4, R28, Isolate::vm_tag_offset());
+ __ StoreToOffset(R4, THR, Thread::vm_tag_offset());
// Restore the bottom 64-bits of callee-saved V registers.
for (int i = kAbiLastPreservedFpuReg; i >= kAbiFirstPreservedFpuReg; i--) {
@@ -1973,10 +1960,9 @@
__ mov(R0, R3); // Exception object.
__ mov(R1, R4); // StackTrace object.
__ mov(THR, R5);
- __ LoadIsolate(R5);
// Set the tag.
__ LoadImmediate(R2, VMTag::kDartTagId);
- __ StoreToOffset(R2, R5, Isolate::vm_tag_offset());
+ __ StoreToOffset(R2, THR, Thread::vm_tag_offset());
// Clear top exit frame.
__ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset());
__ ret(); // Jump to the exception handler code.
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index f070b1b..8ca11ef 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -49,8 +49,6 @@
__ EnterFrame(0);
- __ LoadIsolate(EDI);
-
// Save exit frame information to enable stack walking as we are about
// to transition to Dart VM C++ code.
__ movl(Address(THR, Thread::top_exit_frame_info_offset()), EBP);
@@ -58,16 +56,15 @@
#if defined(DEBUG)
{ Label ok;
// Check that we are always entering from Dart code.
- __ cmpl(Address(EDI, Isolate::vm_tag_offset()),
- Immediate(VMTag::kDartTagId));
+ __ cmpl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
__ j(EQUAL, &ok, Assembler::kNearJump);
__ Stop("Not coming from Dart code.");
__ Bind(&ok);
}
#endif
- // Mark that the isolate is executing VM code.
- __ movl(Address(EDI, Isolate::vm_tag_offset()), ECX);
+ // Mark that the thread is executing VM code.
+ __ movl(Assembler::VMTagAddress(), ECX);
// Reserve space for arguments and align frame before entering C++ world.
__ AddImmediate(ESP, Immediate(-INT32_SIZEOF(NativeArguments)));
@@ -87,9 +84,7 @@
__ movl(Address(ESP, retval_offset), EAX); // Set retval in NativeArguments.
__ call(ECX);
- // Mark that the isolate is executing Dart code. EDI is callee saved.
- __ movl(Address(EDI, Isolate::vm_tag_offset()),
- Immediate(VMTag::kDartTagId));
+ __ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
// Reset exit frame information in Isolate structure.
__ movl(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
@@ -125,7 +120,6 @@
// EAX : address of first argument in argument array.
// ECX : address of the native function to call.
// EDX : argc_tag including number of arguments and function kind.
-// Uses EDI.
void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) {
const intptr_t native_args_struct_offset =
NativeEntry::kNumCallWrapperArguments * kWordSize;
@@ -140,7 +134,6 @@
__ EnterFrame(0);
- __ LoadIsolate(EDI);
// Save exit frame information to enable stack walking as we are about
// to transition to dart VM code.
@@ -149,16 +142,15 @@
#if defined(DEBUG)
{ Label ok;
// Check that we are always entering from Dart code.
- __ cmpl(Address(EDI, Isolate::vm_tag_offset()),
- Immediate(VMTag::kDartTagId));
+ __ cmpl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
__ j(EQUAL, &ok, Assembler::kNearJump);
__ Stop("Not coming from Dart code.");
__ Bind(&ok);
}
#endif
- // Mark that the isolate is executing Native code.
- __ movl(Address(EDI, Isolate::vm_tag_offset()), ECX);
+ // Mark that the thread is executing native code.
+ __ movl(Assembler::VMTagAddress(), ECX);
// Reserve space for the native arguments structure, the outgoing parameters
// (pointer to the native arguments structure, the C function entry point)
@@ -182,9 +174,7 @@
ExternalLabel label(NativeEntry::NativeCallWrapperEntry());
__ call(&label);
- // Mark that the isolate is executing Dart code. EDI is callee saved.
- __ movl(Address(EDI, Isolate::vm_tag_offset()),
- Immediate(VMTag::kDartTagId));
+ __ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
// Reset exit frame information in Isolate structure.
__ movl(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
@@ -200,7 +190,6 @@
// EAX : address of first argument in argument array.
// ECX : address of the native function to call.
// EDX : argc_tag including number of arguments and function kind.
-// Uses EDI.
void StubCode::GenerateCallBootstrapCFunctionStub(Assembler* assembler) {
const intptr_t native_args_struct_offset = kWordSize;
const intptr_t thread_offset =
@@ -214,8 +203,6 @@
__ EnterFrame(0);
- __ LoadIsolate(EDI);
-
// Save exit frame information to enable stack walking as we are about
// to transition to dart VM code.
__ movl(Address(THR, Thread::top_exit_frame_info_offset()), EBP);
@@ -223,16 +210,15 @@
#if defined(DEBUG)
{ Label ok;
// Check that we are always entering from Dart code.
- __ cmpl(Address(EDI, Isolate::vm_tag_offset()),
- Immediate(VMTag::kDartTagId));
+ __ cmpl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
__ j(EQUAL, &ok, Assembler::kNearJump);
__ Stop("Not coming from Dart code.");
__ Bind(&ok);
}
#endif
- // Mark that the isolate is executing Native code.
- __ movl(Address(EDI, Isolate::vm_tag_offset()), ECX);
+ // Mark that the thread is executing native code.
+ __ movl(Assembler::VMTagAddress(), ECX);
// Reserve space for the native arguments structure, the outgoing parameter
// (pointer to the native arguments structure) and align frame before
@@ -252,9 +238,7 @@
__ movl(Address(ESP, 0), EAX); // Pass the pointer to the NativeArguments.
__ call(ECX);
- // Mark that the isolate is executing Dart code. EDI is callee saved.
- __ movl(Address(EDI, Isolate::vm_tag_offset()),
- Immediate(VMTag::kDartTagId));
+ __ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
// Reset exit frame information in Isolate structure.
__ movl(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
@@ -721,15 +705,13 @@
// Set up THR, which caches the current thread in Dart code.
__ movl(THR, EAX);
- __ LoadIsolate(EDI);
// Save the current VMTag on the stack.
- __ movl(ECX, Address(EDI, Isolate::vm_tag_offset()));
+ __ movl(ECX, Assembler::VMTagAddress());
__ pushl(ECX);
- // Mark that the isolate is executing Dart code.
- __ movl(Address(EDI, Isolate::vm_tag_offset()),
- Immediate(VMTag::kDartTagId));
+ // Mark that the thread is executing Dart code.
+ __ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
// Save top resource and top exit frame info. Use EDX as a temporary register.
// StackFrameIterator reads the top exit frame info saved in this frame.
@@ -786,12 +768,11 @@
// Restore the saved top exit frame info and top resource back into the
// Isolate structure.
- __ LoadIsolate(EDI);
__ popl(Address(THR, Thread::top_exit_frame_info_offset()));
__ popl(Address(THR, Thread::top_resource_offset()));
// Restore the current VMTag from the stack.
- __ popl(Address(EDI, Isolate::vm_tag_offset()));
+ __ popl(Assembler::VMTagAddress());
// Restore C++ ABI callee-saved registers.
__ popl(EDI);
@@ -1897,11 +1878,8 @@
__ movl(EBP, Address(ESP, 3 * kWordSize)); // Load target frame_pointer.
__ movl(EBX, Address(ESP, 1 * kWordSize)); // Load target PC into EBX.
__ movl(ESP, Address(ESP, 2 * kWordSize)); // Load target stack_pointer.
- // TODO(koda): Pass thread instead of isolate.
- __ LoadIsolate(EDI);
// Set tag.
- __ movl(Address(EDI, Isolate::vm_tag_offset()),
- Immediate(VMTag::kDartTagId));
+ __ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
// Clear top exit frame.
__ movl(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
__ jmp(EBX); // Jump to the exception handler code.
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index 36f73f7..30a7cdf 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -46,9 +46,6 @@
__ Comment("CallToRuntimeStub");
__ EnterStubFrame();
- COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << S2)) != 0);
- __ LoadIsolate(S2);
-
// Save exit frame information to enable stack walking as we are about
// to transition to Dart VM C++ code.
__ sw(FP, Address(THR, Thread::top_exit_frame_info_offset()));
@@ -56,15 +53,15 @@
#if defined(DEBUG)
{ Label ok;
// Check that we are always entering from Dart code.
- __ lw(T0, Address(S2, Isolate::vm_tag_offset()));
+ __ lw(T0, Assembler::VMTagAddress());
__ BranchEqual(T0, Immediate(VMTag::kDartTagId), &ok);
__ Stop("Not coming from Dart code.");
__ Bind(&ok);
}
#endif
- // Mark that the isolate is executing VM code.
- __ sw(S5, Address(S2, Isolate::vm_tag_offset()));
+ // Mark that the thread is executing VM code.
+ __ sw(S5, Assembler::VMTagAddress());
// Reserve space for arguments and align frame before entering C++ world.
// NativeArguments are passed in registers.
@@ -101,9 +98,9 @@
__ delay_slot()->addiu(A3, A2, Immediate(kWordSize));
__ Comment("CallToRuntimeStub return");
- // Mark that the isolate is executing Dart code.
+ // Mark that the thread is executing Dart code.
__ LoadImmediate(A2, VMTag::kDartTagId);
- __ sw(A2, Address(S2, Isolate::vm_tag_offset()));
+ __ sw(A2, Assembler::VMTagAddress());
// Reset exit frame information in Isolate structure.
__ sw(ZR, Address(THR, Thread::top_exit_frame_info_offset()));
@@ -147,9 +144,6 @@
__ Comment("CallNativeCFunctionStub");
__ EnterStubFrame();
- COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << S2)) != 0);
- __ LoadIsolate(S2);
-
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
__ sw(FP, Address(THR, Thread::top_exit_frame_info_offset()));
@@ -157,15 +151,15 @@
#if defined(DEBUG)
{ Label ok;
// Check that we are always entering from Dart code.
- __ lw(T0, Address(S2, Isolate::vm_tag_offset()));
+ __ lw(T0, Assembler::VMTagAddress());
__ BranchEqual(T0, Immediate(VMTag::kDartTagId), &ok);
__ Stop("Not coming from Dart code.");
__ Bind(&ok);
}
#endif
- // Mark that the isolate is executing Native code.
- __ sw(T5, Address(S2, Isolate::vm_tag_offset()));
+ // Mark that the thread is executing native code.
+ __ sw(T5, Assembler::VMTagAddress());
// Initialize NativeArguments structure and call native function.
// Registers A0, A1, A2, and A3 are used.
@@ -205,9 +199,9 @@
__ jalr(T9);
__ Comment("CallNativeCFunctionStub return");
- // Mark that the isolate is executing Dart code.
+ // Mark that the thread is executing Dart code.
__ LoadImmediate(A2, VMTag::kDartTagId);
- __ sw(A2, Address(S2, Isolate::vm_tag_offset()));
+ __ sw(A2, Assembler::VMTagAddress());
// Reset exit frame information in Isolate structure.
__ sw(ZR, Address(THR, Thread::top_exit_frame_info_offset()));
@@ -232,9 +226,6 @@
__ Comment("CallNativeCFunctionStub");
__ EnterStubFrame();
- COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << S2)) != 0);
- __ LoadIsolate(S2);
-
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
__ sw(FP, Address(THR, Thread::top_exit_frame_info_offset()));
@@ -242,15 +233,15 @@
#if defined(DEBUG)
{ Label ok;
// Check that we are always entering from Dart code.
- __ lw(T0, Address(S2, Isolate::vm_tag_offset()));
+ __ lw(T0, Assembler::VMTagAddress());
__ BranchEqual(T0, Immediate(VMTag::kDartTagId), &ok);
__ Stop("Not coming from Dart code.");
__ Bind(&ok);
}
#endif
- // Mark that the isolate is executing Native code.
- __ sw(T5, Address(S2, Isolate::vm_tag_offset()));
+ // Mark that the thread is executing native code.
+ __ sw(T5, Assembler::VMTagAddress());
// Initialize NativeArguments structure and call native function.
// Registers A0, A1, A2, and A3 are used.
@@ -291,9 +282,9 @@
__ jalr(T9);
__ Comment("CallNativeCFunctionStub return");
- // Mark that the isolate is executing Dart code.
+ // Mark that the thread is executing Dart code.
__ LoadImmediate(A2, VMTag::kDartTagId);
- __ sw(A2, Address(S2, Isolate::vm_tag_offset()));
+ __ sw(A2, Assembler::VMTagAddress());
// Reset exit frame information in Isolate structure.
__ sw(ZR, Address(THR, Thread::top_exit_frame_info_offset()));
@@ -835,15 +826,14 @@
if (THR != A3) {
__ mov(THR, A3);
}
- __ LoadIsolate(T2);
// Save the current VMTag on the stack.
- __ lw(T1, Address(T2, Isolate::vm_tag_offset()));
+ __ lw(T1, Assembler::VMTagAddress());
__ sw(T1, Address(SP, 2 * kWordSize));
- // Mark that the isolate is executing Dart code.
+ // Mark that the thread is executing Dart code.
__ LoadImmediate(T0, VMTag::kDartTagId);
- __ sw(T0, Address(T2, Isolate::vm_tag_offset()));
+ __ sw(T0, Assembler::VMTagAddress());
// Save top resource and top exit frame info. Use T0 as a temporary register.
// StackFrameIterator reads the top exit frame info saved in this frame.
@@ -896,11 +886,10 @@
// Get rid of arguments pushed on the stack.
__ AddImmediate(SP, FP, kExitLinkSlotFromEntryFp * kWordSize);
- __ LoadIsolate(S2);
// Restore the current VMTag from the stack.
__ lw(T1, Address(SP, 2 * kWordSize));
- __ sw(T1, Address(S2, Isolate::vm_tag_offset()));
+ __ sw(T1, Assembler::VMTagAddress());
// Restore the saved top resource and top exit frame info back into the
// Isolate structure. Uses T0 as a temporary register for this.
@@ -2048,10 +2037,9 @@
__ lw(V1, Address(SP, 4 * kWordSize)); // StackTrace object.
__ mov(FP, A2); // Frame_pointer.
__ lw(THR, Address(SP, 5 * kWordSize)); // Thread.
- __ LoadIsolate(A3);
// Set tag.
__ LoadImmediate(A2, VMTag::kDartTagId);
- __ sw(A2, Address(A3, Isolate::vm_tag_offset()));
+ __ sw(A2, Assembler::VMTagAddress());
// Clear top exit frame.
__ sw(ZR, Address(THR, Thread::top_exit_frame_info_offset()));
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 7b4561d..44d5f96 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -46,10 +46,6 @@
__ EnterStubFrame();
- COMPILE_ASSERT(
- (CallingConventions::kCalleeSaveCpuRegisters & (1 << R12)) != 0);
- __ LoadIsolate(R12);
-
// Save exit frame information to enable stack walking as we are about
// to transition to Dart VM C++ code.
__ movq(Address(THR, Thread::top_exit_frame_info_offset()), RBP);
@@ -58,15 +54,15 @@
{ Label ok;
// Check that we are always entering from Dart code.
__ movq(RAX, Immediate(VMTag::kDartTagId));
- __ cmpq(RAX, Address(R12, Isolate::vm_tag_offset()));
+ __ cmpq(RAX, Assembler::VMTagAddress());
__ j(EQUAL, &ok, Assembler::kNearJump);
__ Stop("Not coming from Dart code.");
__ Bind(&ok);
}
#endif
- // Mark that the isolate is executing VM code.
- __ movq(Address(R12, Isolate::vm_tag_offset()), RBX);
+ // Mark that the thread is executing VM code.
+ __ movq(Assembler::VMTagAddress(), RBX);
// Reserve space for arguments and align frame before entering C++ world.
__ subq(RSP, Immediate(sizeof(NativeArguments)));
@@ -90,9 +86,8 @@
#endif
__ CallCFunction(RBX);
- // Mark that the isolate is executing Dart code.
- __ movq(Address(R12, Isolate::vm_tag_offset()),
- Immediate(VMTag::kDartTagId));
+ // Mark that the thread is executing Dart code.
+ __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
// Reset exit frame information in Isolate structure.
__ movq(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
@@ -144,10 +139,6 @@
__ EnterStubFrame();
- COMPILE_ASSERT(
- (CallingConventions::kCalleeSaveCpuRegisters & (1 << R12)) != 0);
- __ LoadIsolate(R12);
-
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
__ movq(Address(THR, Thread::top_exit_frame_info_offset()), RBP);
@@ -156,15 +147,15 @@
{ Label ok;
// Check that we are always entering from Dart code.
__ movq(R8, Immediate(VMTag::kDartTagId));
- __ cmpq(R8, Address(R12, Isolate::vm_tag_offset()));
+ __ cmpq(R8, Assembler::VMTagAddress());
__ j(EQUAL, &ok, Assembler::kNearJump);
__ Stop("Not coming from Dart code.");
__ Bind(&ok);
}
#endif
- // Mark that the isolate is executing Native code.
- __ movq(Address(R12, Isolate::vm_tag_offset()), RBX);
+ // Mark that the thread is executing native code.
+ __ movq(Assembler::VMTagAddress(), RBX);
// Reserve space for the native arguments structure passed on the stack (the
// outgoing pointer parameter to the native arguments structure is passed in
@@ -189,9 +180,8 @@
__ movq(RAX, Address(THR, Thread::native_call_wrapper_entry_point_offset()));
__ CallCFunction(RAX);
- // Mark that the isolate is executing Dart code.
- __ movq(Address(R12, Isolate::vm_tag_offset()),
- Immediate(VMTag::kDartTagId));
+ // Mark that the thread is executing Dart code.
+ __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
// Reset exit frame information in Isolate structure.
__ movq(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
@@ -220,10 +210,6 @@
__ EnterStubFrame();
- COMPILE_ASSERT(
- (CallingConventions::kCalleeSaveCpuRegisters & (1 << R12)) != 0);
- __ LoadIsolate(R12);
-
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
__ movq(Address(THR, Thread::top_exit_frame_info_offset()), RBP);
@@ -232,15 +218,15 @@
{ Label ok;
// Check that we are always entering from Dart code.
__ movq(R8, Immediate(VMTag::kDartTagId));
- __ cmpq(R8, Address(R12, Isolate::vm_tag_offset()));
+ __ cmpq(R8, Assembler::VMTagAddress());
__ j(EQUAL, &ok, Assembler::kNearJump);
__ Stop("Not coming from Dart code.");
__ Bind(&ok);
}
#endif
- // Mark that the isolate is executing Native code.
- __ movq(Address(R12, Isolate::vm_tag_offset()), RBX);
+ // Mark that the thread is executing native code.
+ __ movq(Assembler::VMTagAddress(), RBX);
// Reserve space for the native arguments structure passed on the stack (the
// outgoing pointer parameter to the native arguments structure is passed in
@@ -261,9 +247,8 @@
__ movq(CallingConventions::kArg1Reg, RSP);
__ CallCFunction(RBX);
- // Mark that the isolate is executing Dart code.
- __ movq(Address(R12, Isolate::vm_tag_offset()),
- Immediate(VMTag::kDartTagId));
+ // Mark that the thread is executing Dart code.
+ __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
// Reset exit frame information in Isolate structure.
__ movq(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
@@ -753,17 +738,13 @@
if (THR != kThreadReg) {
__ movq(THR, kThreadReg);
}
- // Load Isolate pointer into kIsolateReg.
- const Register kIsolateReg = RBX;
- __ LoadIsolate(kIsolateReg);
// Save the current VMTag on the stack.
- __ movq(RAX, Address(kIsolateReg, Isolate::vm_tag_offset()));
+ __ movq(RAX, Assembler::VMTagAddress());
__ pushq(RAX);
- // Mark that the isolate is executing Dart code.
- __ movq(Address(kIsolateReg, Isolate::vm_tag_offset()),
- Immediate(VMTag::kDartTagId));
+ // Mark that the thread is executing Dart code.
+ __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
// Save top resource and top exit frame info. Use RAX as a temporary register.
// StackFrameIterator reads the top exit frame info saved in this frame.
@@ -833,12 +814,11 @@
// Restore the saved top exit frame info and top resource back into the
// Isolate structure.
- __ LoadIsolate(kIsolateReg);
__ popq(Address(THR, Thread::top_exit_frame_info_offset()));
__ popq(Address(THR, Thread::top_resource_offset()));
// Restore the current VMTag from the stack.
- __ popq(Address(kIsolateReg, Isolate::vm_tag_offset()));
+ __ popq(Assembler::VMTagAddress());
// Restore C++ ABI callee-saved registers.
__ PopRegisters(CallingConventions::kCalleeSaveCpuRegisters,
@@ -1961,20 +1941,16 @@
Register stacktrace_reg = RBX;
__ movq(stacktrace_reg, Address(RSP, 5 * kWordSize));
__ movq(THR, Address(RSP, 6 * kWordSize));
- Register isolate_reg = RDI;
#else
Register stacktrace_reg = CallingConventions::kArg5Reg;
__ movq(THR, CallingConventions::kArg6Reg);
- Register isolate_reg = CallingConventions::kArg6Reg;
#endif
- __ LoadIsolate(isolate_reg);
__ movq(RBP, CallingConventions::kArg3Reg);
__ movq(RSP, CallingConventions::kArg2Reg);
__ movq(kStackTraceObjectReg, stacktrace_reg);
__ movq(kExceptionObjectReg, CallingConventions::kArg4Reg);
// Set the tag.
- __ movq(Address(isolate_reg, Isolate::vm_tag_offset()),
- Immediate(VMTag::kDartTagId));
+ __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
// Clear top exit frame.
__ movq(Address(THR, Thread::top_exit_frame_info_offset()),
Immediate(0));
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index c9fdbd4..d59ea20a 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -343,7 +343,7 @@
V(DartIsolate, "dart:isolate") \
V(DartMirrors, "dart:mirrors") \
V(DartTypedData, "dart:typed_data") \
- V(DartVMService, "dart:vmservice") \
+ V(DartVMService, "dart:_vmservice") \
V(DartIOLibName, "dart.io") \
V(EvalSourceUri, "evaluate:source") \
V(_Random, "_Random") \
diff --git a/runtime/vm/tags.cc b/runtime/vm/tags.cc
index 4224a22..4349844 100644
--- a/runtime/vm/tags.cc
+++ b/runtime/vm/tags.cc
@@ -84,16 +84,16 @@
VMTagScope::VMTagScope(Thread* thread, uword tag, bool conditional_set)
: StackResource(thread) {
ASSERT(isolate() != NULL);
- previous_tag_ = isolate()->vm_tag();
+ previous_tag_ = thread->vm_tag();
if (conditional_set) {
- isolate()->set_vm_tag(tag);
+ thread->set_vm_tag(tag);
}
}
VMTagScope::~VMTagScope() {
ASSERT(isolate() != NULL);
- isolate()->set_vm_tag(previous_tag_);
+ thread()->set_vm_tag(previous_tag_);
}
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index eff0922..0828f40 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -113,7 +113,8 @@
isolate_(NULL),
heap_(NULL),
store_buffer_block_(NULL),
- log_(new class Log()) {
+ log_(new class Log()),
+ vm_tag_(0) {
ClearState();
#define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value) \
@@ -188,7 +189,7 @@
ASSERT(!isolate->HasMutatorThread());
thread->isolate_ = isolate;
isolate->MakeCurrentThreadMutator(thread);
- isolate->set_vm_tag(VMTag::kVMTagId);
+ thread->set_vm_tag(VMTag::kVMTagId);
ASSERT(thread->store_buffer_block_ == NULL);
thread->StoreBufferAcquire();
ASSERT(isolate->heap() != NULL);
@@ -209,9 +210,9 @@
// TODO(koda): Move store_buffer_block_ into State.
thread->StoreBufferRelease();
if (isolate->is_runnable()) {
- isolate->set_vm_tag(VMTag::kIdleTagId);
+ thread->set_vm_tag(VMTag::kIdleTagId);
} else {
- isolate->set_vm_tag(VMTag::kLoadWaitTagId);
+ thread->set_vm_tag(VMTag::kLoadWaitTagId);
}
isolate->ClearMutatorThread();
thread->isolate_ = NULL;
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 00f601f..1a7d48f 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -282,6 +282,16 @@
state_.long_jump_base = value;
}
+ uword vm_tag() const {
+ return vm_tag_;
+ }
+ void set_vm_tag(uword tag) {
+ vm_tag_ = tag;
+ }
+ static intptr_t vm_tag_offset() {
+ return OFFSET_OF(Thread, vm_tag_);
+ }
+
ThreadId id() const {
ASSERT(id_ != OSThread::kInvalidThreadId);
return id_;
@@ -304,6 +314,7 @@
Mutex timeline_block_lock_;
StoreBufferBlock* store_buffer_block_;
class Log* log_;
+ uword vm_tag_;
#define DECLARE_MEMBERS(type_name, member_name, expr, default_init_value) \
type_name member_name;
CACHED_CONSTANTS_LIST(DECLARE_MEMBERS)
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index d55a8dc..1a8536a 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -479,6 +479,36 @@
}
+DartTimelineEvent::DartTimelineEvent()
+ : isolate_(NULL),
+ event_as_json_(NULL) {
+}
+
+
+DartTimelineEvent::~DartTimelineEvent() {
+ Clear();
+}
+
+
+void DartTimelineEvent::Clear() {
+ if (isolate_ != NULL) {
+ isolate_ = NULL;
+ }
+ if (event_as_json_ != NULL) {
+ free(event_as_json_);
+ event_as_json_ = NULL;
+ }
+}
+
+
+void DartTimelineEvent::Init(Isolate* isolate, const char* event) {
+ ASSERT(isolate_ == NULL);
+ ASSERT(event != NULL);
+ isolate_ = isolate;
+ event_as_json_ = strdup(event);
+}
+
+
TimelineEventRecorder::TimelineEventRecorder()
: global_block_(NULL),
async_id_(0) {
@@ -550,6 +580,21 @@
}
+// Trims the ']' character.
+static void TrimOutput(char* output,
+ intptr_t* output_length) {
+ ASSERT(output != NULL);
+ ASSERT(output_length != NULL);
+ ASSERT(*output_length >= 2);
+ // We expect the first character to be the opening of an array.
+ ASSERT(output[0] == '[');
+ // We expect the last character to be the closing of an array.
+ ASSERT(output[*output_length - 1] == ']');
+ // Skip the ].
+ *output_length -= 1;
+}
+
+
void TimelineEventRecorder::WriteTo(const char* directory) {
Dart_FileOpenCallback file_open = Isolate::file_open_callback();
Dart_FileWriteCallback file_write = Isolate::file_write_callback();
@@ -557,13 +602,11 @@
if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) {
return;
}
+ Thread* T = Thread::Current();
+ StackZone zone(T);
Timeline::ReclaimAllBlocks();
- JSONStream js;
- TimelineEventFilter filter;
- PrintJSON(&js, &filter);
-
intptr_t pid = OS::ProcessId();
char* filename = OS::SCreate(NULL,
"%s/dart-timeline-%" Pd ".json", directory, pid);
@@ -574,8 +617,43 @@
return;
}
free(filename);
- (*file_write)(js.buffer()->buf(), js.buffer()->length(), file);
+
+ JSONStream js;
+ TimelineEventFilter filter;
+ PrintTraceEvent(&js, &filter);
+ // Steal output from JSONStream.
+ char* output = NULL;
+ intptr_t output_length = 0;
+ js.Steal(const_cast<const char**>(&output), &output_length);
+ TrimOutput(output, &output_length);
+ ASSERT(output_length >= 1);
+ (*file_write)(output, output_length, file);
+ // Free the stolen output.
+ free(output);
+
+ const char* dart_events =
+ DartTimelineEventIterator::PrintTraceEvents(this,
+ zone.GetZone(),
+ NULL);
+
+ // If we wrote out vm events and have dart events, write out the comma.
+ if ((output_length > 1) && (dart_events != NULL)) {
+ // Write out the ',' character.
+ const char* comma = ",";
+ (*file_write)(comma, 1, file);
+ }
+
+ // Write out the Dart events.
+ if (dart_events != NULL) {
+ (*file_write)(dart_events, strlen(dart_events), file);
+ }
+
+ // Write out the ']' character.
+ const char* array_close = "]";
+ (*file_write)(array_close, 1, file);
(*file_close)(file);
+
+ return;
}
@@ -615,7 +693,10 @@
: blocks_(NULL),
capacity_(capacity),
num_blocks_(0),
- block_cursor_(0) {
+ block_cursor_(0),
+ dart_events_(NULL),
+ dart_events_capacity_(capacity),
+ dart_events_cursor_(0) {
// Capacity must be a multiple of TimelineEventBlock::kBlockSize
ASSERT((capacity % TimelineEventBlock::kBlockSize) == 0);
// Allocate blocks array.
@@ -631,6 +712,13 @@
for (intptr_t i = 0; i < num_blocks_ - 1; i++) {
blocks_[i]->set_next(blocks_[i + 1]);
}
+ // Pre-allocate DartTimelineEvents.
+ dart_events_ =
+ reinterpret_cast<DartTimelineEvent**>(
+ calloc(dart_events_capacity_, sizeof(DartTimelineEvent*)));
+ for (intptr_t i = 0; i < dart_events_capacity_; i++) {
+ dart_events_[i] = new DartTimelineEvent();
+ }
}
@@ -641,6 +729,12 @@
delete block;
}
free(blocks_);
+ // Delete all DartTimelineEvents.
+ for (intptr_t i = 0; i < dart_events_capacity_; i++) {
+ DartTimelineEvent* event = dart_events_[i];
+ delete event;
+ }
+ free(dart_events_);
}
@@ -681,6 +775,33 @@
}
+void TimelineEventRingRecorder::AppendDartEvent(Isolate* isolate,
+ const char* event) {
+ MutexLocker ml(&lock_);
+ // TODO(johnmccutchan): If locking becomes an issue, use the Isolate to store
+ // the events.
+ if (dart_events_cursor_ == dart_events_capacity_) {
+ dart_events_cursor_ = 0;
+ }
+ ASSERT(dart_events_[dart_events_cursor_] != NULL);
+ dart_events_[dart_events_cursor_]->Clear();
+ dart_events_[dart_events_cursor_]->Init(isolate, event);
+ dart_events_cursor_++;
+}
+
+
+intptr_t TimelineEventRingRecorder::NumDartEventsLocked() {
+ return dart_events_capacity_;
+}
+
+
+DartTimelineEvent* TimelineEventRingRecorder::DartEventAtLocked(intptr_t i) {
+ ASSERT(i >= 0);
+ ASSERT(i < dart_events_capacity_);
+ return dart_events_[i];
+}
+
+
void TimelineEventRingRecorder::PrintTraceEvent(JSONStream* js,
TimelineEventFilter* filter) {
JSONArray events(js);
@@ -761,6 +882,25 @@
}
+void TimelineEventStreamingRecorder::AppendDartEvent(Isolate* isolate,
+ const char* event) {
+ if (event != NULL) {
+ StreamDartEvent(event);
+ }
+}
+
+
+intptr_t TimelineEventStreamingRecorder::NumDartEventsLocked() {
+ return 0;
+}
+
+
+DartTimelineEvent* TimelineEventStreamingRecorder::DartEventAtLocked(
+ intptr_t i) {
+ return NULL;
+}
+
+
TimelineEvent* TimelineEventStreamingRecorder::StartEvent() {
TimelineEvent* event = new TimelineEvent();
return event;
@@ -775,7 +915,10 @@
TimelineEventEndlessRecorder::TimelineEventEndlessRecorder()
: head_(NULL),
- block_index_(0) {
+ block_index_(0),
+ dart_events_(NULL),
+ dart_events_capacity_(0),
+ dart_events_cursor_(0) {
}
@@ -800,6 +943,31 @@
}
+void TimelineEventEndlessRecorder::AppendDartEvent(Isolate* isolate,
+ const char* event) {
+ MutexLocker ml(&lock_);
+ // TODO(johnmccutchan): If locking becomes an issue, use the Isolate to store
+ // the events.
+ if (dart_events_cursor_ == dart_events_capacity_) {
+ // Grow.
+ intptr_t new_capacity =
+ (dart_events_capacity_ == 0) ? 16 : dart_events_capacity_ * 2;
+ dart_events_ = reinterpret_cast<DartTimelineEvent**>(
+ realloc(dart_events_, new_capacity * sizeof(DartTimelineEvent*)));
+ for (intptr_t i = dart_events_capacity_; i < new_capacity; i++) {
+ // Fill with NULLs.
+ dart_events_[i] = NULL;
+ }
+ dart_events_capacity_ = new_capacity;
+ }
+ ASSERT(dart_events_cursor_ < dart_events_capacity_);
+ DartTimelineEvent* dart_event = new DartTimelineEvent();
+ dart_event->Init(isolate, event);
+ ASSERT(dart_events_[dart_events_cursor_] == NULL);
+ dart_events_[dart_events_cursor_++] = dart_event;
+}
+
+
TimelineEventBlock* TimelineEventEndlessRecorder::GetHeadBlockLocked() {
return head_;
}
@@ -833,6 +1001,19 @@
}
+intptr_t TimelineEventEndlessRecorder::NumDartEventsLocked() {
+ return dart_events_cursor_;
+}
+
+
+DartTimelineEvent* TimelineEventEndlessRecorder::DartEventAtLocked(
+ intptr_t i) {
+ ASSERT(i >= 0);
+ ASSERT(i < dart_events_cursor_);
+ return dart_events_[i];
+}
+
+
void TimelineEventEndlessRecorder::PrintJSONEvents(
JSONArray* events,
TimelineEventFilter* filter) const {
@@ -1000,4 +1181,80 @@
return r;
}
+
+DartTimelineEventIterator::DartTimelineEventIterator(
+ TimelineEventRecorder* recorder)
+ : cursor_(0),
+ num_events_(0),
+ recorder_(NULL) {
+ Reset(recorder);
+}
+
+
+DartTimelineEventIterator::~DartTimelineEventIterator() {
+ Reset(NULL);
+}
+
+
+void DartTimelineEventIterator::Reset(TimelineEventRecorder* recorder) {
+ // Clear state.
+ cursor_ = 0;
+ num_events_ = 0;
+ if (recorder_ != NULL) {
+ // Unlock old recorder.
+ recorder_->lock_.Unlock();
+ }
+ recorder_ = recorder;
+ if (recorder_ == NULL) {
+ return;
+ }
+ // Lock new recorder.
+ recorder_->lock_.Lock();
+ cursor_ = 0;
+ num_events_ = recorder_->NumDartEventsLocked();
+}
+
+
+bool DartTimelineEventIterator::HasNext() const {
+ return cursor_ < num_events_;
+}
+
+
+DartTimelineEvent* DartTimelineEventIterator::Next() {
+ ASSERT(cursor_ < num_events_);
+ DartTimelineEvent* r = recorder_->DartEventAtLocked(cursor_);
+ cursor_++;
+ return r;
+}
+
+const char* DartTimelineEventIterator::PrintTraceEvents(
+ TimelineEventRecorder* recorder,
+ Zone* zone,
+ Isolate* isolate) {
+ if (recorder == NULL) {
+ return NULL;
+ }
+
+ if (zone == NULL) {
+ return NULL;
+ }
+
+ char* result = NULL;
+ DartTimelineEventIterator iterator(recorder);
+ while (iterator.HasNext()) {
+ DartTimelineEvent* event = iterator.Next();
+ if (!event->IsValid()) {
+ // Skip invalid
+ continue;
+ }
+ if ((isolate != NULL) && (isolate != event->isolate())) {
+ // If an isolate was specified, skip events from other isolates.
+ continue;
+ }
+ ASSERT(event->event_as_json() != NULL);
+ result = zone->ConcatStrings(result, event->event_as_json());
+ }
+ return result;
+}
+
} // namespace dart
diff --git a/runtime/vm/timeline.h b/runtime/vm/timeline.h
index 669652b..962a207 100644
--- a/runtime/vm/timeline.h
+++ b/runtime/vm/timeline.h
@@ -15,17 +15,20 @@
class JSONStream;
class Object;
class ObjectPointerVisitor;
+class Isolate;
class RawArray;
class Thread;
class TimelineEvent;
class TimelineEventBlock;
class TimelineEventRecorder;
class TimelineStream;
+class Zone;
// (name, enabled by default for isolate).
#define ISOLATE_TIMELINE_STREAM_LIST(V) \
V(API, false) \
V(Compiler, false) \
+ V(Dart, false) \
V(Embedder, false) \
V(GC, false) \
V(Isolate, false) \
@@ -204,6 +207,8 @@
void Init(EventType event_type, const char* label);
void set_event_type(EventType event_type) {
+ // We only reserve 4 bits to hold the event type.
+ COMPILE_ASSERT(kNumEventTypes < 16);
state_ = EventTypeField::update(event_type, state_);
}
@@ -480,6 +485,39 @@
};
+// Timeline events from Dart code are eagerly converted to JSON and stored
+// as a C string.
+class DartTimelineEvent {
+ public:
+ DartTimelineEvent();
+ ~DartTimelineEvent();
+
+ void Clear();
+
+ // This function makes a copy of |event|.
+ void Init(Isolate* isolate, const char* event);
+
+ bool IsValid() const {
+ return (isolate_ != NULL) &&
+ (event_as_json_ != NULL);
+ }
+
+ Isolate* isolate() const {
+ return isolate_;
+ }
+
+ char* event_as_json() const {
+ return event_as_json_;
+ }
+
+ private:
+ Isolate* isolate_;
+ char* event_as_json_;
+
+ DISALLOW_COPY_AND_ASSIGN(DartTimelineEvent);
+};
+
+
// Recorder of |TimelineEvent|s.
class TimelineEventRecorder {
public:
@@ -496,6 +534,9 @@
void FinishBlock(TimelineEventBlock* block);
+ // Interface method(s) which must be implemented.
+ virtual void AppendDartEvent(Isolate* isolate, const char* event) = 0;
+
protected:
void WriteTo(const char* directory);
@@ -504,6 +545,8 @@
virtual void CompleteEvent(TimelineEvent* event) = 0;
virtual TimelineEventBlock* GetHeadBlockLocked() = 0;
virtual TimelineEventBlock* GetNewBlockLocked(Isolate* isolate) = 0;
+ virtual intptr_t NumDartEventsLocked() = 0;
+ virtual DartTimelineEvent* DartEventAtLocked(intptr_t i) = 0;
// Utility method(s).
void PrintJSONMeta(JSONArray* array) const;
@@ -517,6 +560,7 @@
uintptr_t async_id_;
+ friend class DartTimelineEventIterator;
friend class TimelineEvent;
friend class TimelineEventBlockIterator;
friend class TimelineStream;
@@ -539,12 +583,16 @@
void PrintJSON(JSONStream* js, TimelineEventFilter* filter);
void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter);
+ void AppendDartEvent(Isolate* isolate, const char* event);
+
protected:
TimelineEvent* StartEvent();
void CompleteEvent(TimelineEvent* event);
TimelineEventBlock* GetHeadBlockLocked();
intptr_t FindOldestBlockIndex() const;
TimelineEventBlock* GetNewBlockLocked(Isolate* isolate);
+ intptr_t NumDartEventsLocked();
+ DartTimelineEvent* DartEventAtLocked(intptr_t i);
void PrintJSONEvents(JSONArray* array, TimelineEventFilter* filter) const;
@@ -552,6 +600,10 @@
intptr_t capacity_;
intptr_t num_blocks_;
intptr_t block_cursor_;
+
+ DartTimelineEvent** dart_events_;
+ intptr_t dart_events_capacity_;
+ intptr_t dart_events_cursor_;
};
@@ -564,9 +616,12 @@
void PrintJSON(JSONStream* js, TimelineEventFilter* filter);
void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter);
+ void AppendDartEvent(Isolate* isolate, const char* event);
+
// Called when |event| is ready to be streamed. It is unsafe to keep a
// reference to |event| as it may be freed as soon as this function returns.
virtual void StreamEvent(TimelineEvent* event) = 0;
+ virtual void StreamDartEvent(const char* event) = 0;
protected:
TimelineEventBlock* GetNewBlockLocked(Isolate* isolate) {
@@ -575,6 +630,8 @@
TimelineEventBlock* GetHeadBlockLocked() {
return NULL;
}
+ intptr_t NumDartEventsLocked();
+ DartTimelineEvent* DartEventAtLocked(intptr_t i);
TimelineEvent* StartEvent();
void CompleteEvent(TimelineEvent* event);
};
@@ -590,11 +647,15 @@
void PrintJSON(JSONStream* js, TimelineEventFilter* filter);
void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter);
+ void AppendDartEvent(Isolate* isolate, const char* event);
+
protected:
TimelineEvent* StartEvent();
void CompleteEvent(TimelineEvent* event);
TimelineEventBlock* GetNewBlockLocked(Isolate* isolate);
TimelineEventBlock* GetHeadBlockLocked();
+ intptr_t NumDartEventsLocked();
+ DartTimelineEvent* DartEventAtLocked(intptr_t i);
void PrintJSONEvents(JSONArray* array, TimelineEventFilter* filter) const;
@@ -604,6 +665,10 @@
TimelineEventBlock* head_;
intptr_t block_index_;
+ DartTimelineEvent** dart_events_;
+ intptr_t dart_events_capacity_;
+ intptr_t dart_events_cursor_;
+
friend class TimelineTestHelper;
};
@@ -627,6 +692,33 @@
TimelineEventRecorder* recorder_;
};
+
+// An iterator for timeline events.
+class DartTimelineEventIterator {
+ public:
+ explicit DartTimelineEventIterator(TimelineEventRecorder* recorder);
+ ~DartTimelineEventIterator();
+
+ void Reset(TimelineEventRecorder* recorder);
+
+ // Returns true if there is another event.
+ bool HasNext() const;
+
+ // Returns the next event and moves forward.
+ DartTimelineEvent* Next();
+
+ // Returns a zone allocated string of all trace events for isolate.
+ // If isolate is NULL, all isolates' events will be included.
+ static const char* PrintTraceEvents(TimelineEventRecorder* recorder,
+ Zone* zone,
+ Isolate* isolate);
+
+ private:
+ intptr_t cursor_;
+ intptr_t num_events_;
+ TimelineEventRecorder* recorder_;
+};
+
} // namespace dart
#endif // VM_TIMELINE_H_
diff --git a/runtime/vm/timeline_test.cc b/runtime/vm/timeline_test.cc
index e023e28..617e8fe 100644
--- a/runtime/vm/timeline_test.cc
+++ b/runtime/vm/timeline_test.cc
@@ -216,6 +216,10 @@
counts_[event->event_type()]++;
}
+ void StreamDartEvent(const char* event) {
+ // NOOP.
+ }
+
intptr_t CountFor(TimelineEvent::EventType type) {
return counts_[type];
}
diff --git a/runtime/vm/timer.cc b/runtime/vm/timer.cc
index a0b8707c..5b76b48 100644
--- a/runtime/vm/timer.cc
+++ b/runtime/vm/timer.cc
@@ -8,50 +8,6 @@
namespace dart {
-// Define timer command line flags.
-#define DEFINE_TIMER_FLAG(name, msg) \
- DEFINE_FLAG(bool, name, false, ""#name);
-TIMER_LIST(DEFINE_TIMER_FLAG)
-#undef DEFINE_TIMER_FLAG
-DEFINE_FLAG(bool, time_all, false, "Time all functionality");
-// Maintains a list of timers per isolate.
-#define INIT_TIMERS(name, msg) \
- name##_((FLAG_##name || FLAG_time_all), msg),
-TimerList::TimerList()
- : TIMER_LIST(INIT_TIMERS)
- padding_(false) {
-}
-#undef INIT_TIMERS
-
-
-#define TIMER_FIELD_REPORT(name, msg) \
- if (name().report() && name().message() != NULL) { \
- OS::Print("%s : %.3f ms total; %.3f ms max.\n", \
- name().message(), \
- MicrosecondsToMilliseconds(name().TotalElapsedTime()), \
- MicrosecondsToMilliseconds(name().MaxContiguous())); \
- }
-void TimerList::ReportTimers() {
- TIMER_LIST(TIMER_FIELD_REPORT);
-}
-#undef TIMER_FIELD_REPORT
-
-
-#define JSON_TIMER(name, msg) \
- { \
- JSONObject jsobj(&jsarr); \
- jsobj.AddProperty("name", #name); \
- jsobj.AddProperty("time", \
- MicrosecondsToSeconds(name().TotalElapsedTime())); \
- jsobj.AddProperty("max_contiguous", \
- MicrosecondsToSeconds(name().MaxContiguous())); \
- }
-void TimerList::PrintTimersToJSONProperty(JSONObject* jsobj) {
- JSONArray jsarr(jsobj, "timers");
- TIMER_LIST(JSON_TIMER);
-}
-#undef JSON_TIMER
-
} // namespace dart
diff --git a/runtime/vm/timer.h b/runtime/vm/timer.h
index 32af994..4738efa 100644
--- a/runtime/vm/timer.h
+++ b/runtime/vm/timer.h
@@ -90,41 +90,6 @@
DISALLOW_COPY_AND_ASSIGN(Timer);
};
-// List of per isolate timers.
-#define TIMER_LIST(V) \
- V(time_script_loading, "Script Loading") \
- V(time_creating_snapshot, "Snapshot Creation") \
- V(time_isolate_initialization, "Isolate initialization") \
- V(time_compilation, "Function compilation") \
- V(time_bootstrap, "Bootstrap of core classes") \
- V(time_dart_execution, "Dart execution") \
- V(time_total_runtime, "Total runtime for isolate") \
- V(time_gc, "Garbage collection") \
-
-// Maintains a list of timers per isolate.
-class TimerList : public ValueObject {
- public:
- TimerList();
- ~TimerList() {}
-
- // Accessors.
-#define TIMER_FIELD_ACCESSOR(name, msg) \
- Timer& name() { return name##_; }
- TIMER_LIST(TIMER_FIELD_ACCESSOR)
-#undef TIMER_FIELD_ACCESSOR
-
- void ReportTimers();
-
- void PrintTimersToJSONProperty(JSONObject* jsobj);
-
- private:
-#define TIMER_FIELD(name, msg) Timer name##_;
- TIMER_LIST(TIMER_FIELD)
-#undef TIMER_FIELD
- bool padding_;
- DISALLOW_COPY_AND_ASSIGN(TimerList);
-};
-
// The class TimerScope is used to start and stop a timer within a scope.
// It is used as follows:
@@ -207,21 +172,6 @@
};
-// Macros to deal with named timers in the isolate.
-#define START_TIMER(isolate, name) \
-isolate->timer_list().name().Start();
-
-#define STOP_TIMER(isolate, name) \
-isolate->timer_list().name().Stop();
-
-#define TIMERSCOPE(thread, name) \
- TimerScope vm_internal_timer_( \
- true, &(thread->isolate()->timer_list().name()), thread)
-
-#define PAUSETIMERSCOPE(thread, name) \
-PauseTimerScope vm_internal_timer_(true, \
- &(thread->isolate()->timer_list().name()), \
- thread)
} // namespace dart
diff --git a/runtime/vm/vm.gypi b/runtime/vm/vm.gypi
index e298592..4397f96 100644
--- a/runtime/vm/vm.gypi
+++ b/runtime/vm/vm.gypi
@@ -26,30 +26,23 @@
'mirrors_cc_file': '<(gen_source_dir)/mirrors_gen.cc',
'mirrors_patch_cc_file': '<(gen_source_dir)/mirrors_patch_gen.cc',
'profiler_cc_file': '<(gen_source_dir)/profiler_gen.cc',
- 'service_cc_file': '<(gen_source_dir)/service_gen.cc',
'snapshot_test_dat_file': '<(gen_source_dir)/snapshot_test.dat',
'snapshot_test_in_dat_file': 'snapshot_test_in.dat',
'snapshot_test_dart_file': 'snapshot_test.dart',
'typed_data_cc_file': '<(gen_source_dir)/typed_data_gen.cc',
'typed_data_patch_cc_file': '<(gen_source_dir)/typed_data_patch_gen.cc',
+ 'vmservice_cc_file': '<(gen_source_dir)/vmservice_gen.cc',
},
'targets': [
{
'target_name': 'libdart_vm',
'type': 'static_library',
'toolsets':['host', 'target'],
- 'dependencies': [
- 'generate_service_cc_file#host'
- ],
'includes': [
'vm_sources.gypi',
'../platform/platform_headers.gypi',
'../platform/platform_sources.gypi',
],
- 'sources': [
- # Include generated source files.
- '<(service_cc_file)',
- ],
'sources/': [
# Exclude all _test.[cc|h] files.
['exclude', '_test\\.(cc|h)$'],
@@ -105,18 +98,11 @@
'target_name': 'libdart_vm_nosnapshot',
'type': 'static_library',
'toolsets':['host', 'target'],
- 'dependencies': [
- 'generate_service_cc_file#host'
- ],
'includes': [
'vm_sources.gypi',
'../platform/platform_headers.gypi',
'../platform/platform_sources.gypi',
],
- 'sources': [
- # Include generated source files.
- '<(service_cc_file)',
- ],
'sources/': [
# Exclude all _test.[cc|h] files.
['exclude', '_test\\.(cc|h)$'],
@@ -197,6 +183,7 @@
'generate_profiler_cc_file#host',
'generate_typed_data_cc_file#host',
'generate_typed_data_patch_cc_file#host',
+ 'generate_vmservice_cc_file#host',
],
'includes': [
'../lib/async_sources.gypi',
@@ -208,6 +195,7 @@
'../lib/math_sources.gypi',
'../lib/mirrors_sources.gypi',
'../lib/typed_data_sources.gypi',
+ '../lib/vmservice_sources.gypi',
],
'sources': [
'bootstrap.cc',
@@ -233,6 +221,7 @@
'<(profiler_cc_file)',
'<(typed_data_cc_file)',
'<(typed_data_patch_cc_file)',
+ '<(vmservice_cc_file)',
],
'include_dirs': [
'..',
@@ -252,6 +241,7 @@
'../lib/math_sources.gypi',
'../lib/mirrors_sources.gypi',
'../lib/typed_data_sources.gypi',
+ '../lib/vmservice_sources.gypi',
],
'sources': [
'bootstrap_nocore.cc',
@@ -1128,32 +1118,41 @@
]
},
{
- 'target_name': 'generate_service_cc_file',
+ 'target_name': 'generate_vmservice_cc_file',
'type': 'none',
'toolsets':['host'],
'includes': [
- 'service_sources.gypi',
+ '../lib/vmservice_sources.gypi',
+ ],
+ 'sources/': [
+ # Exclude all .[cc|h] files.
+ # This is only here for reference. Excludes happen after
+ # variable expansion, so the script has to do its own
+ # exclude processing of the sources being passed.
+ ['exclude', '\\.cc|h$'],
],
'actions': [
{
- 'action_name': 'generate_service_cc',
+ 'action_name': 'generate_vmservice_cc',
'inputs': [
- '../tools/create_resources.py',
+ '../tools/gen_library_src_paths.py',
+ '<(libgen_in_cc_file)',
'<@(_sources)',
],
'outputs': [
- '<(service_cc_file)',
+ '<(vmservice_cc_file)',
],
'action': [
'python',
- 'tools/create_resources.py',
- '--output', '<(service_cc_file)',
- '--outer_namespace', 'dart',
- '--table_name', 'service',
- '--root_prefix', 'vm/service/',
- '<@(_sources)'
+ 'tools/gen_library_src_paths.py',
+ '--output', '<(vmservice_cc_file)',
+ '--input_cc', '<(libgen_in_cc_file)',
+ '--include', 'vm/bootstrap.h',
+ '--var_name', 'dart::Bootstrap::vmservice_source_paths_',
+ '--library_name', 'dart:_vmservice',
+ '<@(_sources)',
],
- 'message': 'Generating ''<(service_cc_file)'' file.'
+ 'message': 'Generating ''<(vmservice_cc_file)'' file.'
},
]
},
diff --git a/runtime/vm/weak_code.cc b/runtime/vm/weak_code.cc
index 85e623a..cf1e132 100644
--- a/runtime/vm/weak_code.cc
+++ b/runtime/vm/weak_code.cc
@@ -115,17 +115,15 @@
// function is invoked, it will be compiled again.
function.ClearCode();
// Invalidate the old code object so existing references to it
- // (from optimized code) will fail when invoked.
- if (!CodePatcher::IsEntryPatched(code)) {
- CodePatcher::PatchEntry(
- code, Code::Handle(StubCode::FixCallersTarget_entry()->code()));
+ // (from optimized code) will be patched when invoked.
+ if (!code.IsDisabled()) {
+ code.DisableDartCode();
}
} else {
// Make non-OSR code non-entrant.
- if (!CodePatcher::IsEntryPatched(code)) {
+ if (!code.IsDisabled()) {
ReportSwitchingCode(code);
- CodePatcher::PatchEntry(
- code, Code::Handle(StubCode::FixCallersTarget_entry()->code()));
+ code.DisableDartCode();
}
}
}
diff --git a/runtime/vm/zone.cc b/runtime/vm/zone.cc
index ea42f49..7cb7977 100644
--- a/runtime/vm/zone.cc
+++ b/runtime/vm/zone.cc
@@ -178,6 +178,21 @@
}
+char* Zone::ConcatStrings(const char* a, const char* b, char join) {
+ intptr_t a_len = (a == NULL) ? 0 : strlen(a);
+ const intptr_t b_len = strlen(b) + 1; // '\0'-terminated.
+ const intptr_t len = a_len + b_len;
+ char* copy = Alloc<char>(len);
+ if (a_len > 0) {
+ strncpy(copy, a, a_len);
+ // Insert join character.
+ copy[a_len++] = join;
+ }
+ strncpy(©[a_len], b, b_len);
+ return copy;
+}
+
+
#if defined(DEBUG)
void Zone::DumpZoneSizes() {
intptr_t size = 0;
diff --git a/runtime/vm/zone.h b/runtime/vm/zone.h
index 361e6e2..2008ee9 100644
--- a/runtime/vm/zone.h
+++ b/runtime/vm/zone.h
@@ -8,6 +8,7 @@
#include "platform/utils.h"
#include "vm/allocation.h"
#include "vm/handles.h"
+#include "vm/thread.h"
#include "vm/memory_region.h"
namespace dart {
@@ -46,6 +47,10 @@
// Make a copy of the string in the zone allocated area.
char* MakeCopyOfString(const char* str);
+ // Concatenate strings |a| and |b|. |a| may be NULL. If |a| is not NULL,
+ // |join| will be inserted between |a| and |b|.
+ char* ConcatStrings(const char* a, const char* b, char join = ',');
+
// TODO(zra): Remove these calls and replace them with calls to OS::SCreate
// and OS::VSCreate.
// These calls are deprecated. Do not add further calls to these functions.
diff --git a/sdk/lib/_internal/js_runtime/lib/async_patch.dart b/sdk/lib/_internal/js_runtime/lib/async_patch.dart
index f8412c1..1155e79 100644
--- a/sdk/lib/_internal/js_runtime/lib/async_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/async_patch.dart
@@ -506,3 +506,8 @@
Iterator get iterator => new _SyncStarIterator(JS('', '#()', _outerHelper));
}
+
+@patch
+void _rethrow(Object error, StackTrace stackTrace) {
+ throw new AsyncError(error, stackTrace);
+}
diff --git a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart b/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
index 8349d14..2ff405c 100644
--- a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
@@ -44,3 +44,19 @@
_registerExtension(String method, ServiceExtensionHandler handler) {
_extensions[method] = handler;
}
+
+@patch
+int _getTraceClock() {
+ // TODO.
+ return _clockValue++;
+}
+int _clockValue = 0;
+
+@patch
+void _reportCompleteEvent(int start,
+ int end,
+ String category,
+ String name,
+ String argumentsAsJson) {
+ // TODO.
+}
diff --git a/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart b/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
index 85b30b1..8b8d023 100644
--- a/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
@@ -20,6 +20,16 @@
static Isolate get current => _currentIsolateCache;
@patch
+ static Future<Uri> get packageRoot {
+ throw new UnsupportedError("Isolate.packageRoot");
+ }
+
+ @patch
+ static Future<Map<String, Uri>> get packageMap {
+ throw new UnsupportedError("Isolate.packageMap");
+ }
+
+ @patch
static Future<Isolate> spawn(void entryPoint(message), var message,
{bool paused: false, bool errorsAreFatal,
SendPort onExit, SendPort onError}) {
diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart
index 225f5d1..2520f4d 100644
--- a/sdk/lib/async/zone.dart
+++ b/sdk/lib/async/zone.dart
@@ -891,10 +891,14 @@
void _rootHandleUncaughtError(
Zone self, ZoneDelegate parent, Zone zone, error, StackTrace stackTrace) {
_schedulePriorityAsyncCallback(() {
- throw new _UncaughtAsyncError(error, stackTrace);
+ if (error == null) error = new NullThrownError();
+ if (stackTrace == null) throw error;
+ _rethrow(error, stackTrace);
});
}
+external void _rethrow(Object error, StackTrace stackTrace);
+
dynamic _rootRun(Zone self, ZoneDelegate parent, Zone zone, f()) {
if (Zone._current == zone) return f();
@@ -1009,26 +1013,6 @@
return new _CustomZone(zone, specification, valueMap);
}
-class _RootZoneSpecification implements ZoneSpecification {
- HandleUncaughtErrorHandler get handleUncaughtError =>
- _rootHandleUncaughtError;
- RunHandler get run => _rootRun;
- RunUnaryHandler get runUnary => _rootRunUnary;
- RunBinaryHandler get runBinary => _rootRunBinary;
- RegisterCallbackHandler get registerCallback => _rootRegisterCallback;
- RegisterUnaryCallbackHandler get registerUnaryCallback =>
- _rootRegisterUnaryCallback;
- RegisterBinaryCallbackHandler get registerBinaryCallback =>
- _rootRegisterBinaryCallback;
- ErrorCallbackHandler get errorCallback => _rootErrorCallback;
- ScheduleMicrotaskHandler get scheduleMicrotask => _rootScheduleMicrotask;
- CreateTimerHandler get createTimer => _rootCreateTimer;
- CreatePeriodicTimerHandler get createPeriodicTimer =>
- _rootCreatePeriodicTimer;
- PrintHandler get print => _rootPrint;
- ForkHandler get fork => _rootFork;
-}
-
class _RootZone extends _Zone {
const _RootZone();
diff --git a/sdk/lib/convert/json.dart b/sdk/lib/convert/json.dart
index d3624ab..08eb797 100644
--- a/sdk/lib/convert/json.dart
+++ b/sdk/lib/convert/json.dart
@@ -53,8 +53,8 @@
*
* Examples:
*
- * var encoded = JSON.encode([1, 2, { "a": null }]);
- * var decoded = JSON.decode('["foo", { "bar": 499 }]');
+ * var encoded = JSON.encode([1, 2, { "a": null }]);
+ * var decoded = JSON.decode('["foo", { "bar": 499 }]');
*/
const JsonCodec JSON = const JsonCodec();
@@ -65,6 +65,11 @@
/**
* A [JsonCodec] encodes JSON objects to strings and decodes strings to
* JSON objects.
+ *
+ * Examples:
+ *
+ * var encoded = JSON.encode([1, 2, { "a": null }]);
+ * var decoded = JSON.decode('["foo", { "bar": 499 }]');
*/
class JsonCodec extends Codec<Object, String> {
final _Reviver _reviver;
diff --git a/sdk/lib/core/map.dart b/sdk/lib/core/map.dart
index e92c780..4f7fcf8 100644
--- a/sdk/lib/core/map.dart
+++ b/sdk/lib/core/map.dart
@@ -149,7 +149,7 @@
/**
* Returns true if this map contains the given [key].
*
- * Returns true if any of the keys in the map ar equal to `key`
+ * Returns true if any of the keys in the map are equal to `key`
* according to the equality used by the map.
*/
bool containsKey(Object key);
diff --git a/sdk/lib/core/resource.dart b/sdk/lib/core/resource.dart
index 17bdebc..e8c9c67 100644
--- a/sdk/lib/core/resource.dart
+++ b/sdk/lib/core/resource.dart
@@ -5,16 +5,18 @@
part of dart.core;
/**
- * A resource that can be read into the program.
+ * DEPRECATED. A resource that can be read into the program.
*
- * WARNING: This API is _experimental_,
- * and it may be changed or removed in future releases
+ * WARNING: This API is _deprecated_,
+ * and it will be removed in 1.14. Please use
+ * https://pub.dartlang.org/packages/resource instead.
*
* A resource is data that can be located using a URI and read into
* the program at runtime.
* The URI may use the `package` scheme to read resources provided
* along with package sources.
*/
+@Deprecated('1.14')
abstract class Resource {
/**
* Creates a resource object with the given [uri] as location.
diff --git a/sdk/lib/developer/developer.dart b/sdk/lib/developer/developer.dart
index d5620e4..722819c 100644
--- a/sdk/lib/developer/developer.dart
+++ b/sdk/lib/developer/developer.dart
@@ -17,6 +17,7 @@
part 'extension.dart';
part 'profiler.dart';
+part 'timeline.dart';
/// If [when] is true, stop the program as if a breakpoint were hit at the
/// following statement.
diff --git a/sdk/lib/developer/developer_sources.gypi b/sdk/lib/developer/developer_sources.gypi
index 63d69cc..0c4333a 100644
--- a/sdk/lib/developer/developer_sources.gypi
+++ b/sdk/lib/developer/developer_sources.gypi
@@ -7,6 +7,7 @@
'developer.dart',
'extension.dart',
'profiler.dart',
+ 'timeline.dart',
# The above file needs to be first if additional parts are added to the lib.
],
}
diff --git a/sdk/lib/developer/timeline.dart b/sdk/lib/developer/timeline.dart
new file mode 100644
index 0000000..54c5b80
--- /dev/null
+++ b/sdk/lib/developer/timeline.dart
@@ -0,0 +1,103 @@
+// Copyright (c) 2015, 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.
+
+part of dart.developer;
+
+typedef dynamic TimelineSyncFunction();
+
+/// Add to the timeline.
+class Timeline {
+ /// Start a synchronous operation labeled [name]. Optionally takes
+ /// a [Map] of [arguments]. This operation must be finished before
+ /// returning to the event queue.
+ static void startSync(String name, {Map arguments}) {
+ if (name is! String) {
+ throw new ArgumentError.value(name,
+ 'name',
+ 'Must be a String');
+ }
+ var block = new _SyncBlock._(name, _getTraceClock());
+ if (arguments is Map) {
+ block.arguments.addAll(arguments);
+ }
+ _stack.add(block);
+ }
+
+ /// Finish the last synchronous operation that was started.
+ static void finishSync() {
+ if (_stack.length == 0) {
+ throw new StateError(
+ 'Uneven calls to startSync and finishSync');
+ }
+ // Pop top item off of stack.
+ var block = _stack.removeLast();
+ // Close it.
+ block.close();
+ }
+
+ /// A utility method to time a synchronous [function]. Internally calls
+ /// [function] bracketed by calls to [startSync] and [finishSync].
+ static dynamic timeSync(String name,
+ TimelineSyncFunction function,
+ {Map arguments}) {
+ startSync(name, arguments: arguments);
+ try {
+ return function();
+ } finally {
+ finishSync();
+ }
+ }
+
+ static final List<_SyncBlock> _stack = new List<_SyncBlock>();
+}
+
+/// A synchronous block of time on the timeline. This block should not be
+/// kept open across isolate messages.
+class _SyncBlock {
+ /// The category this block belongs to.
+ final String category = 'Dart';
+ /// The name of this block.
+ final String name;
+ /// An (optional) set of arguments which will be serialized to JSON and
+ /// associated with this block.
+ final Map arguments = {};
+ // The start time stamp.
+ final int _start;
+ // Has this block been closed?
+ bool _closed = false;
+
+ _SyncBlock._(this.name,
+ this._start);
+
+ /// Close this block of time. At this point, this block can no longer be
+ /// used.
+ void close() {
+ if (_closed) {
+ throw new StateError(
+ 'It is illegal to call close twice on the same _SyncBlock');
+ }
+ _closed = true;
+ var end = _getTraceClock();
+
+ // Encode arguments map as JSON before reporting.
+ var argumentsAsJson = JSON.encode(arguments);
+
+ // Report event to runtime.
+ _reportCompleteEvent(_start,
+ end,
+ category,
+ name,
+ argumentsAsJson);
+ }
+}
+
+/// Returns the current value from the trace clock.
+external int _getTraceClock();
+
+/// Reports a complete synchronous event.
+external void _reportCompleteEvent(int start,
+ int end,
+ String category,
+ String name,
+ String argumentsAsJson);
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index b581f65..7bef67f 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -122,6 +122,11 @@
// TODO(17738): Implement this.
throw new UnimplementedError();
}
+
+/// Dartium functions that are a NOOP in dart2js.
+unwrap_jso(dartClass_instance) => dartClass_instance;
+wrap_jso(jsObject) => jsObject;
+createCustomUpgrader(Type customElementClass, $this) => $this;
// Copyright (c) 2013, 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.
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 95c43f6..14fc413 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -1106,6 +1106,9 @@
********** **********
******************************************************************************/
+// List of known tagName to DartClass for custom elements, used for upgrade.
+var _knownCustomeElements = new Map<String, Type>();
+
Rectangle make_dart_rectangle(r) =>
r == null ? null : new Rectangle(r['left'], r['top'], r['width'], r['height']);
@@ -1125,19 +1128,7 @@
/**
* Return the JsObject associated with a Dart class [dartClass_instance].
*/
-unwrap_jso(dartClass_instance) {
- try {
- if (dartClass_instance != null)
- return dartClass_instance is NativeFieldWrapperClass2 ?
- dartClass_instance.blink_jsObject : dartClass_instance;
- else
- return null;
- } catch(NoSuchMethodException) {
- // No blink_jsObject then return the dartClass_instance is probably an
- // array that was already converted to a Dart class e.g., Uint8ClampedList.
- return dartClass_instance;
- }
-}
+unwrap_jso(dartClass_instance) => js.unwrap_jso(dartClass_instance);
/**
* Create Dart class that maps to the JS Type, add the JsObject as an expando
@@ -1145,10 +1136,26 @@
*/
wrap_jso(jsObject) {
try {
- if (jsObject is! js.JsObject) {
+ if (jsObject is! js.JsObject || jsObject == null) {
// JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
+ // or it's a simple type.
return jsObject;
}
+
+ // TODO(alanknight): With upgraded custom elements this causes a failure because
+ // we need a new wrapper after the type changes. We could possibly invalidate this
+ // if the constructor name didn't match?
+ var wrapper = js.getDartHtmlWrapperFor(jsObject);
+ if (wrapper != null) {
+ return wrapper;
+ }
+
+ if (jsObject is js.JsArray) {
+ var wrappingList = new _DartHtmlWrappingList(jsObject);
+ js.setDartHtmlWrapperFor(jsObject, wrappingList);
+ return wrappingList;
+ }
+
// Try the most general type conversions on it.
// TODO(alanknight): We may be able to do better. This maintains identity,
// which is useful, but expensive. And if we nest something that only
@@ -1171,10 +1178,24 @@
// Got a dart_class (it's a custom element) use it it's already set up.
dartClass_instance = jsObject['dart_class'];
} else {
- var func = getHtmlCreateFunction(jsTypeName);
- if (func != null) {
- dartClass_instance = func();
- dartClass_instance.blink_jsObject = jsObject;
+ var localName = jsObject['localName'];
+ var customElementClass = _knownCustomeElements[localName];
+ // Custom Element to upgrade.
+ if (jsTypeName == 'HTMLElement' && customElementClass != null) {
+ try {
+ dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
+ } finally {
+ dartClass_instance.blink_jsObject = jsObject;
+ jsObject['dart_class'] = dartClass_instance;
+ js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
+ }
+ } else {
+ var func = getHtmlCreateFunction(jsTypeName);
+ if (func != null) {
+ dartClass_instance = func();
+ dartClass_instance.blink_jsObject = jsObject;
+ js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
+ }
}
}
return dartClass_instance;
@@ -1293,6 +1314,41 @@
// Conversion function place holder (currently not used in dart2js or dartium).
List convertDartToNative_StringArray(List<String> input) => input;
+/**
+ * Wraps a JsArray and will call wrap_jso on its entries.
+ */
+class _DartHtmlWrappingList extends ListBase {
+ _DartHtmlWrappingList(this._basicList);
+
+ final js.JsArray _basicList;
+
+ operator [](int index) => wrap_jso(_basicList[index]);
+
+ operator []=(int index, value) => _basicList[index] = unwrap_jso(value);
+
+ int get length => _basicList.length;
+ int set length(int newLength) => _basicList.length = newLength;
+}
+
+/**
+ * Upgrade the JS HTMLElement to the Dart class. Used by Dart's Polymer.
+ */
+createCustomUpgrader(Type customElementClass, $this) {
+ var dartClass;
+ try {
+ dartClass = _blink.Blink_Utils.constructElement(customElementClass, $this);
+ } catch (e) {
+ throw e;
+ } finally {
+ // Need to remember the Dart class that was created for this custom so
+ // return it and setup the blink_jsObject to the $this that we'll be working
+ // with as we talk to blink.
+ $this['dart_class'] = dartClass;
+ }
+
+ return dartClass;
+}
+
// Copyright (c) 2013, 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.
@@ -10127,10 +10183,10 @@
void _readEntries(_EntriesCallback successCallback, [_ErrorCallback errorCallback]) {
if (errorCallback != null) {
- _blink.BlinkDirectoryReader.instance.readEntries_Callback_2_(unwrap_jso(this), unwrap_jso((entries) => successCallback(entries)), unwrap_jso((error) => errorCallback(wrap_jso(error))));
+ _blink.BlinkDirectoryReader.instance.readEntries_Callback_2_(unwrap_jso(this), unwrap_jso((entries) => successCallback(wrap_jso(entries))), unwrap_jso((error) => errorCallback(wrap_jso(error))));
return;
}
- _blink.BlinkDirectoryReader.instance.readEntries_Callback_1_(unwrap_jso(this), unwrap_jso((entries) => successCallback(entries)));
+ _blink.BlinkDirectoryReader.instance.readEntries_Callback_1_(unwrap_jso(this), unwrap_jso((entries) => successCallback(wrap_jso(entries))));
return;
}
@@ -11053,6 +11109,8 @@
wrapped = wrap_jso(newElement);
if (wrapped == null) {
wrapped = wrap_jso_custom_element(newElement);
+ } else {
+ wrapped.blink_jsObject['dart_class'] = wrapped;
}
}
@@ -11075,6 +11133,8 @@
wrapped = wrap_jso(newElement);
if (wrapped == null) {
wrapped = wrap_jso_custom_element(newElement);
+ } else {
+ wrapped.blink_jsObject['dart_class'] = wrapped;
}
}
@@ -18427,7 +18487,7 @@
@DomName('FontFaceSetLoadEvent.fontfaces')
@DocsEditable()
@Experimental() // untriaged
- List<FontFace> get fontfaces => _blink.BlinkFontFaceSetLoadEvent.instance.fontfaces_Getter_(unwrap_jso(this));
+ List<FontFace> get fontfaces => wrap_jso(_blink.BlinkFontFaceSetLoadEvent.instance.fontfaces_Getter_(unwrap_jso(this)));
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
@@ -18657,7 +18717,7 @@
@DomName('Gamepad.axes')
@DocsEditable()
- List<num> get axes => _blink.BlinkGamepad.instance.axes_Getter_(unwrap_jso(this));
+ List<num> get axes => wrap_jso(_blink.BlinkGamepad.instance.axes_Getter_(unwrap_jso(this)));
@DomName('Gamepad.connected')
@DocsEditable()
@@ -20321,6 +20381,9 @@
}
var elemProto = js.context['Object'].callMethod("create", [baseElement['prototype']]);
+ // Remember for any upgrading done in wrap_jso.
+ _knownCustomeElements[tag] = customElementClass;
+
// TODO(terry): Hack to stop recursion re-creating custom element when the
// created() constructor of the custom element does e.g.,
//
@@ -22870,7 +22933,7 @@
@SupportedBrowser(SupportedBrowser.SAFARI)
@Experimental()
// http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#concept-input-type-file-selected
- List<Entry> get entries => _blink.BlinkHTMLInputElement.instance.webkitEntries_Getter_(unwrap_jso(this));
+ List<Entry> get entries => wrap_jso(_blink.BlinkHTMLInputElement.instance.webkitEntries_Getter_(unwrap_jso(this)));
@DomName('HTMLInputElement.webkitdirectory')
@DocsEditable()
@@ -26123,7 +26186,7 @@
@DomName('MessageEvent.initMessageEvent')
@DocsEditable()
- void _initMessageEvent(String typeArg, bool canBubbleArg, bool cancelableArg, Object dataArg, String originArg, String lastEventIdArg, Window sourceArg, List<MessagePort> messagePorts) => _blink.BlinkMessageEvent.instance.initMessageEvent_Callback_8_(unwrap_jso(this), typeArg, canBubbleArg, cancelableArg, dataArg, originArg, lastEventIdArg, unwrap_jso(sourceArg), messagePorts);
+ void _initMessageEvent(String typeArg, bool canBubbleArg, bool cancelableArg, Object dataArg, String originArg, String lastEventIdArg, Window sourceArg, List<MessagePort> messagePorts) => _blink.BlinkMessageEvent.instance.initMessageEvent_Callback_8_(unwrap_jso(this), typeArg, canBubbleArg, cancelableArg, dataArg, originArg, lastEventIdArg, unwrap_jso(sourceArg), unwrap_jso(messagePorts));
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
@@ -27229,7 +27292,7 @@
}
@DocsEditable()
static MutationObserver _create(callback) => wrap_jso(_blink.BlinkMutationObserver.instance.constructorCallback_1_((mutations, observer) {
- callback(mutations, wrap_jso(observer));
+ callback(wrap_jso(mutations), wrap_jso(observer));
}));
/**
@@ -47217,11 +47280,12 @@
}
}
- Element upgrade(Element element) {
- if (element.runtimeType != _nativeType) {
+ Element upgrade(element) {
+ if (element.runtimeType != js.JsObjectImpl) {
throw new UnsupportedError('Element is incorrect type');
}
- return _Utils.changeElementWrapper(element, _type);
+
+ return createCustomUpgrader(_nativeType, element);
}
}
diff --git a/sdk/lib/io/socket.dart b/sdk/lib/io/socket.dart
index a759598..6464ab4a 100644
--- a/sdk/lib/io/socket.dart
+++ b/sdk/lib/io/socket.dart
@@ -253,41 +253,6 @@
* is fully closed and is no longer bound.
*/
Future<RawServerSocket> close();
-
- /**
- * Get the [RawServerSocketReference].
- *
- * WARNING: This feature is *highly experimental* and currently only
- * works on Linux. The API will be removed in Dart 1.10. Use the
- * `shared` optional argument on the `bind` method instead.
- *
- * The returned [RawServerSocketReference] can be used to create other
- * [RawServerSocket]s listening on the same port,
- * using [RawServerSocketReference.create].
- * Incoming connections on the port will be distributed fairly between the
- * active server sockets.
- * The [RawServerSocketReference] can be distributed to other isolates through
- * a [RawSendPort].
- */
-
- @Deprecated('This will be removed in Dart 1.10. Use the '
- '`shared` optional argument on the `bind` method instead.')
- RawServerSocketReference get reference;
-}
-
-
-/**
- * A [RawServerSocketReference].
- *
- * WARNING: This class is used with [RawServerSocket.reference] which is highly
- * experimental.
- */
-@Deprecated('This will be removed in Dart 1.10.')
-abstract class RawServerSocketReference {
- /**
- * Create a new [RawServerSocket], from this reference.
- */
- Future<RawServerSocket> create();
}
@@ -358,40 +323,6 @@
* is fully closed and is no longer bound.
*/
Future<ServerSocket> close();
-
- /**
- * Get the [ServerSocketReference].
- *
- * WARNING: This feature is *highly experimental* and currently only
- * works on Linux. The API will be removed in Dart 1.10. Use the
- * `shared` optional argument on the `bind` method instead.
- *
- * The returned [ServerSocketReference] can be used to create other
- * [ServerSocket]s listening on the same port,
- * using [ServerSocketReference.create].
- * Incoming connections on the port will be distributed fairly between the
- * active server sockets.
- * The [ServerSocketReference] can be distributed to other isolates through a
- * [SendPort].
- */
- @Deprecated('This will be removed in Dart 1.10. Use the '
- '`shared` optional argument on the `bind` method instead.')
- ServerSocketReference get reference;
-}
-
-
-/**
- * A [ServerSocketReference].
- *
- * WARNING: This class is used with [ServerSocket.reference] which is highly
- * experimental.
- */
-@Deprecated('This will be removed in Dart 1.10.')
-abstract class ServerSocketReference {
- /**
- * Create a new [ServerSocket], from this reference.
- */
- Future<ServerSocket> create();
}
@@ -735,6 +666,8 @@
/**
* Receive a datagram. If there are no datagrams available `null` is
* returned.
+ *
+ * The maximum length of the datagram that can be received is 65503 bytes.
*/
Datagram receive();
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index c671220..d6b4c0b 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.dart
@@ -127,6 +127,29 @@
external static Isolate get current;
/**
+ * Returns the package root of the current isolate, if any.
+ *
+ * If the isolate is using a [packageMap], this getter returns `null`,
+ * otherwise it returns the package root - a directory that package
+ * URIs are resolved against.
+ */
+ external static Future<Uri> get packageRoot;
+
+ /**
+ * Returns the package mapping of the current isolate, if any.
+ *
+ * If the current isolate is using a [packageRoot], this getter
+ * returns `null`.
+ *
+ * The package map maps the name of a package that is available to the
+ * program, to a URI that package URIs for that package are resolved against.
+ *
+ * Returns an empty map if the isolate does not have a way to resolve package
+ * URIs.
+ */
+ external static Future<Map<String, Uri>> get packageMap;
+
+ /**
* Creates and spawns an isolate that shares the same code as the current
* isolate.
*
diff --git a/sdk/lib/js/dartium/js_dartium.dart b/sdk/lib/js/dartium/js_dartium.dart
index b6c7198..186bde7 100644
--- a/sdk/lib/js/dartium/js_dartium.dart
+++ b/sdk/lib/js/dartium/js_dartium.dart
@@ -480,6 +480,41 @@
}
/**
+ * Get the dart wrapper object for object. Top-level so we
+ * we can access it from other libraries without it being
+ * a public instance field on JsObject.
+ */
+getDartHtmlWrapperFor(JsObject object) => object._dartHtmlWrapper;
+
+/**
+ * Set the dart wrapper object for object. Top-level so we
+ * we can access it from other libraries without it being
+ * a public instance field on JsObject.
+ */
+void setDartHtmlWrapperFor(JsObject object, wrapper) {
+ object._dartHtmlWrapper = wrapper;
+}
+
+/**
+ * Used by callMethod to get the JS object for each argument passed if the
+ * argument is a Dart class instance that delegates to a DOM object. See
+ * wrap_jso defined in dart:html.
+ */
+unwrap_jso(dartClass_instance) {
+ try {
+ if (dartClass_instance != null)
+ return dartClass_instance is NativeFieldWrapperClass2 ?
+ dartClass_instance.blink_jsObject : dartClass_instance;
+ else
+ return null;
+ } catch(NoSuchMethodException) {
+ // No blink_jsObject then return the dartClass_instance is probably an
+ // array that was already converted to a Dart class e.g., Uint8ClampedList.
+ return dartClass_instance;
+ }
+}
+
+/**
* Proxies a JavaScript object to Dart.
*
* The properties of the JavaScript object are accessible via the `[]` and
@@ -489,6 +524,12 @@
JsObject.internal();
/**
+ * If this JsObject is wrapped, e.g. DOM objects, then we can save the
+ * wrapper here and preserve its identity.
+ */
+ var _dartHtmlWrapper;
+
+ /**
* Constructs a new JavaScript object from [constructor] and returns a proxy
* to it.
*/
@@ -644,6 +685,10 @@
*/
callMethod(String method, [List args]) {
try {
+ if (args != null) {
+ for (var i = 0; i < args.length; i++)
+ args[i] = unwrap_jso(args[i]);
+ }
return _callMethod(method, args);
} catch (e) {
if (hasProperty(method)) {
@@ -785,11 +830,7 @@
_checkIndex(index);
}
- // Lazily create the Dart class that wraps the JS object when the object in
- // a list if fetched.
- var wrap_entry = html.wrap_jso(super[index]);
- super[index] = wrap_entry;
- return wrap_entry;
+ return super[index];
}
void operator []=(index, E value) {
diff --git a/sdk/lib/web_sql/dartium/web_sql_dartium.dart b/sdk/lib/web_sql/dartium/web_sql_dartium.dart
index 73bc18c..2d8039e 100644
--- a/sdk/lib/web_sql/dartium/web_sql_dartium.dart
+++ b/sdk/lib/web_sql/dartium/web_sql_dartium.dart
@@ -412,6 +412,6 @@
@DomName('SQLTransaction.executeSql')
@DocsEditable()
- void executeSql(String sqlStatement, List<Object> arguments, [SqlStatementCallback callback, SqlStatementErrorCallback errorCallback]) => _blink.BlinkSQLTransaction.instance.executeSql_Callback_4_(unwrap_jso(this), sqlStatement, arguments, unwrap_jso((transaction, resultSet) => callback(wrap_jso(transaction), wrap_jso(resultSet))), unwrap_jso((transaction, error) => errorCallback(wrap_jso(transaction), wrap_jso(error))));
+ void executeSql(String sqlStatement, List<Object> arguments, [SqlStatementCallback callback, SqlStatementErrorCallback errorCallback]) => _blink.BlinkSQLTransaction.instance.executeSql_Callback_4_(unwrap_jso(this), sqlStatement, unwrap_jso(arguments), unwrap_jso((transaction, resultSet) => callback(wrap_jso(transaction), wrap_jso(resultSet))), unwrap_jso((transaction, error) => errorCallback(wrap_jso(transaction), wrap_jso(error))));
}
diff --git a/site/try/poi/scope_information_visitor.dart b/site/try/poi/scope_information_visitor.dart
index 5ae18ee..5f1b5a1 100644
--- a/site/try/poi/scope_information_visitor.dart
+++ b/site/try/poi/scope_information_visitor.dart
@@ -120,7 +120,7 @@
{bool isStatic: false,
bool omitEnclosing: false,
bool includeSuper: false}) {
- e.ensureResolved(compiler);
+ e.ensureResolved(compiler.resolution);
bool isFirst = true;
var serializeEnclosing;
String kind;
@@ -231,7 +231,7 @@
if (category == ElementCategory.FUNCTION ||
category == ElementCategory.VARIABLE ||
element.isConstructor) {
- type = element.computeType(compiler);
+ type = element.computeType(compiler.resolution);
}
if (name == null) {
name = element.name;
diff --git a/site/try/src/leap.dart b/site/try/src/leap.dart
index 626048f..3688bed 100644
--- a/site/try/src/leap.dart
+++ b/site/try/src/leap.dart
@@ -16,7 +16,6 @@
SendPort;
import 'compilation.dart' show
- compilerIsolate,
compilerPort,
currentSource;
diff --git a/tests/co19/co19-co19.status b/tests/co19/co19-co19.status
index 2e60ccc..c28d8d8 100644
--- a/tests/co19/co19-co19.status
+++ b/tests/co19/co19-co19.status
@@ -4,7 +4,8 @@
# This file contains the tests that have been identified as broken and
# have been filed on the co19 issue tracker at
-# https://code.google.com/p/co19/issues/list .
+# https://code.google.com/p/co19/issues/list (read-only).
+# https://github.com/dart-lang/co19/issues .
#
# In order to qualify here these tests need to fail both on the VM and dart2js.
@@ -13,6 +14,10 @@
[ $runtime == vm || $runtime != vm ]
# Tests that fail everywhere, including the analyzer.
+# Super is now allowed in mixins and mixins may now extend a subclass of Object.
+Language/09_Mixins/09_Mixins_A01_t01: Skip # co19 issue 9.
+Language/09_Mixins/09_Mixins_A03_t01: Skip # co19 issue 9.
+
# No longer correct, y#$ now has a meaning. github.com/dart-lang/co19/issues/2
Language/12_Expressions/30_Identifier_Reference_A01_t03: Skip
diff --git a/tests/co19/co19-dartium.status b/tests/co19/co19-dartium.status
index 47d5f46..546f5fe 100644
--- a/tests/co19/co19-dartium.status
+++ b/tests/co19/co19-dartium.status
@@ -20,10 +20,7 @@
LayoutTests/fast/xpath/4XPath/Core/test_parser_t01: RuntimeError # Dartium JSInterop failure
LayoutTests/fast/xpath/py-dom-xpath/abbreviations_t01: RuntimeError # Dartium JSInterop failure
LayoutTests/fast/xpath/py-dom-xpath/axes_t01: RuntimeError # Dartium JSInterop failure
-LibTest/html/Element/offsetParent_A01_t01: RuntimeError # Dartium JSInterop failure
-LibTest/html/Event/currentTarget_A01_t01: RuntimeError # Dartium JSInterop failure
-LibTest/html/Event/matchingTarget_A01_t01: RuntimeError # Dartium JSInterop failure
-LibTest/html/Event/target_A01_t01: RuntimeError # Dartium JSInterop failure
+LayoutTests/fast/dom/custom/element-type_t01: RuntimeError # Dartium JsInterop failure (element upgrade)
[ $compiler == none && $runtime == dartium && $checked ]
LayoutTests/fast/css/style-scoped/style-scoped-scoping-nodes-different-order_t01: RuntimeError # Dartium JSInterop failure
@@ -211,7 +208,6 @@
LibTest/html/HttpRequest/responseType_A01_t01: RuntimeError # co19-roll r706. Please triage this failure.
LibTest/html/HttpRequest/responseType_A01_t03: RuntimeError # co19-roll r706. Please triage this failure.
LibTest/html/HttpRequest/statusText_A01_t01: RuntimeError # co19-roll r706. Please triage this failure.
-LibTest/html/IFrameElement/IFrameElement.created_A01_t01: RuntimeError # co19-roll r706. Please triage this failure.
LibTest/html/IFrameElement/appendHtml_A01_t01: RuntimeError # Issue 23462
LibTest/html/IFrameElement/appendHtml_A01_t02: RuntimeError # Issue 23462
LibTest/html/IFrameElement/attributeChanged_A01_t01: RuntimeError # co19-roll r706. Please triage this failure.
@@ -395,6 +391,7 @@
LayoutTests/fast/dom/characterdata-api-arguments_t01: RuntimeError # co19-roll r738: Please triage this failure.
LayoutTests/fast/dom/client-width-height-quirks_t01: RuntimeError # co19-roll r738: Please triage this failure.
LayoutTests/fast/dom/custom/document-register-svg-extends_t01: RuntimeError # co19-roll r738: Please triage this failure.
+LayoutTests/fast/dom/custom/document-register-type-extensions_t01: RuntimeError # Issue 24516
LayoutTests/fast/dom/dataset-xhtml_t01: RuntimeError # co19-roll r738: Please triage this failure.
LayoutTests/fast/dom/dataset_t01: RuntimeError # co19-roll r738: Please triage this failure.
LayoutTests/fast/dom/focus-contenteditable_t01: RuntimeError, Pass # co19-roll r738: Please triage this failure.
diff --git a/tests/compiler/dart2js/analyze_unused_dart2js_test.dart b/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
index 0c4870b..90fc59b2 100644
--- a/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
+++ b/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
@@ -85,24 +85,24 @@
'pkg/compiler/lib/src/helpers/helpers.dart');
void checkLive(member) {
if (member.isFunction) {
- if (compiler.enqueuer.resolution.hasBeenResolved(member)) {
- compiler.reportHint(compiler.createMessage(
+ if (compiler.enqueuer.resolution.hasBeenProcessed(member)) {
+ compiler.reporter.reportHintMessage(
member, MessageKind.GENERIC,
- {'text': "Helper function in production code '$member'."}));
+ {'text': "Helper function in production code '$member'."});
}
} else if (member.isClass) {
if (member.isResolved) {
- compiler.reportHint(compiler.createMessage(
+ compiler.reporter.reportHintMessage(
member, MessageKind.GENERIC,
- {'text': "Helper class in production code '$member'."}));
+ {'text': "Helper class in production code '$member'."});
} else {
member.forEachLocalMember(checkLive);
}
} else if (member.isTypedef) {
if (member.isResolved) {
- compiler.reportHint(compiler.createMessage(
+ compiler.reporter.reportHintMessage(
member, MessageKind.GENERIC,
- {'text': "Helper typedef in production code '$member'."}));
+ {'text': "Helper typedef in production code '$member'."});
}
}
}
diff --git a/tests/compiler/dart2js/backend_dart/dart_backend_test.dart b/tests/compiler/dart2js/backend_dart/dart_backend_test.dart
index fb5c3ee..597f056 100644
--- a/tests/compiler/dart2js/backend_dart/dart_backend_test.dart
+++ b/tests/compiler/dart2js/backend_dart/dart_backend_test.dart
@@ -614,7 +614,8 @@
PlaceholderCollector collectPlaceholders(compiler, element) {
DartBackend backend = compiler.backend;
- return new PlaceholderCollector(compiler,
+ return new PlaceholderCollector(
+ compiler.reporter,
backend.mirrorRenamer,
new Set<String>(),
new DynoMap(compiler),
diff --git a/tests/compiler/dart2js/backend_dart/dart_printer_test.dart b/tests/compiler/dart2js/backend_dart/dart_printer_test.dart
index f6fd38b..88eabca 100644
--- a/tests/compiler/dart2js/backend_dart/dart_printer_test.dart
+++ b/tests/compiler/dart2js/backend_dart/dart_printer_test.dart
@@ -51,7 +51,7 @@
print("${x.runtimeType}: ${buf.toString()}");
}
-class PrintDiagnosticListener implements DiagnosticListener {
+class PrintDiagnosticListener implements DiagnosticReporter {
void log(message) {
print(message);
}
diff --git a/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart b/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
index 247a25f..41ed1ba 100644
--- a/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
+++ b/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
@@ -218,7 +218,7 @@
enableInlining,
(compiler, element) {
var expectedTypes = f(compiler);
- var signature = element.computeSignature(compiler);
+ var signature = element.functionSignature;
int index = 0;
var inferrer = compiler.typesTask.typesInferrer;
signature.forEachParameter((Element element) {
diff --git a/tests/compiler/dart2js/combinator_hint_test.dart b/tests/compiler/dart2js/combinator_hint_test.dart
new file mode 100644
index 0000000..f8b9c26
--- /dev/null
+++ b/tests/compiler/dart2js/combinator_hint_test.dart
@@ -0,0 +1,125 @@
+// Copyright (c) 2015, 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 that the hint on empty combinators works as intended.
+
+import 'dart:async';
+import 'package:async_helper/async_helper.dart';
+import 'package:expect/expect.dart';
+import 'package:compiler/src/commandline_options.dart';
+import 'package:compiler/src/compiler.dart';
+import 'memory_compiler.dart';
+
+const SOURCE = const {
+ 'show_local.dart': """
+import 'lib.dart' show Foo;
+
+main() {}
+""",
+
+ 'hide_local.dart': """
+import 'lib.dart' hide Foo;
+
+main() {}
+""",
+
+ 'show_package.dart': """
+import 'package:pkg/pkg.dart' show Foo;
+
+main() {}
+""",
+
+ 'hide_package.dart': """
+import 'package:pkg/pkg.dart' hide Foo;
+
+main() {}
+""",
+
+ 'lib.dart': '',
+
+ 'pkg/pkg/pkg.dart': '',
+};
+
+Future<Compiler> test(Uri entryPoint,
+ {bool showPackageWarnings: false,
+ bool suppressHints: false,
+ int hints: 0,
+ Compiler cachedCompiler}) async {
+ print('==================================================================');
+ print('test: $entryPoint showPackageWarnings=$showPackageWarnings '
+ 'suppressHints=$suppressHints');
+ var options = [Flags.analyzeOnly];
+ if (showPackageWarnings) {
+ options.add(Flags.showPackageWarnings);
+ }
+ if (suppressHints) {
+ options.add(Flags.suppressHints);
+ }
+ var collector = new DiagnosticCollector();
+ CompilationResult result = await runCompiler(
+ entryPoint: entryPoint,
+ memorySourceFiles: SOURCE,
+ options: options,
+ packageRoot: Uri.parse('memory:pkg/'),
+ diagnosticHandler: collector,
+ cachedCompiler: cachedCompiler);
+ Expect.equals(0, collector.errors.length,
+ 'Unexpected errors: ${collector.errors}');
+ Expect.equals(0, collector.warnings.length,
+ 'Unexpected warnings: ${collector.warnings}');
+ Expect.equals(hints, collector.hints.length,
+ 'Unexpected hints: ${collector.hints}');
+ Expect.equals(0, collector.infos.length,
+ 'Unexpected infos: ${collector.infos}');
+ print('==================================================================');
+ return result.compiler;
+}
+
+Future<Compiler> testUri(Uri entrypoint,
+ {bool suppressed: false,
+ Compiler cachedCompiler}) async {
+ cachedCompiler = await test(
+ entrypoint,
+ showPackageWarnings: true,
+ suppressHints: false,
+ hints: 1,
+ cachedCompiler: cachedCompiler);
+ cachedCompiler = await test(
+ entrypoint,
+ showPackageWarnings: false,
+ suppressHints: false,
+ hints: suppressed ? 0 : 1,
+ cachedCompiler: cachedCompiler);
+ cachedCompiler = await test(
+ entrypoint,
+ showPackageWarnings: true,
+ suppressHints: true,
+ hints: 0,
+ cachedCompiler: cachedCompiler);
+ cachedCompiler = await test(
+ entrypoint,
+ showPackageWarnings: false,
+ suppressHints: true,
+ hints: 0,
+ cachedCompiler: cachedCompiler);
+ return cachedCompiler;
+}
+
+void main() {
+ asyncTest(() async {
+ Compiler cachedCompiler = await testUri(
+ Uri.parse('memory:show_local.dart'));
+ cachedCompiler = await testUri(
+ Uri.parse('memory:hide_local.dart'),
+ cachedCompiler: cachedCompiler);
+ cachedCompiler = await testUri(
+ Uri.parse('memory:show_package.dart'),
+ cachedCompiler: cachedCompiler);
+ cachedCompiler = await testUri(
+ Uri.parse('memory:hide_package.dart'),
+ suppressed: true,
+ cachedCompiler: cachedCompiler);
+ });
+}
+
diff --git a/tests/compiler/dart2js/compiler_test.dart b/tests/compiler/dart2js/compiler_test.dart
index 3b1f425..74f9b17 100644
--- a/tests/compiler/dart2js/compiler_test.dart
+++ b/tests/compiler/dart2js/compiler_test.dart
@@ -5,15 +5,26 @@
import "dart:async";
import "package:expect/expect.dart";
import "package:async_helper/async_helper.dart";
-import "package:compiler/src/diagnostics/messages.dart";
import "package:compiler/src/elements/elements.dart";
import "package:compiler/src/resolution/members.dart";
import "package:compiler/src/diagnostics/diagnostic_listener.dart";
import "mock_compiler.dart";
+import "diagnostic_reporter_helper.dart";
class CallbackMockCompiler extends MockCompiler {
- CallbackMockCompiler() : super.internal();
+ CallbackReporter reporter;
+
+ CallbackMockCompiler() : super.internal() {
+ reporter = new CallbackReporter(super.reporter);
+ }
+
+}
+
+class CallbackReporter extends DiagnosticReporterWrapper {
+ final DiagnosticReporter reporter;
+
+ CallbackReporter(this.reporter);
var onError;
var onWarning;
@@ -48,9 +59,9 @@
ResolverVisitor visitor = compiler.resolverVisitor();
compiler.parseScript('NoSuchPrefix.NoSuchType foo() {}');
FunctionElement foo = compiler.mainApp.find('foo');
- compiler.setOnWarning(
+ compiler.reporter.setOnWarning(
(c, n, m) => Expect.equals(foo, compiler.currentElement));
- foo.computeType(compiler);
+ foo.computeType(compiler.resolution);
Expect.equals(1, compiler.warnings.length);
});
}
diff --git a/tests/compiler/dart2js/concrete_type_inference_test.dart b/tests/compiler/dart2js/concrete_type_inference_test.dart
index 5e154c4..8a53a44 100644
--- a/tests/compiler/dart2js/concrete_type_inference_test.dart
+++ b/tests/compiler/dart2js/concrete_type_inference_test.dart
@@ -23,7 +23,7 @@
'print',
(compiler, printElement) {
var parameter =
- printElement.computeSignature(compiler).requiredParameters.first;
+ printElement.functionSignature.requiredParameters.first;
var type = compiler.typesTask.getGuaranteedTypeOfElement(parameter);
checkType(compiler, type);
}));
@@ -33,7 +33,7 @@
'print',
(compiler, printElement) {
var parameter =
- printElement.computeSignature(compiler).requiredParameters.first;
+ printElement.functionSignature.requiredParameters.first;
var type = compiler.typesTask.getGuaranteedTypeOfElement(parameter);
checkType(compiler, type);
}));
@@ -43,7 +43,7 @@
'print',
(compiler, printElement) {
var parameter =
- printElement.computeSignature(compiler).requiredParameters.first;
+ printElement.functionSignature.requiredParameters.first;
var type = compiler.typesTask.getGuaranteedTypeOfElement(parameter);
checkType(compiler, type);
}));
@@ -78,12 +78,12 @@
'fisk(a, [b, c]) {} main() { fisk(1); }',
'fisk',
(compiler, fiskElement) {
- var firstParameter =
- fiskElement.computeSignature(compiler).requiredParameters[0];
- var secondParameter =
- fiskElement.computeSignature(compiler).optionalParameters[0];
- var thirdParameter =
- fiskElement.computeSignature(compiler).optionalParameters[1];
+ var firstParameter = fiskElement.functionSignature
+ .requiredParameters[0];
+ var secondParameter = fiskElement.functionSignature
+ .optionalParameters[0];
+ var thirdParameter = fiskElement.functionSignature
+ .optionalParameters[1];
var typesTask = compiler.typesTask;
Expect.identical(
typesTask.uint31Type,
diff --git a/tests/compiler/dart2js/cpa_inference_test.dart b/tests/compiler/dart2js/cpa_inference_test.dart
deleted file mode 100644
index 50e458b..0000000
--- a/tests/compiler/dart2js/cpa_inference_test.dart
+++ /dev/null
@@ -1,2160 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import "package:expect/expect.dart";
-import "package:async_helper/async_helper.dart";
-import 'package:compiler/src/types/types.dart';
-import 'package:compiler/src/inferrer/concrete_types_inferrer.dart';
-import 'package:compiler/src/universe/call_structure.dart' show
- CallStructure;
-import 'package:compiler/src/universe/selector.dart' show
- Selector;
-
-import "compiler_helper.dart";
-import "type_mask_test_helper.dart";
-
-/**
- * Finds the node corresponding to the last occurence of the substring
- * [: identifier; :] in the program represented by the visited AST.
- */
-class VariableFinderVisitor extends Visitor {
- final String identifier;
- Node result;
-
- VariableFinderVisitor(this.identifier);
-
- visitSend(Send node) {
- if (node.isPropertyAccess
- && node.selector.asIdentifier().source == identifier) {
- result = node;
- } else {
- node.visitChildren(this);
- }
- }
-
- visitNode(Node node) {
- node.visitChildren(this);
- }
-}
-
-class AnalysisResult {
- MockCompiler compiler;
- ConcreteTypesInferrer inferrer;
- Node ast;
-
- BaseType int;
- BaseType double;
- BaseType num;
- BaseType bool;
- BaseType string;
- BaseType list;
- BaseType growableList;
- BaseType map;
- BaseType nullType;
- BaseType functionType;
-
- AnalysisResult(MockCompiler compiler) : this.compiler = compiler {
- inferrer = compiler.typesTask.concreteTypesInferrer;
- int = inferrer.baseTypes.intBaseType;
- double = inferrer.baseTypes.doubleBaseType;
- num = inferrer.baseTypes.numBaseType;
- bool = inferrer.baseTypes.boolBaseType;
- string = inferrer.baseTypes.stringBaseType;
- list = inferrer.baseTypes.listBaseType;
- growableList = inferrer.baseTypes.growableListBaseType;
- map = inferrer.baseTypes.mapBaseType;
- nullType = const NullBaseType();
- functionType = inferrer.baseTypes.functionBaseType;
- FunctionElement mainElement = compiler.mainApp.find('main');
- ast = mainElement.node;
- }
-
- BaseType base(String className) {
- final source = className;
- return new ClassBaseType(compiler.mainApp.find(source));
- }
-
- /**
- * Finds the [Node] corresponding to the last occurence of the substring
- * [: identifier; :] in the program represented by the visited AST. For
- * instance, returns the AST node representing [: foo; :] in
- * [: main() { foo = 1; foo; } :].
- */
- Node findNode(String identifier) {
- VariableFinderVisitor finder = new VariableFinderVisitor(identifier);
- ast.accept(finder);
- return finder.result;
- }
-
- /**
- * Finds the [Element] corresponding to [: className#fieldName :].
- */
- Element findField(String className, String fieldName) {
- ClassElement element = compiler.mainApp.find(className);
- return element.lookupLocalMember(fieldName);
- }
-
- ConcreteType concreteFrom(List<BaseType> baseTypes) {
- ConcreteType result = inferrer.emptyConcreteType;
- for (final baseType in baseTypes) {
- result = result.union(inferrer.singletonConcreteType(baseType));
- }
- // We make sure the concrete types expected by the tests don't default to
- // dynamic because of widening.
- assert(!result.isUnknown());
- return result;
- }
-
- /**
- * Checks that the inferred type of the node corresponding to the last
- * occurence of [: variable; :] in the program is the concrete type
- * made of [baseTypes].
- */
- void checkNodeHasType(String variable, List<BaseType> baseTypes) {
- Expect.equals(
- concreteFrom(baseTypes),
- inferrer.inferredTypes[findNode(variable)]);
- }
-
- /**
- * Checks that the inferred type of the node corresponding to the last
- * occurence of [: variable; :] in the program is the unknown concrete type.
- */
- void checkNodeHasUnknownType(String variable) {
- Expect.isTrue(inferrer.inferredTypes[findNode(variable)].isUnknown());
- }
-
- /**
- * Checks that [: className#fieldName :]'s inferred type is the concrete type
- * made of [baseTypes].
- */
- void checkFieldHasType(String className, String fieldName,
- List<BaseType> baseTypes) {
- Expect.equals(
- concreteFrom(baseTypes),
- inferrer.inferredFieldTypes[findField(className, fieldName)]);
- }
-
- /**
- * Checks that [: className#fieldName :]'s inferred type is the unknown
- * concrete type.
- */
- void checkFieldHasUknownType(String className, String fieldName) {
- Expect.isTrue(
- inferrer.inferredFieldTypes[findField(className, fieldName)]
- .isUnknown());
- }
-
- /** Checks that the inferred type for [selector] is [mask]. */
- void checkSelectorHasType(Selector selector,
- TypeMask mask,
- TypeMask expectedMask) {
- Expect.equals(expectedMask, inferrer.getTypeOfSelector(selector, mask));
- }
-}
-
-const String DYNAMIC = '"__dynamic_for_test"';
-
-Future<AnalysisResult> analyze(String code, {int maxConcreteTypeSize: 1000}) {
- Uri uri = new Uri(scheme: 'dart', path: 'test');
- MockCompiler compiler = new MockCompiler.internal(
- enableConcreteTypeInference: true,
- maxConcreteTypeSize: maxConcreteTypeSize);
- compiler.diagnosticHandler = createHandler(compiler, code);
- compiler.registerSource(uri, code);
- compiler.typesTask.concreteTypesInferrer.testMode = true;
- return compiler.runCompiler(uri).then((_) {
- return new AnalysisResult(compiler);
- });
-}
-
-testDynamicBackDoor() {
- final String source = """
- main () {
- var x = $DYNAMIC;
- x;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasUnknownType('x');
- });
-}
-
-testVariableDeclaration() {
- final String source = r"""
- main() {
- var v1;
- var v2;
- v2 = 1;
- v1; v2;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('v1', [result.nullType]);
- result.checkNodeHasType('v2', [result.int]);
- });
-}
-
-testLiterals() {
- final String source = r"""
- main() {
- var v1 = 42;
- var v2 = 42.1;
- var v3 = 'abc';
- var v4 = true;
- var v5 = null;
- v1; v2; v3; v4; v5;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('v1', [result.int]);
- result.checkNodeHasType('v2', [result.double]);
- result.checkNodeHasType('v3', [result.string]);
- result.checkNodeHasType('v4', [result.bool]);
- result.checkNodeHasType('v5', [result.nullType]);
- });
-}
-
-testRedefinition() {
- final String source = r"""
- main() {
- var foo = 42;
- foo = 'abc';
- foo;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.string]);
- });
-}
-
-testIfThenElse() {
- final String source = r"""
- main() {
- var foo = 42;
- if (true) {
- foo = 'abc';
- } else {
- foo = false;
- }
- foo;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.string, result.bool]);
- });
-}
-
-testTernaryIf() {
- final String source = r"""
- main() {
- var foo = 42;
- foo = true ? 'abc' : false;
- foo;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.string, result.bool]);
- });
-}
-
-testWhile() {
- final String source = r"""
- class A { f() => new B(); }
- class B { f() => new C(); }
- class C { f() => new A(); }
- main() {
- var bar = null;
- var foo = new A();
- while(bar = 42) {
- foo = foo.f();
- }
- foo; bar;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType(
- 'foo',
- [result.base('A'), result.base('B'), result.base('C')]);
- // Check that the condition is evaluated.
- // TODO(polux): bar's type could be inferred to be {int} here.
- result.checkNodeHasType('bar', [result.int, result.nullType]);
- });
-}
-
-testDoWhile() {
- final String source = r"""
- class A { f() => new B(); }
- class B { f() => new C(); }
- class C { f() => new A(); }
- main() {
- var bar = null;
- var foo = new A();
- do {
- foo = foo.f();
- } while (bar = 42);
- foo; bar;
- }
- """;
- return analyze(source).then((AnalysisResult result) {
- result.checkNodeHasType(
- 'foo',
- [result.base('A'), result.base('B'), result.base('C')]);
- // Check that the condition is evaluated.
- result.checkNodeHasType('bar', [result.int]);
- });
-}
-
-testFor1() {
- final String source = r"""
- class A { f() => new B(); }
- class B { f() => new C(); }
- class C { f() => new A(); }
- main() {
- var foo = new A();
- for(;;) {
- foo = foo.f();
- }
- foo;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType(
- 'foo',
- [result.base('A'), result.base('B'), result.base('C')]);
- });
-}
-
-testFor2() {
- final String source = r"""
- class A { f() => new B(); test() => true; }
- class B { f() => new A(); test() => true; }
- main() {
- var bar = null;
- var foo = new A();
- for(var i = new A(); bar = 42; i = i.f()) {
- foo = i;
- }
- foo; bar;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.base('A'), result.base('B')]);
- // Check that the condition is evaluated.
- // TODO(polux): bar's type could be inferred to be {int} here.
- result.checkNodeHasType('bar', [result.int, result.nullType]);
- });
-}
-
-testFor3() {
- final String source = r"""
- main() {
- var i = 1;
- for(;;) {
- var x = 2;
- i = x;
- }
- i;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('i', [result.int]);
- });
-}
-
-testForIn() {
- final String source = r"""
- class MyIterator {
- var counter = 0;
-
- moveNext() {
- if (counter == 0) {
- counter = 1;
- return true;
- } else if (counter == 1) {
- counter = 2;
- return true;
- } else {
- return false;
- }
- }
-
- get current => (counter == 1) ? "foo" : 42;
- }
-
- class MyIterable {
- get iterator => new MyIterator();
- }
-
- main() {
- var res;
- for (var i in new MyIterable()) {
- res = i;
- }
- res;
- }
- """;
- return analyze(source).then((AnalysisResult result) {
- result.checkNodeHasType('res',
- [result.int, result.string, result.nullType]);
- });
-}
-
-testToplevelVariable() {
- final String source = r"""
- final top = 'abc';
- class A {
- f() => top;
- }
- main() {
- var foo = top;
- var bar = new A().f();
- foo; bar;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.string]);
- result.checkNodeHasType('bar', [result.string]);
- });
-}
-
-testToplevelVariable2() {
- final String source = r"""
- class A {
- var x;
- }
- final top = new A().x;
-
- main() {
- var a = new A();
- a.x = 42;
- a.x = "abc";
- var foo = top;
- foo;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.nullType, result.int,
- result.string]);
- });
-}
-
-testToplevelVariable3() {
- final String source = r"""
- var top = "a";
-
- f() => top;
-
- main() {
- var foo = f();
- var bar = top;
- top = 42;
- var baz = top;
- foo; bar; baz;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.int, result.string]);
- result.checkNodeHasType('bar', [result.int, result.string]);
- result.checkNodeHasType('baz', [result.int, result.string]);
- });
-}
-
-testNonRecusiveFunction() {
- final String source = r"""
- f(x, y) => true ? x : y;
- main() { var foo = f(42, "abc"); foo; }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.int, result.string]);
- });
-}
-
-testMultipleReturns() {
- final String source = r"""
- f(x, y) {
- if (true) return x;
- else return y;
- }
- main() { var foo = f(42, "abc"); foo; }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.int, result.string]);
- });
-}
-
-testRecusiveFunction() {
- final String source = r"""
- f(x) {
- if (true) return x;
- else return f(true ? x : "abc");
- }
- main() { var foo = f(42); foo; }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.int, result.string]);
- });
-}
-
-testMutuallyRecusiveFunction() {
- final String source = r"""
- f() => true ? 42 : g();
- g() => true ? "abc" : f();
- main() { var foo = f(); foo; }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.int, result.string]);
- });
-}
-
-testSimpleSend() {
- final String source = """
- class A {
- f(x) => x;
- }
- class B {
- f(x) => 'abc';
- }
- class C {
- f(x) => 3.14;
- }
- class D {
- var f; // we check that this field is ignored in calls to dynamic.f()
- D(this.f);
- }
- main() {
- new B(); new D(42); // we instantiate B and D but not C
- var foo = new A().f(42);
- var bar = $DYNAMIC.f(42);
- foo; bar;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.int]);
- result.checkNodeHasType('bar', [result.int, result.string]);
- });
-}
-
-testSendToThis1() {
- final String source = r"""
- class A {
- A();
- f() => g();
- g() => 42;
- }
- main() {
- var foo = new A().f();
- foo;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.int]);
- });
-}
-
-testSendToThis2() {
- final String source = r"""
- class A {
- foo() => this;
- }
- class B extends A {
- bar() => foo();
- }
- main() {
- var x = new B().bar();
- x;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('x', [result.base('B')]);
- });
-}
-
-testSendToThis3() {
- final String source = r"""
- class A {
- bar() => 42;
- foo() => bar();
- }
- class B extends A {
- bar() => "abc";
- }
- main() {
- var x = new B().foo();
- x;
- }
- """;
- return analyze(source).then((AnalysisResult result) {
- result.checkNodeHasType('x', [result.string]);
- });
-}
-
-testSendToThis4() {
- final String source = """
- class A {
- bar() => 42;
- foo() => bar();
- }
- class B extends A {
- bar() => "abc";
- }
- main() {
- new A(); new B(); // make A and B seen
- var x = $DYNAMIC.foo();
- x;
- }
- """;
- return analyze(source).then((AnalysisResult result) {
- result.checkNodeHasType('x', [result.int, result.string]);
- });
-}
-
-testConstructor() {
- final String source = r"""
- class A {
- var x, y, z;
- A(this.x, a) : y = a { z = 'abc'; }
- }
- main() {
- new A(42, 'abc');
- new A(true, null);
- }
- """;
- return analyze(source).then((result) {
- result.checkFieldHasType('A', 'x', [result.int, result.bool]);
- result.checkFieldHasType('A', 'y', [result.string, result.nullType]);
- result.checkFieldHasType('A', 'z', [result.string]);
- });
-}
-
-testGetters() {
- final String source = """
- class A {
- var x;
- A(this.x);
- get y => x;
- get z => y;
- }
- class B {
- var x;
- B(this.x);
- }
- main() {
- var a = new A(42);
- var b = new B('abc');
- var foo = a.x;
- var bar = a.y;
- var baz = a.z;
- var qux = null.x;
- var quux = $DYNAMIC.x;
- foo; bar; baz; qux; quux;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.int]);
- result.checkNodeHasType('bar', [result.int]);
- result.checkNodeHasType('baz', [result.int]);
- result.checkNodeHasType('qux', []);
- result.checkNodeHasType('quux', [result.int, result.string]);
- });
-}
-
-testDynamicGetters() {
- final String source = """
- class A {
- get x => f();
- f() => 42;
- }
- class B extends A {
- f() => "abc";
- }
- main() {
- new A(); new B(); // make A and B seen
- var x = $DYNAMIC.x;
- x;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('x', [result.int, result.string]);
- });
-}
-
-testToplevelGetters() {
- final String source = """
- int _x = 42;
- get x => _x;
-
- f() => x;
-
- main() {
- var foo = f();
- var bar = x;
- _x = "a";
- var baz = x;
- foo; bar; baz;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.int, result.string]);
- result.checkNodeHasType('bar', [result.int, result.string]);
- result.checkNodeHasType('baz', [result.int, result.string]);
- });
-}
-
-testSetters() {
- final String source = """
- class A {
- var x;
- var w;
- A(this.x, this.w);
- set y(a) { x = a; z = a; }
- set z(a) { w = a; }
- }
- class B {
- var x;
- B(this.x);
- }
- main() {
- var a = new A(42, 42);
- var b = new B(42);
- a.x = 'abc';
- a.y = true;
- null.x = 42; // should be ignored
- $DYNAMIC.x = null;
- $DYNAMIC.y = 3.14;
- }
- """;
- return analyze(source).then((result) {
- result.checkFieldHasType('B', 'x',
- [result.int, // new B(42)
- result.nullType]); // dynamic.x = null
- result.checkFieldHasType('A', 'x',
- [result.int, // new A(42, ...)
- result.string, // a.x = 'abc'
- result.bool, // a.y = true
- result.nullType, // dynamic.x = null
- result.double]); // dynamic.y = 3.14
- result.checkFieldHasType('A', 'w',
- [result.int, // new A(..., 42)
- result.bool, // a.y = true
- result.double]); // dynamic.y = 3.14
- });
-}
-
-testToplevelSetters() {
- final String source = """
- int _x = 42;
- set x(y) => _x = y;
-
- f(y) { x = y; }
-
- main() {
- var foo = _x;
- x = "a";
- var bar = _x;
- f(true);
- var baz = _x;
- foo; bar; baz;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.int, result.string, result.bool]);
- result.checkNodeHasType('bar', [result.int, result.string, result.bool]);
- result.checkNodeHasType('baz', [result.int, result.string, result.bool]);
- });
-}
-
-
-testOptionalNamedParameters() {
- final String source = r"""
- class A {
- var x, y, z, w;
- A(this.x, {this.y, this.z, this.w});
- }
- class B {
- var x, y;
- B(this.x, {this.y});
- }
- class C {
- var x, y;
- C(this.x, {this.y});
- }
- class Test {
- var a, b, c, d;
- var e, f;
- var g, h;
-
- Test(this.a, this.b, this.c, this.d,
- this.e, this.f,
- this.g, this.h);
-
- f1(x, {y, z, w}) {
- a = x;
- b = y;
- c = z;
- d = w;
- }
- f2(x, {y}) {
- e = x;
- f = y;
- }
- f3(x, {y}) {
- g = x;
- h = y;
- }
- }
- class Foo {
- }
- main() {
- // We want to test expiclitely for null later so we initialize all the
- // fields of Test with a placeholder type: Foo.
- var foo = new Foo();
- var test = new Test(foo, foo, foo, foo, foo, foo, foo, foo);
-
- new A(42);
- new A('abc', w: true, z: 42.1);
- test.f1(42);
- test.f1('abc', w: true, z: 42.1);
-
- new B('abc', y: true);
- new B(1, 2); // too many positional arguments
- test.f2('abc', y: true);
- test.f2(1, 2); // too many positional arguments
-
- new C('abc', y: true);
- new C(1, z: 2); // non-existing named parameter
- test.f3('abc', y: true);
- test.f3(1, z: 2); // non-existing named parameter
- }
- """;
- return analyze(source).then((result) {
-
- final foo = result.base('Foo');
- final nil = result.nullType;
-
- result.checkFieldHasType('A', 'x', [result.int, result.string]);
- result.checkFieldHasType('A', 'y', [nil]);
- result.checkFieldHasType('A', 'z', [nil, result.double]);
- result.checkFieldHasType('A', 'w', [nil, result.bool]);
- result.checkFieldHasType('Test', 'a', [foo, result.int, result.string]);
- result.checkFieldHasType('Test', 'b', [foo, nil]);
- result.checkFieldHasType('Test', 'c', [foo, nil, result.double]);
- result.checkFieldHasType('Test', 'd', [foo, nil, result.bool]);
-
- result.checkFieldHasType('B', 'x', [result.string]);
- result.checkFieldHasType('B', 'y', [result.bool]);
- result.checkFieldHasType('Test', 'e', [foo, result.string]);
- result.checkFieldHasType('Test', 'f', [foo, result.bool]);
-
- result.checkFieldHasType('C', 'x', [result.string]);
- result.checkFieldHasType('C', 'y', [result.bool]);
- result.checkFieldHasType('Test', 'g', [foo, result.string]);
- result.checkFieldHasType('Test', 'h', [foo, result.bool]);
- });
-}
-
-testOptionalPositionalParameters() {
- final String source = r"""
- class A {
- var x, y, z, w;
- A(this.x, [this.y, this.z, this.w]);
- }
- class B {
- var x, y;
- B(this.x, [this.y]);
- }
- class Test {
- var a, b, c, d;
- var e, f;
-
- Test(this.a, this.b, this.c, this.d,
- this.e, this.f);
-
- f1(x, [y, z, w]) {
- a = x;
- b = y;
- c = z;
- d = w;
- }
- f2(x, [y]) {
- e = x;
- f = y;
- }
- }
- class Foo {
- }
- main() {
- // We want to test expiclitely for null later so we initialize all the
- // fields of Test with a placeholder type: Foo.
- var foo = new Foo();
- var test = new Test(foo, foo, foo, foo, foo, foo);
-
- new A(42);
- new A('abc', true, 42.1);
- test.f1(42);
- test.f1('abc', true, 42.1);
-
- new B('a', true);
- new B(1, 2, 3); // too many arguments
- test.f2('a', true);
- test.f2(1, 2, 3); // too many arguments
- }
- """;
- return analyze(source).then((result) {
-
- final foo = result.base('Foo');
- final nil = result.nullType;
-
- result.checkFieldHasType('A', 'x', [result.int, result.string]);
- result.checkFieldHasType('A', 'y', [nil, result.bool]);
- result.checkFieldHasType('A', 'z', [nil, result.double]);
- result.checkFieldHasType('A', 'w', [nil]);
- result.checkFieldHasType('Test', 'a', [foo, result.int, result.string]);
- result.checkFieldHasType('Test', 'b', [foo, nil, result.bool]);
- result.checkFieldHasType('Test', 'c', [foo, nil, result.double]);
- result.checkFieldHasType('Test', 'd', [foo, nil]);
-
- result.checkFieldHasType('B', 'x', [result.string]);
- result.checkFieldHasType('B', 'y', [result.bool]);
- result.checkFieldHasType('Test', 'e', [foo, result.string]);
- result.checkFieldHasType('Test', 'f', [foo, result.bool]);
- });
-}
-
-testListLiterals() {
- final String source = r"""
- class A {
- var x;
- A(this.x);
- }
- main() {
- var x = [];
- var y = [1, "a", null, new A(42)];
- x; y;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('x', [result.growableList]);
- result.checkNodeHasType('y', [result.growableList]);
- result.checkFieldHasType('A', 'x', [result.int]);
- });
-}
-
-testMapLiterals() {
- final String source = r"""
- class A {
- var x;
- A(this.x);
- }
- main() {
- var x = {};
- var y = {'a': "foo", 'b': new A(42) };
- x; y;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('x', [result.map]);
- result.checkNodeHasType('y', [result.map]);
- result.checkFieldHasType('A', 'x', [result.int]);
- });
-}
-
-testReturn() {
- final String source = r"""
- f() { if (true) { return 1; }; return "a"; }
- g() { f(); return; }
- main() {
- var x = f();
- var y = g();
- x; y;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('x', [result.int, result.string]);
- result.checkNodeHasType('y', [result.nullType]);
- });
-}
-
-testNoReturn() {
- final String source = r"""
- f() { if (true) { return 1; }; }
- g() { f(); }
- main() {
- var x = f();
- var y = g();
- x; y;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('x', [result.int, result.nullType]);
- result.checkNodeHasType('y', [result.nullType]);
- });
-}
-
-testArithmeticOperators() {
- String source(op) {
- return """
- main() {
- var a = 1 $op 2;
- var b = 1 $op 2.1;
- var c = 1.1 $op 2;
- var d = 1.1 $op 2.1;
- var e = (1 $op 2.1) $op 1;
- var f = 1 $op (1 $op 2.1);
- var g = (1 $op 2.1) $op 1.1;
- var h = 1.1 $op (1 $op 2);
- var i = (1 $op 2) $op 1;
- var j = 1 $op (1 $op 2);
- var k = (1.1 $op 2.1) $op 1.1;
- var l = 1.1 $op (1.1 $op 2.1);
- a; b; c; d; e; f; g; h; i; j; k; l;
- }""";
- }
- return Future.forEach(['+', '*', '-'], (String op) {
- return analyze(source(op)).then((result) {
- result.checkNodeHasType('a', [result.int]);
- result.checkNodeHasType('b', [result.num]);
- result.checkNodeHasType('c', [result.num]);
- result.checkNodeHasType('d', [result.double]);
- result.checkNodeHasType('e', [result.num]);
- result.checkNodeHasType('f', [result.num]);
- result.checkNodeHasType('g', [result.num]);
- result.checkNodeHasType('h', [result.num]);
- result.checkNodeHasType('i', [result.int]);
- result.checkNodeHasType('j', [result.int]);
- result.checkNodeHasType('k', [result.double]);
- result.checkNodeHasType('l', [result.double]);
- });
- });
-}
-
-testBooleanOperators() {
- String source(op) {
- return """
- main() {
- var a = true $op null;
- var b = null $op true;
- var c = 1 $op true;
- var d = true $op "a";
- a; b; c; d;
- }""";
- }
- return Future.forEach(['&&', '||'], (String op) {
- return analyze(source(op)).then((result) {
- result.checkNodeHasType('a', [result.bool]);
- result.checkNodeHasType('b', [result.bool]);
- result.checkNodeHasType('c', [result.bool]);
- result.checkNodeHasType('d', [result.bool]);
- });
- });
-}
-
-testBooleanOperatorsShortCirtcuit() {
- String source(op) {
- return """
- main() {
- var x = null;
- "foo" $op (x = 42);
- x;
- }""";
- }
- return Future.forEach(['&&', '||'], (String op) {
- return analyze(source(op)).then((AnalysisResult result) {
- result.checkNodeHasType('x', [result.nullType, result.int]);
- });
- });
-}
-
-testOperators() {
- final String source = r"""
- class A {
- operator <(x) => 42;
- operator <<(x) => "a";
- }
- main() {
- var x = new A() < "foo";
- var y = new A() << "foo";
- x; y;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('x', [result.int]);
- result.checkNodeHasType('y', [result.string]);
- });
-}
-
-testSetIndexOperator() {
- final String source = r"""
- class A {
- var witness1;
- var witness2;
- operator []=(i, x) { witness1 = i; witness2 = x; }
- }
- main() {
- var x = new A()[42] = "abc";
- x;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('x', [result.string]);
- result.checkFieldHasType('A', 'witness1', [result.int, result.nullType]);
- result.checkFieldHasType('A', 'witness2', [result.string, result.nullType]);
- });
-}
-
-testCompoundOperators1() {
- final String source = r"""
- class A {
- operator +(x) => "foo";
- }
- main() {
- var x1 = 1;
- x1++;
- var x2 = 1;
- ++x2;
- var x3 = 1;
- x3 += 42;
- var x4 = new A();
- x4++;
- var x5 = new A();
- ++x5;
- var x6 = new A();
- x6 += true;
-
- x1; x2; x3; x4; x5; x6;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('x1', [result.int]);
- result.checkNodeHasType('x2', [result.int]);
- result.checkNodeHasType('x3', [result.int]);
- result.checkNodeHasType('x4', [result.string]);
- result.checkNodeHasType('x5', [result.string]);
- result.checkNodeHasType('x6', [result.string]);
- });
-}
-
-
-testCompoundOperators2() {
- final String source = r"""
- class A {
- var xx;
- var yy;
- var witness1;
- var witness2;
- var witness3;
- var witness4;
-
- A(this.xx, this.yy);
- get x { witness1 = "foo"; return xx; }
- set x(a) { witness2 = "foo"; xx = a; }
- get y { witness3 = "foo"; return yy; }
- set y(a) { witness4 = "foo"; yy = a; }
- }
- main () {
- var a = new A(1, 1);
- a.x++;
- a.y++;
- }
- """;
- return analyze(source).then((result) {
- result.checkFieldHasType('A', 'xx', [result.int]);
- result.checkFieldHasType('A', 'yy', [result.int]);
- result.checkFieldHasType('A', 'witness1', [result.string, result.nullType]);
- result.checkFieldHasType('A', 'witness2', [result.string, result.nullType]);
- result.checkFieldHasType('A', 'witness3', [result.string, result.nullType]);
- result.checkFieldHasType('A', 'witness4', [result.string, result.nullType]);
- });
-}
-
-testInequality() {
- final String source = r"""
- class A {
- var witness;
- operator ==(x) { witness = "foo"; return "abc"; }
- }
- class B {
- operator ==(x) { throw "error"; }
- }
- main() {
- var foo = 1 != 2;
- var bar = (new A() != 2);
- var baz = (new B() != 2);
- foo; bar; baz;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.bool]);
- result.checkNodeHasType('bar', [result.bool]);
- // TODO(polux): could be even better: empty
- result.checkNodeHasType('baz', [result.bool]);
- result.checkFieldHasType('A', 'witness', [result.string, result.nullType]);
- });
-}
-
-testFieldInitialization1() {
- final String source = r"""
- class A {
- var x;
- var y = 1;
- }
- class B extends A {
- var z = "foo";
- }
- main () {
- // we need to access y and z once to trigger their analysis
- new B().y;
- new B().z;
- }
- """;
- return analyze(source).then((result) {
- result.checkFieldHasType('A', 'x', [result.nullType]);
- result.checkFieldHasType('A', 'y', [result.int]);
- result.checkFieldHasType('B', 'z', [result.string]);
- });
-}
-
-testFieldInitialization2() {
- final String source = r"""
- var top = 42;
- class A {
- var x = top;
- }
- main () {
- // we need to access X once to trigger its analysis
- new A().x;
- }
- """;
- return analyze(source).then((result) {
- result.checkFieldHasType('A', 'x', [result.int]);
- });
-}
-
-testFieldInitialization3() {
- final String source = r"""
- class A {
- var x;
- }
- f() => new A().x;
- class B {
- var x = new A().x;
- var y = f();
- }
- main () {
- var foo = new B().x;
- var bar = new B().y;
- new A().x = "a";
- foo; bar;
- }
- """;
- return analyze(source).then((result) {
- // checks that B.B is set as a reader of A.x
- result.checkFieldHasType('B', 'x', [result.nullType, result.string]);
- // checks that B.B is set as a caller of f
- result.checkFieldHasType('B', 'y', [result.nullType, result.string]);
- // checks that readers of x are notified by changes in x's type
- result.checkNodeHasType('foo', [result.nullType, result.string]);
- // checks that readers of y are notified by changes in y's type
- result.checkNodeHasType('bar', [result.nullType, result.string]);
- });
-}
-
-testLists() {
- final String source = """
- class A {}
- class B {}
- class C {}
- class D {}
- class E {}
- class F {}
- class G {}
-
- main() {
- var l1 = [new A()];
- var l2 = [];
- l1['a'] = new B(); // raises an error, so B should not be recorded
- l1[1] = new C();
- l1.add(new D());
- l1.insert('a', new E()); // raises an error, so E should not be recorded
- l1.insert(1, new F());
- $DYNAMIC[1] = new G();
- var x1 = l1[1];
- var x2 = l2[1];
- var x3 = l1['foo']; // raises an error, should return empty
- var x4 = l1.removeAt(1);
- var x5 = l2.removeAt(1);
- var x6 = l1.removeAt('a'); // raises an error, should return empty
- var x7 = l1.removeLast();
- var x8 = l2.removeLast();
- x1; x2; x3; x4; x5; x6; x7; x8;
- }""";
- return analyze(source).then((result) {
- final expectedTypes = ['A', 'C', 'D', 'F', 'G'].map(result.base).toList();
- result.checkNodeHasType('x1', expectedTypes);
- result.checkNodeHasType('x2', expectedTypes);
- result.checkNodeHasType('x3', []);
- result.checkNodeHasType('x4', expectedTypes);
- result.checkNodeHasType('x5', expectedTypes);
- result.checkNodeHasType('x6', []);
- result.checkNodeHasType('x7', expectedTypes);
- result.checkNodeHasType('x8', expectedTypes);
- });
-}
-
-testListWithCapacity() {
- final String source = r"""
- main() {
- var l = new List(10);
- var x = [][0];
- x;
- }""";
- return analyze(source).then((result) {
- result.checkNodeHasType('x', [result.nullType]);
- });
-}
-
-testEmptyList() {
- final String source = r"""
- main() {
- var l = new List();
- var x = l[0];
- x;
- }""";
- return analyze(source).then((result) {
- result.checkNodeHasType('x', []);
- });
-}
-
-testSendWithWrongArity() {
- final String source = r"""
- f(x) { }
- class A { g(x) { } }
- main () {
- var x = f();
- var y = f(1, 2);
- var z = new A().g();
- var w = new A().g(1, 2);
- x; y; z; w;
- }
- """;
- return analyze(source).then((result) {
- // TODO(polux): It would be better if x and y also had the empty type. This
- // requires a change in SimpleTypeInferrerVisitor.visitStaticSend which
- // would impact the default type inference and possibly break dart2js.
- // Keeping this change for a later CL.
- result.checkNodeHasUnknownType('x');
- result.checkNodeHasUnknownType('y');
- result.checkNodeHasType('z', []);
- result.checkNodeHasType('w', []);
- });
-}
-
-testBigTypesWidening1() {
- final String source = r"""
- small() => true ? 1 : 'abc';
- big() => true ? 1 : (true ? 'abc' : false);
- main () {
- var x = small();
- var y = big();
- x; y;
- }
- """;
- return analyze(source, maxConcreteTypeSize: 2).then((result) {
- result.checkNodeHasType('x', [result.int, result.string]);
- result.checkNodeHasUnknownType('y');
- });
-}
-
-testBigTypesWidening2() {
- final String source = r"""
- class A {
- var x, y;
- A(this.x, this.y);
- }
- main () {
- var a = new A(1, 1);
- a.x = 'abc';
- a.y = 'abc';
- a.y = true;
- }
- """;
- return analyze(source, maxConcreteTypeSize: 2).then((result) {
- result.checkFieldHasType('A', 'x', [result.int, result.string]);
- result.checkFieldHasUknownType('A', 'y');
- });
-}
-
-testDynamicIsAbsorbing() {
- final String source = """
- main () {
- var x = 1;
- if (true) {
- x = $DYNAMIC;
- } else {
- x = 42;
- }
- x;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasUnknownType('x');
- });
-}
-
-testJsCall() {
- final String source = r"""
- import 'dart:_foreign_helper';
- import 'dart:_interceptors';
-
- abstract class AbstractA {}
- class A extends AbstractA {}
- class B extends A {}
- class BB extends B {}
- class C extends A {}
- class D implements A {}
- class E extends A {}
-
- class X {}
-
- main () {
- // we don't create any E on purpose
- new B(); new BB(); new C(); new D();
-
- var a = JS('', '1');
- var b = JS('Object', '1');
- var c = JS('JSExtendableArray', '1');
- var cNull = JS('JSExtendableArray|Null', '1');
- var d = JS('String', '1');
- var dNull = JS('String|Null', '1');
- var e = JS('int', '1');
- var eNull = JS('int|Null', '1');
- var f = JS('double', '1');
- var fNull = JS('double|Null', '1');
- var g = JS('num', '1');
- var gNull = JS('num|Null', '1');
- var h = JS('bool', '1');
- var hNull = JS('bool|Null', '1');
- var i = JS('AbstractA', '1');
- var iNull = JS('AbstractA|Null', '1');
-
- a; b; c; cNull; d; dNull; e; eNull; f; fNull; g; gNull; h; hNull; i;
- iNull;
- }
- """;
- return analyze(source, maxConcreteTypeSize: 6).then((result) {
- List maybe(List types) => new List.from(types)..add(result.nullType);
- // a and b have all the types seen by the resolver, which are more than 6
- result.checkNodeHasUnknownType('a');
- result.checkNodeHasUnknownType('b');
- final expectedCType = [result.growableList];
- result.checkNodeHasType('c', expectedCType);
- result.checkNodeHasType('cNull', maybe(expectedCType));
- final expectedDType = [result.string];
- result.checkNodeHasType('d', expectedDType);
- result.checkNodeHasType('dNull', maybe(expectedDType));
- final expectedEType = [result.int];
- result.checkNodeHasType('e', expectedEType);
- result.checkNodeHasType('eNull', maybe(expectedEType));
- final expectedFType = [result.num];
- result.checkNodeHasType('f', expectedFType);
- result.checkNodeHasType('fNull', maybe(expectedFType));
- final expectedGType = [result.num];
- result.checkNodeHasType('g', expectedGType);
- result.checkNodeHasType('gNull', maybe(expectedGType));
- final expectedType = [result.bool];
- result.checkNodeHasType('h', expectedType);
- result.checkNodeHasType('hNull', maybe(expectedType));
- final expectedIType = [result.base('B'),
- result.base('BB'),
- result.base('C'),
- result.base('D')];
- result.checkNodeHasType('i', expectedIType);
- result.checkNodeHasType('iNull', maybe(expectedIType));
- });
-}
-
-testJsCallAugmentsSeenClasses() {
- final String source1 = """
- main () {
- var x = $DYNAMIC.truncate();
- x;
- }
- """;
- return analyze(source1).then((AnalysisResult result) {
- result.checkNodeHasType('x', []);
- }).whenComplete(() {
-
- final String source2 = """
- import 'dart:_foreign_helper';
-
- main () {
- var x = $DYNAMIC.truncate();
- JS('double', 'foo');
- x;
- }
- """;
- return analyze(source2).then((AnalysisResult result) {
- result.checkNodeHasType('x', [result.int]);
- });
- });
-}
-
-testIsCheck() {
- final String source = r"""
- main () {
- var x = (1 is String);
- x;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('x', [result.bool]);
- });
-}
-
-testSeenClasses() {
- final String source = """
- class A {
- witness() => 42;
- }
- class B {
- witness() => "string";
- }
- class AFactory {
- onlyCalledInAFactory() => new A();
- }
- class BFactory {
- onlyCalledInAFactory() => new B();
- }
-
- main() {
- new AFactory().onlyCalledInAFactory();
- new BFactory();
- // should be of type {int} and not {int, String} since B is unreachable
- var foo = $DYNAMIC.witness();
- foo;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.int]);
- });
-}
-
-testIntDoubleNum() {
- final String source = r"""
- main() {
- var a = 1;
- var b = 1.1;
- var c = true ? 1 : 1.1;
- a; b; c;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('a', [result.int]);
- result.checkNodeHasType('b', [result.double]);
- result.checkNodeHasType('c', [result.num]);
- });
-}
-
-testConcreteTypeToTypeMask() {
- final String source = r"""
- class A {}
- class B extends A {}
- class C extends A {}
- class D implements A {}
- main() {
- new A();
- new B();
- new C();
- new D();
- }
- """;
- return analyze(source).then((result) {
-
- convert(ConcreteType type) {
- return result.compiler.typesTask.concreteTypesInferrer
- .types.concreteTypeToTypeMask(type);
- }
-
- final nullSingleton =
- result.compiler.typesTask.concreteTypesInferrer.singletonConcreteType(
- new NullBaseType());
-
- singleton(ClassElement element) {
- return result.compiler.typesTask.concreteTypesInferrer
- .singletonConcreteType(new ClassBaseType(element));
- }
-
- var world = result.compiler.world;
-
- ClassElement a = findElement(result.compiler, 'A');
- ClassElement b = findElement(result.compiler, 'B');
- ClassElement c = findElement(result.compiler, 'C');
- ClassElement d = findElement(result.compiler, 'D');
-
- for (ClassElement cls in [a, b, c, d]) {
- Expect.equals(convert(singleton(cls)),
- new TypeMask.nonNullExact(cls, world));
- }
-
- for (ClassElement cls in [a, b, c, d]) {
- Expect.equals(convert(singleton(cls).union(nullSingleton)),
- new TypeMask.exact(cls, world));
- }
-
- Expect.equals(convert(singleton(a).union(singleton(b))),
- new TypeMask.nonNullSubclass(a, world));
-
- Expect.equals(
- convert(singleton(a).union(singleton(b)).union(nullSingleton)),
- new TypeMask.subclass(a, world));
-
- Expect.equals(
- simplify(convert(singleton(b).union(singleton(d))), result.compiler),
- new TypeMask.nonNullSubtype(a, world));
- });
-}
-
-testSelectors() {
- final String source = r"""
- // ABC <--- A
- // `- BC <--- B
- // `- C
-
- class ABC {}
- class A extends ABC {}
- class BC extends ABC {}
- class B extends BC {}
- class C extends BC {}
-
- class XY {}
- class X extends XY { foo() => new B(); }
- class Y extends XY { foo() => new C(); }
- class Z { foo() => new A(); }
-
- main() {
- new X().foo();
- new Y().foo();
- new Z().foo();
- }
- """;
- return analyze(source).then((result) {
-
- var world = result.compiler.world;
-
- ClassElement a = findElement(result.compiler, 'A');
- ClassElement b = findElement(result.compiler, 'B');
- ClassElement c = findElement(result.compiler, 'C');
- ClassElement xy = findElement(result.compiler, 'XY');
- ClassElement x = findElement(result.compiler, 'X');
- ClassElement y = findElement(result.compiler, 'Y');
- ClassElement z = findElement(result.compiler, 'Z');
-
- Selector foo =
- new Selector.call(const PublicName("foo"), CallStructure.NO_ARGS);
-
- result.checkSelectorHasType(
- foo,
- null,
- new TypeMask.unionOf([a, b, c]
- .map((cls) => new TypeMask.nonNullExact(cls, world)),
- result.compiler.world));
- result.checkSelectorHasType(
- foo,
- new TypeMask.subclass(x, world),
- new TypeMask.nonNullExact(b, world));
- result.checkSelectorHasType(
- foo,
- new TypeMask.subclass(y, world),
- new TypeMask.nonNullExact(c, world));
- result.checkSelectorHasType(
- foo,
- new TypeMask.subclass(z, world),
- new TypeMask.nonNullExact(a, world));
- result.checkSelectorHasType(
- foo,
- new TypeMask.subclass(xy, world),
- new TypeMask.unionOf([b, c].map((cls) =>
- new TypeMask.nonNullExact(cls, world)), world));
-
- result.checkSelectorHasType(
- new Selector.call(const PublicName("bar"), CallStructure.NO_ARGS),
- null, null);
- });
-}
-
-testEqualsNullSelector() {
- final String source = r"""
- main() {
- 1 == null;
- }
- """;
- return analyze(source).then((result) {
- ClassElement bool = result.compiler.backend.boolImplementation;
- result.checkSelectorHasType(new Selector.binaryOperator('=='),
- null,
- new TypeMask.nonNullExact(bool,
- result.compiler.world));
- });
-}
-
-testMixins() {
- final String source = r"""
- class A {
- foo() => "abc";
- get x => 42;
- }
- class B extends Object with A {
- bar() => foo();
- baz() => x;
- }
- main() {
- var b = new B();
- var x = b.foo();
- var y = b.bar();
- var z = b.x;
- var w = b.baz();
- x; y; z; w;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('x', [result.string]);
- result.checkNodeHasType('y', [result.string]);
- result.checkNodeHasType('z', [result.int]);
- result.checkNodeHasType('w', [result.int]);
- });
-}
-
-testClosures1() {
- final String source = r"""
- class A {
- final foo = 42;
- }
- class B {
- final foo = "abc";
- }
- class C {
- final foo = true;
- }
- main() {
- var a;
- var f = (x) {
- a = x.foo;
- };
- // We make sure that x doesn't have type dynamic by adding C to the
- // set of seen classes and by checking that a's type doesn't contain
- // bool.
- new C();
- f(new A());
- f(new B());
- a;
- }
- """;
- return analyze(source).then((AnalysisResult result) {
- result.checkNodeHasType('a', [result.nullType, result.int, result.string]);
- });
-}
-
-testClosures2() {
- final String source = r"""
- class A {
- final foo = 42;
- }
- class B {
- final foo = "abc";
- }
- class C {
- final foo = true;
- }
- main() {
- // We make sure that x doesn't have type dynamic by adding C to the
- // set of seen classes and by checking that a's type doesn't contain
- // bool.
- new C();
-
- var a;
- f(x) {
- a = x.foo;
- }
- f(new A());
- f(new B());
- a; f;
- }
- """;
- return analyze(source).then((AnalysisResult result) {
- result.checkNodeHasType('a', [result.nullType, result.int, result.string]);
- result.checkNodeHasType('f', [result.functionType]);
- });
-}
-
-testClosures3() {
- final String source = r"""
- class A {
- var g;
- A(this.g);
- }
- main() {
- var foo = new A((x) => x).g(42);
- foo;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.int]);
- });
-}
-
-testClosures4() {
- final String source = """
- class A {
- var f = $DYNAMIC;
- }
- main() {
- var f = (x) => x;
- var g = (x) => "a";
- var h = (x, y) => true;
-
- var foo = $DYNAMIC(42);
- var bar = new A().f(1.2);
- var baz = $DYNAMIC.f(null);
-
- foo; bar; baz;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.int, result.string]);
- result.checkNodeHasType('bar', [result.double, result.string]);
- result.checkNodeHasType('baz', [result.nullType, result.string]);
- });
-}
-
-testClosures5() {
- final String source = r"""
- f(x) => x;
- class A {
- var g;
- A(this.g);
- }
- main() {
- var foo = new A(f).g(42);
- foo;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.int]);
- });
-}
-
-testClosures6() {
- final String source = r"""
- class A {
- var g;
- A(this.g);
- }
- class B {
- f(x) => x;
- }
- main() {
- var foo = new A(new B().f).g(42);
- foo;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.int]);
- });
-}
-
-testClosures7() {
- final String source = r"""
- class A {
- final x = 42;
- f() => () => x;
- }
- main() {
- var foo = new A().f()();
- foo;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.int]);
- });
-}
-
-testClosures8() {
- final String source = r"""
- class A {
- final x = 42;
- f() => () => x;
- }
- class B extends A {
- get x => "a";
- }
- main() {
- var foo = new B().f()();
- foo;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.string]);
- });
-}
-
-testClosures9() {
- final String source = r"""
- class A {
- g() => 42;
- f() => () => g();
- }
- class B extends A {
- g() => "a";
- }
- main() {
- var foo = new B().f()();
- foo;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.string]);
- });
-}
-
-testClosures10() {
- final String source = r"""
- class A {
- f() => 42;
- }
- main() {
- var a = new A();
- g() => a.f();
- var foo = g();
- foo; a;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.int]);
- });
-}
-
-testClosures11() {
- final String source = r"""
- class A {
- var x;
- f() => x;
- }
- main() {
- var a = new A();
- f() => a.f();
- a.x = 42;
- var foo = f();
- foo;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.nullType, result.int]);
- });
-}
-
-testClosures12() {
- final String source = r"""
- var f = (x) => x;
- main() {
- var foo = f(1);
- foo;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.int]);
- });
-}
-
-testRefinement() {
- final String source = """
- class A {
- f() => null;
- g() => 42;
- }
- class B {
- g() => "aa";
- }
- main() {
- var x = $DYNAMIC ? new A() : new B();
- x.f();
- var foo = x.g();
- foo;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('foo', [result.int]);
- });
-}
-
-testDefaultArguments() {
- final String source = r"""
- f1([x = 42]) => x;
- g1([x]) => x;
-
- f2({x: 42}) => x;
- g2({x}) => x;
-
- main() {
- var xf1 = f1();
- var xg1 = g1();
- var xf2 = f2();
- var xg2 = g2();
- xf1; xg1; xf2; xg2;
- }
- """;
- return analyze(source).then((result) {
- result.checkNodeHasType('xf1', [result.int]);
- result.checkNodeHasType('xg1', [result.nullType]);
- result.checkNodeHasType('xf2', [result.int]);
- result.checkNodeHasType('xg2', [result.nullType]);
- });
-}
-
-testSuperConstructorCall() {
- final String source = r"""
- class A {
- final x;
- A(this.x);
- }
-
- class B extends A {
- B(x) : super(x);
- }
- main() {
- var b = new B(42);
- var foo = b.x;
- foo;
- }
- """;
- return analyze(source).then((result) {
- result.checkFieldHasType('A', 'x', [result.int]);
- result.checkNodeHasType('foo', [result.int]);
- });
-}
-
-testSuperConstructorCall2() {
- final String source = r"""
- class A {
- var x;
- A() {
- x = 42;
- }
- }
- class B extends A {
- }
- main() {
- new B();
- }
- """;
- return analyze(source).then((result) {
- result.checkFieldHasType('A', 'x', [result.int]);
- });
-}
-
-testSuperConstructorCall3() {
- final String source = r"""
- class A {
- var x;
- A() {
- x = 42;
- }
- }
- class B extends A {
- B(unused) {}
- }
- main() {
- new B("abc");
- }
- """;
- return analyze(source).then((result) {
- result.checkFieldHasType('A', 'x', [result.int]);
- });
-}
-
-void main() {
- asyncTest(() => Future.forEach([
- testDynamicBackDoor,
- testVariableDeclaration,
- testLiterals,
- testRedefinition,
- testIfThenElse,
- testTernaryIf,
- testWhile,
- testDoWhile,
- testFor1,
- testFor2,
- testFor3,
- testForIn,
- testToplevelVariable,
- testToplevelVariable2,
- testToplevelVariable3,
- testNonRecusiveFunction,
- testMultipleReturns,
- testRecusiveFunction,
- testMutuallyRecusiveFunction,
- testSimpleSend,
- testSendToThis1,
- testSendToThis2,
- testSendToThis3,
- testSendToThis4,
- testConstructor,
- testGetters,
- testToplevelGetters,
- testDynamicGetters,
- testSetters,
- testToplevelSetters,
- testOptionalNamedParameters,
- testOptionalPositionalParameters,
- testListLiterals,
- testMapLiterals,
- testReturn,
- testNoReturn,
- testArithmeticOperators,
- testBooleanOperators,
- testBooleanOperatorsShortCirtcuit,
- testOperators,
- testCompoundOperators1,
- testCompoundOperators2,
- testSetIndexOperator,
- testInequality,
- testFieldInitialization1,
- testFieldInitialization2,
- testFieldInitialization3,
- testSendWithWrongArity,
- testBigTypesWidening1,
- testBigTypesWidening2,
- testDynamicIsAbsorbing,
- testLists,
- testListWithCapacity,
- testEmptyList,
- testJsCall,
- testJsCallAugmentsSeenClasses,
- testIsCheck,
- testSeenClasses,
- testIntDoubleNum,
- testConcreteTypeToTypeMask,
- testSelectors,
- // TODO(polux): this test is failing, see http://dartbug.com/16825.
- //testEqualsNullSelector,
- testMixins,
- testClosures1,
- testClosures2,
- testClosures3,
- testClosures4,
- testClosures5,
- testClosures6,
- testClosures7,
- testClosures8,
- testClosures9,
- testClosures10,
- testClosures11,
- testClosures12,
- testRefinement,
- testDefaultArguments,
- testSuperConstructorCall,
- testSuperConstructorCall2,
- testSuperConstructorCall3,
- ], (f) => f()));
-}
diff --git a/tests/compiler/dart2js/diagnostic_reporter_helper.dart b/tests/compiler/dart2js/diagnostic_reporter_helper.dart
new file mode 100644
index 0000000..0bff795
--- /dev/null
+++ b/tests/compiler/dart2js/diagnostic_reporter_helper.dart
@@ -0,0 +1,75 @@
+// Copyright (c) 2015, 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.
+
+library dart2js.diagnostic_reporter.helper;
+
+import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
+import 'package:compiler/src/diagnostics/messages.dart';
+import 'package:compiler/src/diagnostics/spannable.dart';
+import 'package:compiler/src/diagnostics/source_span.dart';
+import 'package:compiler/src/elements/elements.dart';
+
+abstract class DiagnosticReporterWrapper extends DiagnosticReporter {
+ DiagnosticReporter get reporter;
+
+ @override
+ DiagnosticMessage createMessage(
+ Spannable spannable,
+ MessageKind messageKind,
+ [Map arguments = const {}]) {
+ return reporter.createMessage(spannable, messageKind, arguments);
+ }
+
+ @override
+ internalError(Spannable spannable, message) {
+ return reporter.internalError(spannable, message);
+ }
+
+ @override
+ void log(message) {
+ return reporter.log(message);
+ }
+
+ @override
+ DiagnosticOptions get options => reporter.options;
+
+ @override
+ void reportError(
+ DiagnosticMessage message,
+ [List<DiagnosticMessage> infos = const <DiagnosticMessage> []]) {
+ reporter.reportError(message, infos);
+ }
+
+ @override
+ void reportHint(
+ DiagnosticMessage message,
+ [List<DiagnosticMessage> infos = const <DiagnosticMessage> []]) {
+ reporter.reportHint(message, infos);
+ }
+
+ @override
+ void reportInfo(
+ Spannable node,
+ MessageKind errorCode,
+ [Map arguments = const {}]) {
+ reporter.reportInfo(node, errorCode, arguments);
+ }
+
+ @override
+ void reportWarning(
+ DiagnosticMessage message,
+ [List<DiagnosticMessage> infos = const <DiagnosticMessage> []]) {
+ reporter.reportWarning(message, infos);
+ }
+
+ @override
+ SourceSpan spanFromSpannable(Spannable node) {
+ return reporter.spanFromSpannable(node);
+ }
+
+ @override
+ withCurrentElement(Element element, f()) {
+ return reporter.withCurrentElement(element, f);
+ }
+}
diff --git a/tests/compiler/dart2js/dump_info_test.dart b/tests/compiler/dart2js/dump_info_test.dart
index 2f3d022..575d6d6 100644
--- a/tests/compiler/dart2js/dump_info_test.dart
+++ b/tests/compiler/dart2js/dump_info_test.dart
@@ -102,8 +102,6 @@
var compiler = result.compiler;
Expect.isFalse(compiler.compilationFailed);
var dumpTask = compiler.dumpInfoTask;
- dumpTask.collectInfo();
- var info = dumpTask.infoCollector;
StringBuffer sb = new StringBuffer();
dumpTask.dumpInfoJson(sb);
diff --git a/tests/compiler/dart2js/exit_code_test.dart b/tests/compiler/dart2js/exit_code_test.dart
index acb111b..ff03975 100644
--- a/tests/compiler/dart2js/exit_code_test.dart
+++ b/tests/compiler/dart2js/exit_code_test.dart
@@ -17,6 +17,7 @@
import 'package:compiler/src/compile_time_constants.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/dart2js.dart' as entry;
+import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
import 'package:compiler/src/diagnostics/invariant.dart';
import 'package:compiler/src/diagnostics/messages.dart';
import 'package:compiler/src/diagnostics/spannable.dart';
@@ -28,11 +29,13 @@
import 'package:compiler/src/old_to_new_api.dart';
import 'package:compiler/src/resolution/resolution.dart';
import 'package:compiler/src/scanner/scanner_task.dart';
+import 'diagnostic_reporter_helper.dart';
class TestCompiler extends apiimpl.Compiler {
final String testMarker;
final String testType;
final Function onTest;
+ DiagnosticReporter reporter;
TestCompiler(api.CompilerInput inputProvider,
api.CompilerOutput outputProvider,
@@ -50,6 +53,7 @@
packageRoot, options, environment, packageConfig, findPackages) {
scanner = new TestScanner(this);
resolver = new TestResolver(this, backend.constantCompilerTask);
+ reporter = new TestDiagnosticReporter(this, super.reporter);
test('Compiler');
}
@@ -78,13 +82,6 @@
return super.codegen(work, world);
}
- withCurrentElement(Element element, f()) {
- return super.withCurrentElement(element, () {
- test('Compiler.withCurrentElement');
- return f();
- });
- }
-
test(String marker) {
if (marker == testMarker) {
switch (testType) {
@@ -98,19 +95,19 @@
break;
case 'warning':
onTest(testMarker, testType);
- reportWarning(createMessage(
+ reporter.reportWarningMessage(
NO_LOCATION_SPANNABLE,
- MessageKind.GENERIC, {'text': marker}));
+ MessageKind.GENERIC, {'text': marker});
break;
case 'error':
onTest(testMarker, testType);
- reportError(createMessage(
+ reporter.reportErrorMessage(
NO_LOCATION_SPANNABLE,
- MessageKind.GENERIC, {'text': marker}));
+ MessageKind.GENERIC, {'text': marker});
break;
case 'internalError':
onTest(testMarker, testType);
- internalError(NO_LOCATION_SPANNABLE, marker);
+ reporter.internalError(NO_LOCATION_SPANNABLE, marker);
break;
case 'NoSuchMethodError':
onTest(testMarker, testType);
@@ -124,6 +121,21 @@
}
}
+class TestDiagnosticReporter extends DiagnosticReporterWrapper {
+ final TestCompiler compiler;
+ final DiagnosticReporter reporter;
+
+ TestDiagnosticReporter(this.compiler, this.reporter);
+
+ @override
+ withCurrentElement(Element element, f()) {
+ return super.withCurrentElement(element, () {
+ compiler.test('Compiler.withCurrentElement');
+ return f();
+ });
+ }
+}
+
class TestScanner extends ScannerTask {
TestScanner(TestCompiler compiler) : super(compiler);
diff --git a/tests/compiler/dart2js/find_my_name_test.dart b/tests/compiler/dart2js/find_my_name_test.dart
index 60aba02c..dd93af3 100644
--- a/tests/compiler/dart2js/find_my_name_test.dart
+++ b/tests/compiler/dart2js/find_my_name_test.dart
@@ -36,7 +36,7 @@
testClass(String code, MockCompiler compiler) {
int skip = code.indexOf('{');
ClassElementX cls = parseUnit(code, compiler, compiler.mainApp).head;
- cls.parseNode(compiler);
+ cls.parseNode(compiler.parsing);
cls.forEachLocalMember((Element e) {
String name = e.name;
if (e.isConstructor) {
diff --git a/tests/compiler/dart2js/inference_stats_test.dart b/tests/compiler/dart2js/inference_stats_test.dart
new file mode 100644
index 0000000..e742b0a
--- /dev/null
+++ b/tests/compiler/dart2js/inference_stats_test.dart
@@ -0,0 +1,339 @@
+// Copyright (c) 2015, 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.
+// SharedOptions=-Dsend_stats=true
+
+/// Tests that we compute send metrics correctly in many simple scenarios.
+library dart2js.test.send_measurements_test;
+
+import 'dart:async';
+import 'package:test/test.dart';
+import 'package:dart2js_info/info.dart';
+import 'memory_compiler.dart';
+import 'dart:io';
+
+main() {
+ test('nothing is reachable, nothing to count', () {
+ return _check('''
+ main() {}
+ test() { int x = 3; }
+ ''');
+ });
+
+ test('local variable read', () {
+ return _check('''
+ main() => test();
+ test() { int x = 3; int y = x; }
+ ''',
+ localSend: 1); // from `int y = x`;
+ });
+
+ test('generative constructor call', () {
+ return _check('''
+ class A {
+ get f => 1;
+ }
+ main() => test();
+ test() { new A(); }
+ ''',
+ constructorSend: 1); // from new A()
+ });
+
+ group('instance call', () {
+ test('monomorphic only one implementor', () {
+ return _check('''
+ class A {
+ get f => 1;
+ }
+ main() => test();
+ test() { new A().f; }
+ ''',
+ constructorSend: 1, // new A()
+ instanceSend: 1); // f resolved to A.f
+ });
+
+ test('monomorphic only one type possible from types', () {
+ return _check('''
+ class A {
+ get f => 1;
+ }
+ class B extends A {
+ get f => 1;
+ }
+ main() => test();
+ test() { new B().f; }
+ ''',
+ constructorSend: 1,
+ instanceSend: 1); // f resolved to B.f
+ });
+
+ test('monomorphic only one type possible from liveness', () {
+ return _check('''
+ class A {
+ get f => 1;
+ }
+ class B extends A {
+ get f => 1;
+ }
+ main() => test();
+ test() { A x = new B(); x.f; }
+ ''',
+ constructorSend: 1, // new B()
+ localSend: 1, // x in x.f
+ instanceSend: 1); // x.f known to resolve to B.f
+ });
+
+ test('monomorphic one possible, more than one live', () {
+ return _check('''
+ class A {
+ get f => 1;
+ }
+ class B extends A {
+ get f => 1;
+ }
+ main() { new A(); test(); }
+ test() { B x = new B(); x.f; }
+ ''',
+ constructorSend: 1, // new B()
+ localSend: 1, // x in x.f
+ instanceSend: 1); // x.f resolves to B.f
+ });
+
+ test('polymorphic-virtual couple possible types from liveness', () {
+ // Note: this would be an instanceSend if we used the inferrer.
+ return _check('''
+ class A {
+ get f => 1;
+ }
+ class B extends A {
+ get f => 1;
+ }
+ main() { new A(); test(); }
+ test() { A x = new B(); x.f; }
+ ''',
+ constructorSend: 1, // new B()
+ localSend: 1, // x in x.f
+ virtualSend: 1); // x.f may be A.f or B.f (types alone is not enough)
+ });
+
+ test("polymorphic-dynamic: type annotations don't help", () {
+ return _check('''
+ class A {
+ get f => 1;
+ }
+ class B extends A {
+ get f => 1;
+ }
+ main() { new A(); test(); }
+ test() { var x = new B(); x.f; }
+ ''',
+ constructorSend: 1, // new B()
+ localSend: 1, // x in x.f
+ dynamicSend: 1); // x.f could be any `f` or no `f`
+ });
+ });
+
+ group('instance this call', () {
+ test('monomorphic only one implementor', () {
+ return _check('''
+ class A {
+ get f => 1;
+ test() => this.f;
+ }
+ main() => new A().test();
+ ''',
+ instanceSend: 1); // this.f resolved to A.f
+ });
+
+ test('monomorphic only one type possible from types & liveness', () {
+ return _check('''
+ class A {
+ get f => 1;
+ test() => this.f;
+ }
+ class B extends A {
+ get f => 1;
+ }
+ main() => new B().test();
+ ''',
+ instanceSend: 1); // this.f resolved to B.f
+ });
+
+ test('polymorphic-virtual couple possible types from liveness', () {
+ // Note: this would be an instanceSend if we used the inferrer.
+ return _check('''
+ class A {
+ get f => 1;
+ test() => this.f;
+ }
+ class B extends A {
+ get f => 1;
+ }
+ main() { new A(); new B().test(); }
+ ''',
+ virtualSend: 1); // this.f may be A.f or B.f
+ });
+ });
+
+ group('noSuchMethod', () {
+ test('error will be thrown', () {
+ return _check('''
+ class A {
+ }
+ main() { test(); }
+ test() { new A().f; }
+ ''',
+ constructorSend: 1, // new B()
+ nsmErrorSend: 1); // f not there, A has no nSM
+ });
+
+ test('nSM will be called - one option', () {
+ return _check('''
+ class A {
+ noSuchMethod(i) => null;
+ }
+ main() { test(); }
+ test() { new A().f; }
+ ''',
+ constructorSend: 1, // new B()
+ singleNsmCallSend: 1); // f not there, A has nSM
+ });
+
+ // TODO(sigmund): is it worth splitting multiNSMvirtual?
+ test('nSM will be called - multiple options', () {
+ return _check('''
+ class A {
+ noSuchMethod(i) => null;
+ }
+ class B extends A {
+ noSuchMethod(i) => null;
+ }
+ main() { new A(); test(); }
+ test() { A x = new B(); x.f; }
+ ''',
+ constructorSend: 1, // new B()
+ localSend: 1, // x in x.f
+ multiNsmCallSend: 1); // f not there, A has nSM
+ });
+
+ // TODO(sigmund): is it worth splitting multiNSMvirtual?
+ test('nSM will be called - multiple options', () {
+ return _check('''
+ class A {
+ noSuchMethod(i) => null;
+ }
+ class B extends A {
+ // don't count A's nsm as distinct
+ }
+ main() { new A(); test(); }
+ test() { A x = new B(); x.f; }
+ ''',
+ constructorSend: 1, // new B()
+ localSend: 1, // x in x.f
+ singleNsmCallSend: 1); // f not there, A has nSM
+ });
+
+ test('nSM will be called - multiple options', () {
+ return _check('''
+ class A {
+ noSuchMethod(i) => null;
+ }
+ class B extends A {
+ get f => null;
+ }
+ main() { new A(); test(); }
+ test() { A x = new B(); x.f; }
+ ''',
+ constructorSend: 1, // new B()
+ localSend: 1, // x in x.f
+ dynamicSend: 1); // f not known to be there there, A has nSM
+ });
+
+ test('nSM in super', () {
+ return _check('''
+ class A {
+ noSuchMethod(i) => null;
+ }
+ class B extends A {
+ get f => super.f;
+ }
+ main() { new A(); test(); }
+ test() { A x = new B(); x.f; }
+ ''',
+ singleNsmCallSend: 1, // super.f
+ testMethod: 'f');
+ });
+ });
+}
+
+
+/// Checks that the `test` function in [code] produces the given distribution of
+/// sends.
+_check(String code, {int staticSend: 0, int superSend: 0, int localSend: 0,
+ int constructorSend: 0, int typeVariableSend: 0, int nsmErrorSend: 0,
+ int singleNsmCallSend: 0, int instanceSend: 0, int interceptorSend: 0,
+ int multiNsmCallSend: 0, int virtualSend: 0, int multiInterceptorSend: 0,
+ int dynamicSend: 0, String testMethod: 'test'}) async {
+
+ // Set up the expectation.
+ var expected = new Measurements();
+ int monomorphic = staticSend + superSend + localSend + constructorSend +
+ typeVariableSend + nsmErrorSend + singleNsmCallSend + instanceSend +
+ interceptorSend;
+ int polymorphic = multiNsmCallSend + virtualSend + multiInterceptorSend +
+ dynamicSend;
+
+ expected.counters[Metric.monomorphicSend] = monomorphic;
+ expected.counters[Metric.staticSend] = staticSend;
+ expected.counters[Metric.superSend] = superSend;
+ expected.counters[Metric.localSend] = localSend;
+ expected.counters[Metric.constructorSend] = constructorSend;
+ expected.counters[Metric.typeVariableSend] = typeVariableSend;
+ expected.counters[Metric.nsmErrorSend] = nsmErrorSend;
+ expected.counters[Metric.singleNsmCallSend] = singleNsmCallSend;
+ expected.counters[Metric.instanceSend] = instanceSend;
+ expected.counters[Metric.interceptorSend] = interceptorSend;
+
+ expected.counters[Metric.polymorphicSend] = polymorphic;
+ expected.counters[Metric.multiNsmCallSend] = multiNsmCallSend;
+ expected.counters[Metric.virtualSend] = virtualSend;
+ expected.counters[Metric.multiInterceptorSend] = multiInterceptorSend;
+ expected.counters[Metric.dynamicSend] = dynamicSend;
+
+ expected.counters[Metric.send] = monomorphic + polymorphic;
+
+ // Run the compiler to get the results.
+ var all = await _compileAndGetStats(code);
+ var function = all.functions.firstWhere((f) => f.name == testMethod,
+ orElse: () => null);
+ var result = function?.measurements;
+ if (function == null) {
+ expect(expected.counters[Metric.send], 0);
+ return;
+ }
+
+ expect(result, isNotNull);
+
+ _compareMetric(Metric key) {
+ var expectedValue = expected.counters[key];
+ var value = result.counters[key];
+ if (value == null) value = 0;
+ if (value == expectedValue) return;
+ expect(expectedValue, value,
+ reason: "count for `$key` didn't match:\n"
+ "expected measurements:\n${recursiveDiagnosticString(expected, key)}\n"
+ "actual measurements:\n${recursiveDiagnosticString(result, key)}");
+ }
+
+ _compareMetric(Metric.send);
+ expected.counters.keys.forEach(_compareMetric);
+}
+
+/// Helper that runs the compiler and returns the [GlobalResult] computed for
+/// it.
+Future<AllInfo> _compileAndGetStats(String program) async {
+ var result = await runCompiler(
+ memorySourceFiles: {'main.dart': program}, options: ['--dump-info']);
+ expect(result.compiler.compilationFailed, isFalse);
+ return result.compiler.dumpInfoTask.infoCollector.result;
+}
diff --git a/tests/compiler/dart2js/js_spec_string_test.dart b/tests/compiler/dart2js/js_spec_string_test.dart
index a169bca..1481da4 100644
--- a/tests/compiler/dart2js/js_spec_string_test.dart
+++ b/tests/compiler/dart2js/js_spec_string_test.dart
@@ -14,7 +14,7 @@
const OBJECT = 'Object';
const NULL = 'Null';
-class Listener extends DiagnosticListener {
+class Listener extends DiagnosticReporter {
String errorMessage;
internalError(spannable, message) {
errorMessage = message;
diff --git a/tests/compiler/dart2js/least_upper_bound_test.dart b/tests/compiler/dart2js/least_upper_bound_test.dart
index d239812..9d7af4d 100644
--- a/tests/compiler/dart2js/least_upper_bound_test.dart
+++ b/tests/compiler/dart2js/least_upper_bound_test.dart
@@ -381,12 +381,12 @@
checkLub(DartType a, DartType b, DartType expectedLub) {
DartType lub = env.computeLeastUpperBound(a, b);
if (a != b) {
- expectedLub = expectedLub.unalias(env.compiler);
- lub = lub.unalias(env.compiler);
+ expectedLub = expectedLub.unalias(env.compiler.resolution);
+ lub = lub.unalias(env.compiler.resolution);
}
Expect.equals(expectedLub, lub,
- 'Unexpected lub(${a.unalias(env.compiler)},'
- '${b.unalias(env.compiler)}) = '
+ 'Unexpected lub(${a.unalias(env.compiler.resolution)},'
+ '${b.unalias(env.compiler.resolution)}) = '
'${lub}, expected ${expectedLub}');
}
diff --git a/tests/compiler/dart2js/memory_compiler.dart b/tests/compiler/dart2js/memory_compiler.dart
index c23b809..906799d 100644
--- a/tests/compiler/dart2js/memory_compiler.dart
+++ b/tests/compiler/dart2js/memory_compiler.dart
@@ -245,10 +245,10 @@
compiler.deferredLibraryClass = cachedCompiler.deferredLibraryClass;
Iterable cachedTreeElements =
- cachedCompiler.enqueuer.resolution.resolvedElements;
+ cachedCompiler.enqueuer.resolution.processedElements;
cachedTreeElements.forEach((element) {
if (element.library.isPlatformLibrary) {
- compiler.enqueuer.resolution.registerResolvedElement(element);
+ compiler.enqueuer.resolution.registerProcessedElement(element);
}
});
diff --git a/tests/compiler/dart2js/message_kind_helper.dart b/tests/compiler/dart2js/message_kind_helper.dart
index 12089cf..9d60632 100644
--- a/tests/compiler/dart2js/message_kind_helper.dart
+++ b/tests/compiler/dart2js/message_kind_helper.dart
@@ -114,7 +114,7 @@
}
}
Expect.isTrue(messageFound, '"$pattern" does not match any in $messages');
- Expect.isFalse(compiler.hasCrashed);
+ Expect.isFalse(compiler.reporter.hasCrashed);
if (!unexpectedMessages.isEmpty) {
for (String message in unexpectedMessages) {
print("Unexpected message: $message");
@@ -129,13 +129,13 @@
bool pendingStuff = false;
for (var e in compiler.resolver.pendingClassesToBePostProcessed) {
pendingStuff = true;
- compiler.reportInfo(
+ compiler.reporter.reportInfo(
e, MessageKind.GENERIC,
{'text': 'Pending class to be post-processed.'});
}
for (var e in compiler.resolver.pendingClassesToBeResolved) {
pendingStuff = true;
- compiler.reportInfo(
+ compiler.reporter.reportInfo(
e, MessageKind.GENERIC,
{'text': 'Pending class to be resolved.'});
}
diff --git a/tests/compiler/dart2js/metadata_test.dart b/tests/compiler/dart2js/metadata_test.dart
index 205c897..0f1e9fd 100644
--- a/tests/compiler/dart2js/metadata_test.dart
+++ b/tests/compiler/dart2js/metadata_test.dart
@@ -9,9 +9,14 @@
import 'compiler_helper.dart';
import 'package:compiler/src/parser/partial_elements.dart' show
PartialMetadataAnnotation;
+import 'package:compiler/src/diagnostics/diagnostic_listener.dart' show
+ DiagnosticReporter;
-void checkPosition(Spannable spannable, Node node, String source, compiler) {
- SourceSpan span = compiler.spanFromSpannable(spannable);
+void checkPosition(Spannable spannable,
+ Node node,
+ String source,
+ DiagnosticReporter reporter) {
+ SourceSpan span = reporter.spanFromSpannable(spannable);
Expect.isTrue(span.begin < span.end,
'begin = ${span.begin}; end = ${span.end}');
Expect.isTrue(span.end < source.length,
@@ -36,12 +41,13 @@
Expect.equals(1, element.metadata.length,
'Unexpected metadata count on $element.');
PartialMetadataAnnotation annotation = element.metadata.first;
- annotation.ensureResolved(compiler);
+ annotation.ensureResolved(compiler.resolution);
PrimitiveConstantValue value =
compiler.constants.getConstantValue(annotation.constant);
Expect.stringEquals('xyz', value.primitiveValue.slowToString());
- checkPosition(annotation, annotation.cachedNode, source1, compiler);
+ checkPosition(
+ annotation, annotation.cachedNode, source1, compiler.reporter);
});
// Ensure that each repeated annotation has a unique instance of
@@ -56,8 +62,8 @@
Expect.equals(2, element.metadata.length);
PartialMetadataAnnotation annotation1 = element.metadata.elementAt(0);
PartialMetadataAnnotation annotation2 = element.metadata.elementAt(1);
- annotation1.ensureResolved(compiler);
- annotation2.ensureResolved(compiler);
+ annotation1.ensureResolved(compiler.resolution);
+ annotation2.ensureResolved(compiler.resolution);
Expect.isFalse(identical(annotation1, annotation2),
'expected unique instances');
Expect.notEquals(annotation1, annotation2, 'expected unequal instances');
@@ -69,8 +75,10 @@
Expect.stringEquals('xyz', value1.primitiveValue.slowToString());
Expect.stringEquals('xyz', value2.primitiveValue.slowToString());
- checkPosition(annotation1, annotation1.cachedNode, source2, compiler);
- checkPosition(annotation2, annotation2.cachedNode, source2, compiler);
+ checkPosition(
+ annotation1, annotation1.cachedNode, source2, compiler.reporter);
+ checkPosition(
+ annotation2, annotation2.cachedNode, source2, compiler.reporter);
});
if (isTopLevelOnly) return;
@@ -87,17 +95,18 @@
compileAndCheck(source3, 'Foo', (compiler, element) {
compiler.enqueuer.resolution.queueIsClosed = false;
Expect.equals(0, element.metadata.length);
- element.ensureResolved(compiler);
+ element.ensureResolved(compiler.resolution);
Expect.equals(0, element.metadata.length);
element = element.lookupLocalMember(name);
Expect.equals(1, element.metadata.length);
PartialMetadataAnnotation annotation = element.metadata.first;
- annotation.ensureResolved(compiler);
+ annotation.ensureResolved(compiler.resolution);
PrimitiveConstantValue value =
compiler.constants.getConstantValue(annotation.constant);
Expect.stringEquals('xyz', value.primitiveValue.slowToString());
- checkPosition(annotation, annotation.cachedNode, source3, compiler);
+ checkPosition(
+ annotation, annotation.cachedNode, source3, compiler.reporter);
});
// Ensure that each repeated annotation has a unique instance of
@@ -112,14 +121,14 @@
compileAndCheck(source4, 'Foo', (compiler, element) {
compiler.enqueuer.resolution.queueIsClosed = false;
Expect.equals(0, element.metadata.length);
- element.ensureResolved(compiler);
+ element.ensureResolved(compiler.resolution);
Expect.equals(0, element.metadata.length);
element = element.lookupLocalMember(name);
Expect.equals(2, element.metadata.length);
PartialMetadataAnnotation annotation1 = element.metadata.elementAt(0);
PartialMetadataAnnotation annotation2 = element.metadata.elementAt(1);
- annotation1.ensureResolved(compiler);
- annotation2.ensureResolved(compiler);
+ annotation1.ensureResolved(compiler.resolution);
+ annotation2.ensureResolved(compiler.resolution);
Expect.isFalse(identical(annotation1, annotation2),
'expected unique instances');
Expect.notEquals(annotation1, annotation2, 'expected unequal instances');
@@ -131,8 +140,10 @@
Expect.stringEquals('xyz', value1.primitiveValue.slowToString());
Expect.stringEquals('xyz', value2.primitiveValue.slowToString());
- checkPosition(annotation1, annotation1.cachedNode, source4, compiler);
- checkPosition(annotation1, annotation2.cachedNode, source4, compiler);
+ checkPosition(
+ annotation1, annotation1.cachedNode, source4, compiler.reporter);
+ checkPosition(
+ annotation1, annotation2.cachedNode, source4, compiler.reporter);
});
}
@@ -174,12 +185,13 @@
Expect.equals(1, metadata.length);
PartialMetadataAnnotation annotation = metadata.first;
- annotation.ensureResolved(compiler);
+ annotation.ensureResolved(compiler.resolution);
PrimitiveConstantValue value =
compiler.constants.getConstantValue(annotation.constant);
Expect.stringEquals('xyz', value.primitiveValue.slowToString());
- checkPosition(annotation, annotation.cachedNode, source, compiler);
+ checkPosition(
+ annotation, annotation.cachedNode, source, compiler.reporter);
}));
}
diff --git a/tests/compiler/dart2js/minimal_resolution_test.dart b/tests/compiler/dart2js/minimal_resolution_test.dart
index ca61f80..b46b340 100644
--- a/tests/compiler/dart2js/minimal_resolution_test.dart
+++ b/tests/compiler/dart2js/minimal_resolution_test.dart
@@ -6,6 +6,9 @@
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/compiler.dart';
+import 'package:compiler/src/elements/elements.dart';
+import 'package:compiler/src/enqueue.dart';
+import 'package:compiler/src/js_backend/js_backend.dart';
import 'package:expect/expect.dart';
import 'memory_compiler.dart';
@@ -13,15 +16,45 @@
asyncTest(() async {
await analyze('main() {}');
await analyze('main() => proxy;', proxyConstant: true);
+ await analyze('@deprecated main() {}');
+ await analyze('@deprecated main() => deprecated;', deprecatedClass: true);
+ await analyze('main() => deprecated;', deprecatedClass: true);
});
}
+void checkInstantiated(Compiler compiler, ClassElement cls, bool expected) {
+ ResolutionEnqueuer enqueuer = compiler.enqueuer.resolution;
+ bool isInstantiated =
+ enqueuer.universe.directlyInstantiatedClasses.contains(cls);
+ bool isProcessed = enqueuer.isClassProcessed(cls);
+ Expect.equals(expected, isInstantiated,
+ 'Unexpected instantiation state of class $cls.');
+ Expect.equals(expected, isProcessed,
+ 'Unexpected processing state of class $cls.');
+}
+
analyze(String code,
- {bool proxyConstant: false}) async {
+ {bool proxyConstant: false,
+ bool deprecatedClass: false}) async {
CompilationResult result = await runCompiler(
memorySourceFiles: {'main.dart': code},
options: ['--analyze-only']);
Expect.isTrue(result.isSuccess);
Compiler compiler = result.compiler;
- Expect.equals(proxyConstant, compiler.proxyConstant != null);
+ Expect.equals(proxyConstant, compiler.proxyConstant != null,
+ "Unexpected computation of proxy constant.");
+
+ checkInstantiated(
+ compiler, compiler.coreLibrary.find('_Proxy'), proxyConstant);
+ checkInstantiated(
+ compiler, compiler.coreLibrary.find('Deprecated'), deprecatedClass);
+
+ LibraryElement jsHelperLibrary =
+ compiler.libraryLoader.lookupLibrary(JavaScriptBackend.DART_JS_HELPER);
+ jsHelperLibrary.forEachLocalMember((Element element) {
+ Uri uri = element.compilationUnit.script.resourceUri;
+ if (element.isClass && uri.path.endsWith('annotations.dart')) {
+ checkInstantiated(compiler, element, false);
+ }
+ });
}
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index 9f67d12..5c33011 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -12,6 +12,7 @@
import 'package:compiler/src/common/names.dart' show
Uris;
import 'package:compiler/src/constants/expressions.dart';
+import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
import 'package:compiler/src/diagnostics/messages.dart';
import 'package:compiler/src/diagnostics/source_span.dart';
import 'package:compiler/src/diagnostics/spannable.dart';
@@ -76,7 +77,6 @@
bool enableTypeAssertions: false,
bool enableUserAssertions: false,
bool enableMinification: false,
- bool enableConcreteTypeInference: false,
int maxConcreteTypeSize: 5,
bool disableTypeInference: false,
bool analyzeAll: false,
@@ -99,7 +99,6 @@
enableUserAssertions: enableUserAssertions,
enableAssertMessage: true,
enableMinification: enableMinification,
- enableConcreteTypeInference: enableConcreteTypeInference,
maxConcreteTypeSize: maxConcreteTypeSize,
disableTypeInferenceFlag: disableTypeInference,
analyzeAllFlag: analyzeAll,
@@ -107,7 +106,8 @@
emitJavaScript: emitJavaScript,
preserveComments: preserveComments,
trustTypeAnnotations: trustTypeAnnotations,
- showPackageWarnings: true,
+ diagnosticOptions:
+ new DiagnosticOptions(showPackageWarnings: true),
outputProvider: new LegacyCompilerOutput(outputProvider)) {
this.disableInlining = disableInlining;
@@ -157,7 +157,7 @@
// dynamic invocation the ArgumentTypesRegistry eventually iterates over
// the interfaces of the Object class which would be 'null' if the class
// wasn't resolved.
- objectClass.ensureResolved(this);
+ objectClass.ensureResolved(resolution);
}).then((_) => uri);
}
diff --git a/tests/compiler/dart2js/mock_libraries.dart b/tests/compiler/dart2js/mock_libraries.dart
index 957cb56..95bb3fb 100644
--- a/tests/compiler/dart2js/mock_libraries.dart
+++ b/tests/compiler/dart2js/mock_libraries.dart
@@ -347,11 +347,11 @@
operator &(other) => 42;
operator ^(other) => 42;
- operator >(other) => true;
- operator >=(other) => true;
- operator <(other) => true;
- operator <=(other) => true;
- operator ==(other) => true;
+ operator >(other) => !identical(this, other);
+ operator >=(other) => !identical(this, other);
+ operator <(other) => !identical(this, other);
+ operator <=(other) => !identical(this, other);
+ operator ==(other) => identical(this, other);
get hashCode => throw "JSNumber.hashCode not implemented.";
// We force side effects on _tdivFast to mimic the shortcomings of
diff --git a/tests/compiler/dart2js/override_inheritance_test.dart b/tests/compiler/dart2js/override_inheritance_test.dart
index 0e24785..c71e6b2 100644
--- a/tests/compiler/dart2js/override_inheritance_test.dart
+++ b/tests/compiler/dart2js/override_inheritance_test.dart
@@ -29,7 +29,7 @@
compiler.diagnosticHandler = createHandler(compiler, source);
compiler.parseScript(source);
var cls = compiler.mainApp.find('Class');
- cls.ensureResolved(compiler);
+ cls.ensureResolved(compiler.resolution);
MembersCreator.computeAllClassMembers(compiler, cls);
toList(o) => o == null ? [] : o is List ? o : [o];
diff --git a/tests/compiler/dart2js/parser_helper.dart b/tests/compiler/dart2js/parser_helper.dart
index ea49b68..572a082 100644
--- a/tests/compiler/dart2js/parser_helper.dart
+++ b/tests/compiler/dart2js/parser_helper.dart
@@ -37,7 +37,7 @@
export "package:compiler/src/tokens/token.dart";
export "package:compiler/src/tokens/token_constants.dart";
-class LoggerCanceler extends DiagnosticListener {
+class LoggerCanceler extends DiagnosticReporter {
void log(message) {
print(message);
}
@@ -93,15 +93,15 @@
.tokenize();
Node parseBodyCode(String text, Function parseMethod,
- {DiagnosticListener diagnosticHandler}) {
+ {DiagnosticReporter reporter}) {
Token tokens = scan(text);
- if (diagnosticHandler == null) diagnosticHandler = new LoggerCanceler();
+ if (reporter == null) reporter = new LoggerCanceler();
Uri uri = new Uri(scheme: "source");
Script script = new Script(uri, uri,new MockFile(text));
LibraryElement library = new LibraryElementX(script);
library.canUseNative = true;
NodeListener listener =
- new NodeListener(diagnosticHandler, library.entryCompilationUnit);
+ new NodeListener(reporter, library.entryCompilationUnit);
Parser parser = new Parser(listener);
Token endToken = parseMethod(parser, tokens);
assert(endToken.kind == EOF_TOKEN);
@@ -118,12 +118,14 @@
ElementX element = parseUnit(text, compiler, compiler.mainApp).head;
Expect.isNotNull(element);
Expect.equals(ElementKind.FUNCTION, element.kind);
- return element.parseNode(compiler);
+ return element.parseNode(compiler.parsing);
}
-Node parseMember(String text, {DiagnosticListener diagnosticHandler}) {
- return parseBodyCode(text, (parser, tokens) => parser.parseMember(tokens),
- diagnosticHandler: diagnosticHandler);
+Node parseMember(String text, {DiagnosticReporter reporter}) {
+ return parseBodyCode(
+ text,
+ (parser, tokens) => parser.parseMember(tokens),
+ reporter: reporter);
}
class MockFile extends StringSourceFile {
@@ -144,13 +146,16 @@
var script = new Script(uri, uri, new MockFile(text));
var unit = new CompilationUnitElementX(script, library);
int id = 0;
- ElementListener listener = new ElementListener(compiler, unit, () => id++);
+ DiagnosticReporter reporter = compiler.reporter;
+ ElementListener listener = new ElementListener(reporter, unit, () => id++);
PartialParser parser = new PartialParser(listener);
- compiler.withCurrentElement(unit, () => parser.parseUnit(tokens));
+ reporter.withCurrentElement(unit, () => parser.parseUnit(tokens));
return unit.localMembers;
}
-NodeList fullParseUnit(String source, {DiagnosticListener diagnosticHandler}) {
- return parseBodyCode(source, (parser, tokens) => parser.parseUnit(tokens),
- diagnosticHandler: diagnosticHandler);
+NodeList fullParseUnit(String source, {DiagnosticReporter reporter}) {
+ return parseBodyCode(
+ source,
+ (parser, tokens) => parser.parseUnit(tokens),
+ reporter: reporter);
}
diff --git a/tests/compiler/dart2js/parser_test.dart b/tests/compiler/dart2js/parser_test.dart
index 17584fb..4674201 100644
--- a/tests/compiler/dart2js/parser_test.dart
+++ b/tests/compiler/dart2js/parser_test.dart
@@ -292,7 +292,7 @@
Expect.isNull(function.getOrSet);
}
-class Collector extends DiagnosticListener {
+class Collector extends DiagnosticReporter {
int token = -1;
void reportFatalError(Token token) {
@@ -326,7 +326,7 @@
return x;
}''';
parse() {
- parseMember(source, diagnosticHandler: new Collector());
+ parseMember(source, reporter: new Collector());
}
check(Collector c) {
Expect.equals(OPEN_CURLY_BRACKET_TOKEN, c.token);
@@ -338,7 +338,7 @@
void testMissingCloseBraceInClass() {
final String source = 'class Foo {'; // Missing close '}'.
parse() {
- fullParseUnit(source, diagnosticHandler: new Collector());
+ fullParseUnit(source, reporter: new Collector());
}
check(Collector c) {
Expect.equals(BAD_INPUT_TOKEN, c.token);
@@ -350,7 +350,7 @@
void testUnmatchedAngleBracket() {
final String source = 'A<'; // unmatched '<'
parse() {
- fullParseUnit(source, diagnosticHandler: new Collector());
+ fullParseUnit(source, reporter: new Collector());
}
check(Collector c) {
Expect.equals(LT_TOKEN, c.token);
diff --git a/tests/compiler/dart2js/patch_test.dart b/tests/compiler/dart2js/patch_test.dart
index 10c8bca..1422a1a 100644
--- a/tests/compiler/dart2js/patch_test.dart
+++ b/tests/compiler/dart2js/patch_test.dart
@@ -45,7 +45,7 @@
}
void expectHasBody(compiler, ElementX element) {
- var node = element.parseNode(compiler);
+ var node = element.parseNode(compiler.parsing);
Expect.isNotNull(node, "Element isn't parseable, when a body was expected");
Expect.isNotNull(node.body);
// If the element has a body it is either a Block or a Return statement,
@@ -55,7 +55,7 @@
}
void expectHasNoBody(compiler, ElementX element) {
- var node = element.parseNode(compiler);
+ var node = element.parseNode(compiler.parsing);
Expect.isNotNull(node, "Element isn't parseable, when a body was expected");
Expect.isFalse(node.hasBody());
}
@@ -248,7 +248,7 @@
""");
var classOrigin = ensure(compiler, "Class", compiler.coreLibrary.find,
expectIsPatched: true);
- classOrigin.ensureResolved(compiler);
+ classOrigin.ensureResolved(compiler.resolution);
var classPatch = ensure(compiler, "Class", compiler.coreLibrary.patch.find,
expectIsPatch: true);
@@ -287,7 +287,7 @@
""");
var classOrigin = ensure(compiler, "Class", compiler.coreLibrary.find,
expectIsPatched: true);
- classOrigin.ensureResolved(compiler);
+ classOrigin.ensureResolved(compiler.resolution);
var classPatch = ensure(compiler, "Class", compiler.coreLibrary.patch.find,
expectIsPatch: true);
@@ -331,7 +331,7 @@
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
expectIsPatched: true);
- container.parseNode(compiler);
+ container.parseNode(compiler.parsing);
ensure(compiler, "Class", compiler.coreLibrary.patch.find,
expectIsPatch: true);
@@ -360,7 +360,7 @@
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
expectIsPatched: true);
- container.parseNode(compiler);
+ container.parseNode(compiler.parsing);
ensure(compiler,
"field",
container.lookupLocalMember,
@@ -393,7 +393,7 @@
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
expectIsPatched: true);
- container.parseNode(compiler);
+ container.parseNode(compiler.parsing);
ensure(compiler, "Class", compiler.coreLibrary.patch.find,
expectIsPatch: true);
@@ -421,7 +421,7 @@
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
expectIsPatched: true);
- container.parseNode(compiler);
+ container.parseNode(compiler.parsing);
ensure(compiler, "Class", compiler.coreLibrary.patch.find,
expectIsPatch: true);
@@ -489,8 +489,8 @@
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
expectIsPatched: true);
- container.ensureResolved(compiler);
- container.parseNode(compiler);
+ container.ensureResolved(compiler.resolution);
+ container.parseNode(compiler.parsing);
void expect(String methodName, List infos, List errors) {
compiler.clearMessages();
@@ -568,7 +568,7 @@
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
expectIsPatched: true);
- container.parseNode(compiler);
+ container.parseNode(compiler.parsing);
compiler.warnings.clear();
compiler.errors.clear();
@@ -629,7 +629,7 @@
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
expectIsPatched: true);
- container.parseNode(compiler);
+ container.parseNode(compiler.parsing);
Expect.isTrue(compiler.warnings.isEmpty,
"Unexpected warnings: ${compiler.warnings}");
@@ -712,7 +712,7 @@
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
expectIsPatched: true);
- container.parseNode(compiler);
+ container.parseNode(compiler.parsing);
print('testPatchNonExternalMember.errors:${compiler.errors}');
print('testPatchNonExternalMember.warnings:${compiler.warnings}');
@@ -866,7 +866,7 @@
ClassElement cls = ensure(compiler, "A", compiler.coreLibrary.find,
expectIsPatched: true);
- cls.ensureResolved(compiler);
+ cls.ensureResolved(compiler.resolution);
ensure(compiler, "method", cls.patch.lookupLocalMember,
checkHasBody: true, expectIsRegular: true);
@@ -882,7 +882,7 @@
new Selector.call(const PublicName('method'), CallStructure.NO_ARGS);
TypeMask typeMask = new TypeMask.exact(cls, world);
FunctionElement method = cls.implementation.lookupLocalMember('method');
- method.computeType(compiler);
+ method.computeType(compiler.resolution);
Expect.isTrue(selector.applies(method, world));
Expect.isTrue(typeMask.canHit(method, selector, world));
@@ -892,14 +892,14 @@
new Selector.call(const PublicName('clear'), CallStructure.NO_ARGS);
typeMask = new TypeMask.exact(cls, world);
method = cls.lookupLocalMember('clear');
- method.computeType(compiler);
+ method.computeType(compiler.resolution);
Expect.isTrue(selector.applies(method, world));
Expect.isTrue(typeMask.canHit(method, selector, world));
// Check that the declaration method in the declaration class is a target
// for a typed selector on a subclass.
cls = ensure(compiler, "B", compiler.coreLibrary.find);
- cls.ensureResolved(compiler);
+ cls.ensureResolved(compiler.resolution);
typeMask = new TypeMask.exact(cls, world);
Expect.isTrue(selector.applies(method, world));
Expect.isTrue(typeMask.canHit(method, selector, world));
diff --git a/tests/compiler/dart2js/related_types.dart b/tests/compiler/dart2js/related_types.dart
index 54d9ab8..6e3f8b2 100644
--- a/tests/compiler/dart2js/related_types.dart
+++ b/tests/compiler/dart2js/related_types.dart
@@ -8,6 +8,7 @@
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/core_types.dart';
import 'package:compiler/src/dart_types.dart';
+import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
import 'package:compiler/src/diagnostics/messages.dart';
import 'package:compiler/src/elements/elements.dart';
import 'package:compiler/src/filenames.dart';
@@ -55,13 +56,13 @@
/// Check [member] for unrelated types.
void checkMemberElement(Compiler compiler, MemberElement member) {
- if (!compiler.enqueuer.resolution.hasBeenResolved(member)) return;
+ if (!compiler.resolution.hasBeenResolved(member)) return;
ResolvedAst resolvedAst = member.resolvedAst;
RelatedTypesChecker relatedTypesChecker =
new RelatedTypesChecker(compiler, resolvedAst);
if (resolvedAst.node != null) {
- compiler.withCurrentElement(member.implementation, () {
+ compiler.reporter.withCurrentElement(member.implementation, () {
relatedTypesChecker.apply(resolvedAst.node);
});
}
@@ -79,6 +80,8 @@
CoreTypes get coreTypes => compiler.coreTypes;
+ DiagnosticReporter get reporter => compiler.reporter;
+
InterfaceType get thisType => resolvedAst.element.enclosingClass.thisType;
/// Returns `true` if there exists no common subtype of [left] and [right].
@@ -97,10 +100,10 @@
/// a hint otherwise.
void checkRelated(Node node, DartType left, DartType right) {
if (hasEmptyIntersection(left, right)) {
- compiler.reportHint(compiler.createMessage(
+ reporter.reportHintMessage(
node,
MessageKind.NO_COMMON_SUBTYPES,
- {'left': left, 'right': right}));
+ {'left': left, 'right': right});
}
}
diff --git a/tests/compiler/dart2js/resolver_test.dart b/tests/compiler/dart2js/resolver_test.dart
index 3f18c93..236b0bd 100644
--- a/tests/compiler/dart2js/resolver_test.dart
+++ b/tests/compiler/dart2js/resolver_test.dart
@@ -193,9 +193,9 @@
' bar() { g(Foo<T> f) {}; g(); }'
'}');
ClassElement foo = compiler.mainApp.find('Foo');
- foo.ensureResolved(compiler);
- foo.lookupLocalMember('t').computeType(compiler);;
- foo.lookupLocalMember('foo').computeType(compiler);;
+ foo.ensureResolved(compiler.resolution);
+ foo.lookupLocalMember('t').computeType(compiler.resolution);
+ foo.lookupLocalMember('foo').computeType(compiler.resolution);
compiler.resolver.resolve(foo.lookupLocalMember('bar'));
Expect.equals(0, compiler.warnings.length);
Expect.equals(0, compiler.errors.length);
@@ -219,7 +219,8 @@
new ResolverVisitor(compiler, fooB,
new ResolutionRegistry(compiler,
new CollectingTreeElements(fooB)));
- FunctionExpression node = (fooB as FunctionElementX).parseNode(compiler);
+ FunctionExpression node =
+ (fooB as FunctionElementX).parseNode(compiler.parsing);
visitor.visit(node.body);
Map mapping = map(visitor);
@@ -262,7 +263,7 @@
new ResolutionRegistry(compiler,
new CollectingTreeElements(funElement)));
FunctionExpression function =
- (funElement as FunctionElementX).parseNode(compiler);
+ (funElement as FunctionElementX).parseNode(compiler.parsing);
visitor.visit(function.body);
Map mapping = map(visitor);
List<Element> values = mapping.values.toList();
@@ -285,7 +286,7 @@
new ResolutionRegistry(compiler,
new CollectingTreeElements(funElement)));
FunctionExpression function =
- (funElement as FunctionElementX).parseNode(compiler);
+ (funElement as FunctionElementX).parseNode(compiler.parsing);
visitor.visit(function.body);
Expect.equals(0, compiler.warnings.length);
Expect.equals(1, compiler.errors.length);
@@ -530,7 +531,7 @@
ClassElement fooElement = compiler.mainApp.find('Foo');
ClassElement barElement = compiler.mainApp.find('Bar');
- Expect.equals(barElement.computeType(compiler),
+ Expect.equals(barElement.computeType(compiler.resolution),
fooElement.supertype);
Expect.isTrue(fooElement.interfaces.isEmpty);
Expect.isTrue(barElement.interfaces.isEmpty);
@@ -580,7 +581,7 @@
Expect.equals(null, barElement.supertype);
Expect.isTrue(barElement.interfaces.isEmpty);
- Expect.equals(barElement.computeType(compiler),
+ Expect.equals(barElement.computeType(compiler.resolution),
fooElement.interfaces.head);
Expect.equals(1, length(fooElement.interfaces));
});
@@ -599,8 +600,8 @@
ClassElement i2 = compiler.mainApp.find('I2');
Expect.equals(2, length(c.interfaces));
- Expect.equals(i1.computeType(compiler), at(c.interfaces, 0));
- Expect.equals(i2.computeType(compiler), at(c.interfaces, 1));
+ Expect.equals(i1.computeType(compiler.resolution), at(c.interfaces, 0));
+ Expect.equals(i2.computeType(compiler.resolution), at(c.interfaces, 1));
});
}
@@ -651,7 +652,8 @@
compiler.parseScript("int a;");
VariableElementX element = compiler.mainApp.find("a");
Expect.equals(ElementKind.FIELD, element.kind);
- VariableDefinitions node = element.variables.parseNode(element, compiler);
+ VariableDefinitions node =
+ element.variables.parseNode(element, compiler.parsing);
Identifier typeName = node.type.typeName;
Expect.equals(typeName.source, 'int');
@@ -662,8 +664,10 @@
Expect.equals(ElementKind.FIELD, cElement.kind);
Expect.isTrue(bElement != cElement);
- VariableDefinitions bNode = bElement.variables.parseNode(bElement, compiler);
- VariableDefinitions cNode = cElement.variables.parseNode(cElement, compiler);
+ VariableDefinitions bNode =
+ bElement.variables.parseNode(bElement, compiler.parsing);
+ VariableDefinitions cNode =
+ cElement.variables.parseNode(cElement, compiler.parsing);
Expect.equals(bNode, cNode);
Expect.isNull(bNode.type);
Expect.isTrue(bNode.modifiers.isVar);
@@ -1079,7 +1083,7 @@
Element memberElement = cls.lookupLocalMember(memberName);
Expect.isNotNull(memberElement);
Expect.isTrue(
- compiler.enqueuer.resolution.hasBeenResolved(memberElement));
+ compiler.enqueuer.resolution.hasBeenProcessed(memberElement));
}
testToString() {
diff --git a/tests/compiler/dart2js/semantic_visitor_test.dart b/tests/compiler/dart2js/semantic_visitor_test.dart
index 3376a67..f8ea57f 100644
--- a/tests/compiler/dart2js/semantic_visitor_test.dart
+++ b/tests/compiler/dart2js/semantic_visitor_test.dart
@@ -330,7 +330,7 @@
ResolvedAst resolvedAst = astElement.resolvedAst;
SemanticTestVisitor visitor = createVisitor(resolvedAst.elements);
try {
- compiler.withCurrentElement(resolvedAst.element, () {
+ compiler.reporter.withCurrentElement(resolvedAst.element, () {
//print(resolvedAst.node.toDebugString());
resolvedAst.node.accept(visitor);
});
diff --git a/tests/compiler/dart2js/source_mapping_test.dart b/tests/compiler/dart2js/source_mapping_test.dart
index 40c0f69..6c7b46f 100644
--- a/tests/compiler/dart2js/source_mapping_test.dart
+++ b/tests/compiler/dart2js/source_mapping_test.dart
@@ -68,7 +68,7 @@
String RETURN_TEST = 'void main() { print(((x) { @return x; })(0)); }';
-String NOT_TEST = 'void main() { ((x) { if (@!x) print(x); })(false); }';
+String NOT_TEST = 'void main() { ((x) { if (@!x) print(x); })(1==2); }';
String UNARY_TEST = 'void main() { ((x, y) { print(@-x + @~y); })(1,2); }';
diff --git a/tests/compiler/dart2js/type_checker_test.dart b/tests/compiler/dart2js/type_checker_test.dart
index fc7b601..045d2be 100644
--- a/tests/compiler/dart2js/type_checker_test.dart
+++ b/tests/compiler/dart2js/type_checker_test.dart
@@ -75,10 +75,11 @@
Expect.equals(type, analyzeType(compiler, code));
}
- checkType(compiler.intClass.computeType(compiler), "3");
- checkType(compiler.boolClass.computeType(compiler), "false");
- checkType(compiler.boolClass.computeType(compiler), "true");
- checkType(compiler.stringClass.computeType(compiler), "'hestfisk'");
+ checkType(compiler.intClass.computeType(compiler.resolution), "3");
+ checkType(compiler.boolClass.computeType(compiler.resolution), "false");
+ checkType(compiler.boolClass.computeType(compiler.resolution), "true");
+ checkType(
+ compiler.stringClass.computeType(compiler.resolution), "'hestfisk'");
}
Future testReturn(MockCompiler compiler) {
@@ -175,7 +176,7 @@
""";
compiler.parseScript(script);
ClassElement foo = compiler.mainApp.find("Class");
- foo.ensureResolved(compiler);
+ foo.ensureResolved(compiler.resolution);
FunctionElement method = foo.lookupLocalMember('forIn');
analyzeIn(compiler, method, """{
@@ -308,7 +309,7 @@
""";
compiler.parseScript(script);
ClassElement foo = compiler.mainApp.find("Class");
- foo.ensureResolved(compiler);
+ foo.ensureResolved(compiler.resolution);
FunctionElement method = foo.lookupLocalMember('forIn');
analyzeIn(compiler, method, """{
@@ -894,11 +895,11 @@
LibraryElement library = compiler.mainApp;
compiler.parseScript(CLASS_WITH_METHODS, library);
ClassElement ClassWithMethods = library.find("ClassWithMethods");
- ClassWithMethods.ensureResolved(compiler);
+ ClassWithMethods.ensureResolved(compiler.resolution);
Element c = ClassWithMethods.lookupLocalMember('method');
assert(c != null);
ClassElement SubClass = library.find("SubClass");
- SubClass.ensureResolved(compiler);
+ SubClass.ensureResolved(compiler.resolution);
Element d = SubClass.lookupLocalMember('method');
assert(d != null);
@@ -1190,7 +1191,7 @@
}""";
compiler.parseScript(script);
ClassElement foo = compiler.mainApp.find("Foo");
- foo.ensureResolved(compiler);
+ foo.ensureResolved(compiler.resolution);
Element method = foo.lookupLocalMember('method');
analyzeIn(compiler, method, "{ int i = this; }", warnings: NOT_ASSIGNABLE);
analyzeIn(compiler, method, "{ Object o = this; }");
@@ -1210,7 +1211,7 @@
''';
compiler.parseScript(script);
ClassElement B = compiler.mainApp.find("B");
- B.ensureResolved(compiler);
+ B.ensureResolved(compiler.resolution);
Element method = B.lookupLocalMember('method');
analyzeIn(compiler, method, "{ int i = super.field; }",
warnings: NOT_ASSIGNABLE);
@@ -1517,7 +1518,7 @@
}""";
compiler.parseScript(script);
ClassElement foo = compiler.mainApp.find("Foo");
- foo.ensureResolved(compiler);
+ foo.ensureResolved(compiler.resolution);
Element method = foo.lookupLocalMember('method');
analyzeIn(compiler, method, "{ Type type = T; }");
@@ -1552,7 +1553,7 @@
compiler.parseScript(script);
ClassElement classTest = compiler.mainApp.find("Test");
- classTest.ensureResolved(compiler);
+ classTest.ensureResolved(compiler.resolution);
FunctionElement methodTest = classTest.lookupLocalMember("test");
test(String expression, [message]) {
@@ -1592,7 +1593,7 @@
compiler.parseScript(script);
ClassElement classTest = compiler.mainApp.find("Test");
- classTest.ensureResolved(compiler);
+ classTest.ensureResolved(compiler.resolution);
FunctionElement methodTest = classTest.lookupLocalMember("test");
test(String expression, [message]) {
@@ -1614,7 +1615,7 @@
compiler.parseScript(script);
ClassElement classTest = compiler.mainApp.find("Test");
- classTest.ensureResolved(compiler);
+ classTest.ensureResolved(compiler.resolution);
FunctionElement methodTest = classTest.lookupLocalMember("test");
test(String expression, [message]) {
@@ -2325,7 +2326,7 @@
}""";
compiler.parseScript(script);
ClassElement foo = compiler.mainApp.find("Foo");
- foo.ensureResolved(compiler);
+ foo.ensureResolved(compiler.resolution);
FunctionElement method = foo.lookupLocalMember('method');
analyzeIn(compiler, method, "{ await 0; }");
analyzeIn(compiler, method, "{ int i = await 0; }");
@@ -2505,17 +2506,17 @@
element = elements.head;
if (element.isClass) {
ClassElementX classElement = element;
- classElement.ensureResolved(compiler);
+ classElement.ensureResolved(compiler.resolution);
classElement.forEachLocalMember((Element e) {
if (!e.isSynthesized) {
element = e;
- node = element.parseNode(compiler);
+ node = element.parseNode(compiler.parsing);
compiler.resolver.resolve(element);
mapping = element.treeElements;
}
});
} else {
- node = element.parseNode(compiler);
+ node = element.parseNode(compiler.parsing);
compiler.resolver.resolve(element);
mapping = element.treeElements;
}
@@ -2549,7 +2550,7 @@
compiler.diagnosticHandler = createHandler(compiler, text);
Token tokens = scan(text);
- NodeListener listener = new NodeListener(compiler, null);
+ NodeListener listener = new NodeListener(compiler.reporter, null);
Parser parser = new Parser(listener);
parser.parseStatement(tokens);
Node node = listener.popNode();
@@ -2596,7 +2597,7 @@
compiler.resolver.resolve(element);
Token tokens = scan(text);
- NodeListener listener = new NodeListener(compiler, null);
+ NodeListener listener = new NodeListener(compiler.reporter, null);
Parser parser = new Parser(listener,
yieldIsKeyword: element.asyncMarker.isYielding,
awaitIsKeyword: element.asyncMarker.isAsync);
diff --git a/tests/compiler/dart2js/type_combination_test.dart b/tests/compiler/dart2js/type_combination_test.dart
index 2dc9f61..c75ad56 100644
--- a/tests/compiler/dart2js/type_combination_test.dart
+++ b/tests/compiler/dart2js/type_combination_test.dart
@@ -734,7 +734,7 @@
World world = compiler.world;
backend.interceptorsLibrary.forEachLocalMember((element) {
if (element.isClass) {
- element.ensureResolved(compiler);
+ element.ensureResolved(compiler.resolution);
backend.registerInstantiatedType(
element.rawType,
compiler.enqueuer.resolution,
diff --git a/tests/compiler/dart2js/type_equals_test.dart b/tests/compiler/dart2js/type_equals_test.dart
index 3b71f5f..0911d60 100644
--- a/tests/compiler/dart2js/type_equals_test.dart
+++ b/tests/compiler/dart2js/type_equals_test.dart
@@ -10,15 +10,17 @@
bool test(compiler, String name1, String name2, {bool expect}) {
Expect.isTrue((expect != null), 'required parameter "expect" not given');
var clazz = findElement(compiler, "Class");
- clazz.ensureResolved(compiler);
+ clazz.ensureResolved(compiler.resolution);
var element1 = clazz.buildScope().lookup(name1);
var element2 = clazz.buildScope().lookup(name2);
Expect.isNotNull(element1);
Expect.isNotNull(element2);
Expect.equals(element1.kind, ElementKind.FUNCTION);
Expect.equals(element2.kind, ElementKind.FUNCTION);
- FunctionSignature signature1 = element1.computeSignature(compiler);
- FunctionSignature signature2 = element2.computeSignature(compiler);
+ element1.computeType(compiler.resolution);
+ element2.computeType(compiler.resolution);
+ FunctionSignature signature1 = element1.functionSignature;
+ FunctionSignature signature2 = element2.functionSignature;
// Function signatures are used to be to provide void types (only occuring as
// as return types) and (inlined) function types (only occuring as method
diff --git a/tests/compiler/dart2js/type_inference8_test.dart b/tests/compiler/dart2js/type_inference8_test.dart
index fc2d578..570e43a 100644
--- a/tests/compiler/dart2js/type_inference8_test.dart
+++ b/tests/compiler/dart2js/type_inference8_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import "package:async_helper/async_helper.dart";
+import "package:compiler/src/constants/values.dart";
import "package:compiler/src/types/types.dart";
import "package:expect/expect.dart";
import 'compiler_helper.dart';
@@ -37,7 +38,8 @@
var typesInferrer = typesTask.typesInferrer;
var element = findElement(compiler, "foo");
var mask = typesInferrer.getReturnTypeOfElement(element);
- var falseType = new ValueTypeMask(typesTask.boolType, false);
+ var falseType =
+ new ValueTypeMask(typesTask.boolType, new FalseConstantValue());
// 'foo' should always return false
Expect.equals(falseType, mask);
// the argument to 'bar' is always false
diff --git a/tests/compiler/dart2js/type_order_test.dart b/tests/compiler/dart2js/type_order_test.dart
index e4faa01..5cc9178 100644
--- a/tests/compiler/dart2js/type_order_test.dart
+++ b/tests/compiler/dart2js/type_order_test.dart
@@ -44,15 +44,15 @@
InterfaceType A_X_Y = add(instantiate(A, [X, Y]));
InterfaceType A_Y_X = add(instantiate(A, [Y, X]));
- TypedefType B_this = add(B.computeType(env.compiler));
+ TypedefType B_this = add(B.computeType(env.compiler.resolution));
TypedefType B_raw = add(B.rawType);
TypeVariableType BT = add(B_this.typeArguments[0]);
TypeVariableType BS = add(B_this.typeArguments[1]);
FunctionType B_this_alias = add(B.alias);
TypedefType B_X_Y = add(instantiate(B, [X, Y]));
- FunctionType B_X_Y_alias = add(B_X_Y.unalias(env.compiler));
+ FunctionType B_X_Y_alias = add(B_X_Y.unalias(env.compiler.resolution));
TypedefType B_Y_X = add(instantiate(B, [Y, X]));
- FunctionType B_Y_X_alias = add(B_Y_X.unalias(env.compiler));
+ FunctionType B_Y_X_alias = add(B_Y_X.unalias(env.compiler.resolution));
InterfaceType C_this = add(C.thisType);
InterfaceType C_raw = add(C.rawType);
diff --git a/tests/compiler/dart2js/type_representation_test.dart b/tests/compiler/dart2js/type_representation_test.dart
index 81c3654..83f4806 100644
--- a/tests/compiler/dart2js/type_representation_test.dart
+++ b/tests/compiler/dart2js/type_representation_test.dart
@@ -133,7 +133,8 @@
expect(dynamic_, 'null');
// List<E>
- expect(List_.computeType(env.compiler), '[$List_rep, $List_E_rep]');
+ expect(List_.computeType(env.compiler.resolution),
+ '[$List_rep, $List_E_rep]');
// List
expect(List_.rawType, '$List_rep');
// List<dynamic>
@@ -194,7 +195,7 @@
'$args: [$int_rep], $opt: [,]}], $typedefTag: $Typedef10_rep}]');
// Map<K,V>
- expect(Map_.computeType(env.compiler),
+ expect(Map_.computeType(env.compiler.resolution),
'[$Map_rep, $Map_K_rep, $Map_V_rep]');
// Map
expect(Map_.rawType, '$Map_rep');
@@ -206,49 +207,49 @@
// void m1() {}
- expect(env.getElement('m1').computeType(env.compiler),
+ expect(env.getElement('m1').computeType(env.compiler.resolution),
'{$func: 1, $retvoid: true}');
// int m2() => 0;
- expect(env.getElement('m2').computeType(env.compiler),
+ expect(env.getElement('m2').computeType(env.compiler.resolution),
'{$func: 1, $ret: $int_rep}');
// List<int> m3() => null;
- expect(env.getElement('m3').computeType(env.compiler),
+ expect(env.getElement('m3').computeType(env.compiler.resolution),
'{$func: 1, $ret: [$List_rep, $int_rep]}');
// m4() {}
- expect(env.getElement('m4').computeType(env.compiler),
+ expect(env.getElement('m4').computeType(env.compiler.resolution),
'{$func: 1}');
// m5(int a, String b) {}
- expect(env.getElement('m5').computeType(env.compiler),
+ expect(env.getElement('m5').computeType(env.compiler.resolution),
'{$func: 1, $args: [$int_rep, $String_rep]}');
// m6(int a, [String b]) {}
- expect(env.getElement('m6').computeType(env.compiler),
+ expect(env.getElement('m6').computeType(env.compiler.resolution),
'{$func: 1, $args: [$int_rep],'
' $opt: [$String_rep]}');
// m7(int a, String b, [List<int> c, d]) {}
- expect(env.getElement('m7').computeType(env.compiler),
+ expect(env.getElement('m7').computeType(env.compiler.resolution),
'{$func: 1,'
' $args: [$int_rep, $String_rep],'
' $opt: [[$List_rep, $int_rep],,]}');
// m8(int a, {String b}) {}
- expect(env.getElement('m8').computeType(env.compiler),
+ expect(env.getElement('m8').computeType(env.compiler.resolution),
'{$func: 1,'
' $args: [$int_rep], $named: {b: $String_rep}}');
// m9(int a, String b, {List<int> c, d}) {}
- expect(env.getElement('m9').computeType(env.compiler),
+ expect(env.getElement('m9').computeType(env.compiler.resolution),
'{$func: 1,'
' $args: [$int_rep, $String_rep],'
' $named: {c: [$List_rep, $int_rep], d: null}}');
// m10(void f(int a, [b])) {}
- expect(env.getElement('m10').computeType(env.compiler),
+ expect(env.getElement('m10').computeType(env.compiler.resolution),
'{$func: 1, $args:'
' [{$func: 1,'
' $retvoid: true, $args: [$int_rep], $opt: [,]}]}');
diff --git a/tests/compiler/dart2js/type_substitution_test.dart b/tests/compiler/dart2js/type_substitution_test.dart
index dad50ae..91c8718 100644
--- a/tests/compiler/dart2js/type_substitution_test.dart
+++ b/tests/compiler/dart2js/type_substitution_test.dart
@@ -12,11 +12,12 @@
DartType getType(compiler, String name) {
var clazz = findElement(compiler, "Class");
- clazz.ensureResolved(compiler);
+ clazz.ensureResolved(compiler.resolution);
var element = clazz.buildScope().lookup(name);
Expect.isNotNull(element);
Expect.equals(element.kind, ElementKind.FUNCTION);
- FunctionSignature signature = element.computeSignature(compiler);
+ element.computeType(compiler.resolution);
+ FunctionSignature signature = element.functionSignature;
// Function signatures are used to be to provide void types (only occuring as
// as return types) and (inlined) function types (only occuring as method
@@ -210,7 +211,7 @@
Expect.isNotNull(Typedef2_int_String);
DartType Function_int_String = getType(compiler, "Function2b");
Expect.isNotNull(Function_int_String);
- DartType unalias1 = Typedef2_int_String.unalias(compiler);
+ DartType unalias1 = Typedef2_int_String.unalias(compiler.resolution);
Expect.equals(Function_int_String, unalias1,
'$Typedef2_int_String.unalias=$unalias1 != $Function_int_String');
@@ -218,7 +219,7 @@
Expect.isNotNull(Typedef1);
DartType Function_dynamic_dynamic = getType(compiler, "Function1c");
Expect.isNotNull(Function_dynamic_dynamic);
- DartType unalias2 = Typedef1.unalias(compiler);
+ DartType unalias2 = Typedef1.unalias(compiler.resolution);
Expect.equals(Function_dynamic_dynamic, unalias2,
'$Typedef1.unalias=$unalias2 != $Function_dynamic_dynamic');
}));
diff --git a/tests/compiler/dart2js/type_test_helper.dart b/tests/compiler/dart2js/type_test_helper.dart
index c67d0ba..32ed3ff 100644
--- a/tests/compiler/dart2js/type_test_helper.dart
+++ b/tests/compiler/dart2js/type_test_helper.dart
@@ -92,15 +92,15 @@
var element = compiler.mainApp.find(name);
Expect.isNotNull(element);
if (element.isClass) {
- element.ensureResolved(compiler);
+ element.ensureResolved(compiler.resolution);
} else if (element.isTypedef) {
- element.computeType(compiler);
+ element.computeType(compiler.resolution);
}
return element;
}
DartType getElementType(String name) {
- return getElement(name).computeType(compiler);
+ return getElement(name).computeType(compiler.resolution);
}
DartType operator[] (String name) {
@@ -111,7 +111,7 @@
DartType getMemberType(ClassElement element, String name) {
Element member = element.localLookup(name);
- return member.computeType(compiler);
+ return member.computeType(compiler.resolution);
}
bool isSubtype(DartType T, DartType S) {
diff --git a/tests/compiler/dart2js/unparser2_test.dart b/tests/compiler/dart2js/unparser2_test.dart
index 09c713d..91e13aa 100644
--- a/tests/compiler/dart2js/unparser2_test.dart
+++ b/tests/compiler/dart2js/unparser2_test.dart
@@ -99,7 +99,7 @@
return unparse(node);
}
-class MessageCollector extends DiagnosticListener {
+class MessageCollector extends DiagnosticReporter {
List<String> messages;
MessageCollector() {
messages = [];
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 56f3f17..a257c10 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -237,3 +237,6 @@
symbol_reserved_word_test/09: RuntimeError # Please triage this failure.
symbol_reserved_word_test/12: RuntimeError # Please triage this failure.
symbol_test/none: RuntimeError # Please triage this failure.
+
+[ $compiler == dart2js && $cps_ir && $host_checked ]
+regexp/pcre_test: Crash # Stack Overflow
diff --git a/tests/html/html.status b/tests/html/html.status
index ff918be..557a657 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -13,12 +13,15 @@
cross_domain_iframe_test: RuntimeError # Dartium JSInterop failure
crypto_test/functional: RuntimeError # Dartium JSInterop failure
custom/document_register_basic_test: RuntimeError # Dartium JSInterop failure
+custom/document_register_type_extensions_test/construction: RuntimeError # Issue 24516
+custom/document_register_type_extensions_test/parsing: RuntimeError # Issue 24516
custom/document_register_type_extensions_test/registration: RuntimeError # Dartium JSInterop failure
custom/element_upgrade_test: RuntimeError # Dartium JSInterop failure
custom/js_custom_test: RuntimeError # Dartium JSInterop failure
custom_elements_test/register: RuntimeError # Dartium JSInterop failure
indexeddb_2_test: Skip # Dartium JSInterop failure
-js_test: RuntimeError # Dartium JSInterop failure
+js_test/transferrables: RuntimeError # Dartium JSInterop failure
+js_test/JsArray: RuntimeError # Dartium JSInterop failure
native_gc_test: Skip # Dartium JSInterop failure
speechrecognition_test/types: RuntimeError # Dartium JSInterop failure
storage_quota_test/missingenumcheck: RuntimeError # Dartium JSInterop failure
@@ -37,6 +40,7 @@
[ $compiler == dart2js ]
input_element_test/attributes: Fail # Issue 21555
+wrapping_collections_test: SkipByDesign # Testing an issue that is only relevant to Dartium
[ $compiler == dart2js && $csp && $browser ]
custom/js_custom_test: Fail # Issue 14643
@@ -59,7 +63,6 @@
[ $compiler == none && ($runtime == drt || $runtime == dartium || $runtime == ContentShellOnAndroid) ]
# postMessage in dartium always transfers the typed array buffer, never a view
postmessage_structured_test/typed_arrays: Fail
-postmessage_structured_test/primitives: RuntimeError # Bug 24432
# Dartium seems to lose the data from the dispatchEvent.
async_test: Fail # Uses spawn, not implemented from a DOM isolate in Dartium
keyboard_event_test: Fail # Issue 13902
@@ -134,10 +137,10 @@
[$runtime == ie10 || $runtime == ie11]
indexeddb_5_test: Fail # Issue 12893
-js_test: Fail # Issue 14246
-element_test/click: Fail # IE does not support firing this event.
+js_test/transferrables: RuntimeError # Issue 14246
+element_test/click: Fail # IE does not support firing this event.
serialized_script_value_test: Fail
-websocket_test/websocket: Fail # TODO(efortuna): Issue 7875.
+websocket_test/websocket: Fail # Issue 7875. Closed with "working as intended".
canvasrenderingcontext2d_test/drawImage_video_element: Fail # IE does not support drawImage w/ video element
canvasrenderingcontext2d_test/drawImage_video_element_dataUrl: Fail # IE does not support drawImage w/ video element
no_linked_scripts_htmltest: Skip # Times out on IE. Issue 21537
diff --git a/tests/html/js_test.dart b/tests/html/js_test.dart
index 081ab02..ab83a5c 100644
--- a/tests/html/js_test.dart
+++ b/tests/html/js_test.dart
@@ -11,7 +11,7 @@
import 'dart:js';
import 'package:unittest/unittest.dart';
-import 'package:unittest/html_config.dart';
+import 'package:unittest/html_individual_config.dart';
_injectJs() {
final script = new ScriptElement();
@@ -230,7 +230,7 @@
main() {
_injectJs();
- useHtmlConfiguration();
+ useHtmlIndividualConfiguration();
group('identity', () {
@@ -552,7 +552,7 @@
array.length = 3;
expect(array, [1, 2, null]);
});
-
+
test('add', () {
var array = new JsArray();
array.add('a');
diff --git a/tests/html/wrapping_collections_test.dart b/tests/html/wrapping_collections_test.dart
new file mode 100644
index 0000000..dc84508
--- /dev/null
+++ b/tests/html/wrapping_collections_test.dart
@@ -0,0 +1,26 @@
+library wrapping_collection_test;
+
+import 'dart:html';
+import 'dart:js' as js;
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+/// Test that if we access objects through JS-interop we get the
+/// appropriate objects, even if dart:html maps them.
+main() {
+ test("Access through JS-interop", () {
+ var performance = js.context['performance'];
+ var entries = performance.callMethod('getEntries', const []);
+ entries.forEach((x) {
+ expect(x is js.JsObject, isTrue);
+ });
+ });
+
+ test("Access through dart:html", () {
+ var dartPerformance = wrap_jso(js.context['performance']);
+ var dartEntries = dartPerformance.getEntries();
+ dartEntries.forEach((x) {
+ expect(x is PerformanceEntry, isTrue);
+ });
+ });
+}
\ No newline at end of file
diff --git a/tests/isolate/package_root_test.dart b/tests/isolate/package_root_test.dart
index 2ee6b30..a17bce7 100644
--- a/tests/isolate/package_root_test.dart
+++ b/tests/isolate/package_root_test.dart
@@ -5,32 +5,27 @@
import 'dart:io';
import 'dart:isolate';
-final SPAWN_PACKAGE_ROOT = Uri.parse("otherPackageRoot");
+final SPAWN_PACKAGE_ROOT = "file:///no/such/file/";
void main([args, port]) {
if (port != null) {
- testPackageRoot(args);
+ testPackageRoot(port);
return;
}
- var p = new ReceivePort();
+ var p = new RawReceivePort();
Isolate.spawnUri(Platform.script,
- [p.sendPort, Platform.packageRoot],
- {},
- packageRoot: SPAWN_PACKAGE_ROOT);
- p.listen((msg) {
+ [],
+ p.sendPort,
+ packageRoot: Uri.parse(SPAWN_PACKAGE_ROOT));
+ p.handler = (msg) {
p.close();
- });
+ if (msg != SPAWN_PACKAGE_ROOT) {
+ throw "Bad package root in child isolate: $msg";
+ }
+ };
}
-
-void testPackageRoot(args) {
- var parentPackageRoot = args[1];
- if (parentPackageRoot == Platform.packageRoot) {
- throw "Got parent package root";
- }
- if (Uri.parse(Platform.packageRoot) != SPAWN_PACKAGE_ROOT) {
- throw "Wrong package root";
- }
- args[0].send(null);
+testPackageRoot(port) async {
+ var packageRoot = await Isolate.packageRoot;
+ port.send(packageRoot.toString());
}
-
diff --git a/tests/language/await_regression_test.dart b/tests/language/await_regression_test.dart
index 9c3e663..90a562d 100644
--- a/tests/language/await_regression_test.dart
+++ b/tests/language/await_regression_test.dart
@@ -30,7 +30,19 @@
Expect.equals(sum, 0);
}
+testSideEffects() async {
+ Future foo(int a1, int a2) {
+ Expect.equals(10, a1);
+ Expect.equals(11, a2);
+ return new Future.value();
+ }
+ int a = 10;
+ await foo(a++, a++);
+ Expect.equals(12, a);
+}
+
main() async {
testNestedFunctions();
testNamedArguments();
+ testSideEffects();
}
diff --git a/tests/language/language.status b/tests/language/language.status
index 9ad2646..e164c45 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -73,6 +73,9 @@
mirror_in_static_init_test: Fail # Issue 22071
vm/debug_break_enabled_vm_test/*: Skip # Issue 14651.
+[ $compiler == none && $runtime == dartium && $system == linux && $arch != x64 ]
+issue_22780_test/01 : Pass, Timeout # Issue 24473
+
[ $compiler == none && $runtime == drt ]
disassemble_test: Pass, Fail # Issue 18122
@@ -94,6 +97,4 @@
vm/load_to_load_unaligned_forwarding_vm_test: Pass, Crash # Unaligned offset. Issue 22151
[ $compiler == none && ( $runtime == dartium || $runtime == drt ) ]
-mixin_super_test: Fail # Can't pass VMOptions to dartium.
-mixin_super_bound2_test: Fail # Can't pass VMOptions to dartium.
issue23244_test: Fail # Can't run spawnFunction on dartium.
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index bb3cf05..a5f91bf 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -362,6 +362,9 @@
mixin_super_bound_test: StaticWarning # legitimate StaticWarning, cannot be annotated
mixin_super_bound2_test: CompileTimeError # Issue 23772
mixin_super_test: CompileTimeError # Issue 23772
+mixin_super_2_test: CompileTimeError # Issue 23772
+mixin_super_use_test: CompileTimeError # Issue 23772
+mixin_superclass_test: CompileTimeError # Issue 23772
named_constructor_test/01: StaticWarning
named_constructor_test/03: StaticWarning
named_parameters2_test: StaticWarning
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index 24de2b9..e42ce660 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -303,6 +303,11 @@
mixin_invalid_bound_test/none: StaticWarning # legitimate StaticWarning, cannot be annotated
mixin_invalid_bound2_test/none: StaticWarning # legitimate StaticWarning, cannot be annotated
mixin_super_bound_test: StaticWarning # legitimate StaticWarning, cannot be annotated
+mixin_super_bound2_test: CompileTimeError # Issue 24478
+mixin_super_test: CompileTimeError # Issue 24478
+mixin_super_2_test: CompileTimeError # Issue 24478
+mixin_super_use_test: CompileTimeError # Issue 24478
+mixin_superclass_test: CompileTimeError # Issue 24478
named_constructor_test/01: StaticWarning
named_constructor_test/03: StaticWarning
named_parameters2_test: StaticWarning
@@ -416,7 +421,8 @@
switch7_negative_test: CompileTimeError
switch_fallthru_test: StaticWarning
test_negative_test: CompileTimeError
-top_level_non_prefixed_library_test: StaticWarning
+# Note: test is in error but analyzer doesn't notice due to bug #24502
+# top_level_non_prefixed_library_test: StaticWarning
try_catch4_test: StaticWarning
try_catch5_test: StaticWarning
type_argument_in_super_type_test: StaticWarning
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 99ceb15..06637d1 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -49,7 +49,10 @@
mixin_super_constructor_named_test/01: Fail # Issue 15101
mixin_super_constructor_positionals_test/01: Fail # Issue 15101
mixin_super_test: CompileTimeError # Issue 23773
+mixin_super_2_test: CompileTimeError # Issue 23773
mixin_super_bound2_test: CompileTimeError # Issue 23773
+mixin_super_use_test: CompileTimeError # Issue 23773
+mixin_superclass_test: CompileTimeError # Issue 23773
ref_before_declaration_test/00: MissingCompileTimeError
ref_before_declaration_test/01: MissingCompileTimeError
@@ -368,8 +371,8 @@
switch_label2_test: Crash # (switch (target){cas... continue to a labeled switch case
switch_label_test: Crash # (switch (animal){cas... continue to a labeled switch case
switch_try_catch_test: Crash # (switch (0){_0:case ... continue to a labeled switch case
-sync_generator1_test/01: Timeout # Please triage this failure.
-sync_generator1_test/none: Timeout # Please triage this failure.
+sync_generator1_test/01: RuntimeError # Expect.equals(expected: <(1, 2, 3, 5, [6])>, actual: <(1)>) fails.
+sync_generator1_test/none: RuntimeError # Expect.equals(expected: <(1, 2, 3, 5, [6])>, actual: <(1)>) fails.
sync_generator3_test/test1: RuntimeError # Please triage this failure.
sync_generator3_test/test2: RuntimeError # Please triage this failure.
syncstar_yield_test/copyParameters: RuntimeError # Please triage this failure.
@@ -379,3 +382,10 @@
type_variable_field_initializer_closure_test: RuntimeError # Please triage this failure.
type_variable_field_initializer_test: RuntimeError # Please triage this failure.
type_variable_nested_test: RuntimeError # Please triage this failure.
+
+[ $compiler == dart2js && $cps_ir && $host_checked ]
+async_throw_in_catch_test/forceAwait: Crash # Issue 24485
+async_throw_in_catch_test/none: Crash # Issue 24485
+execute_finally9_test: Crash # Issue 24485
+regress_21795_test: Crash # Issue 24485
+regress_23537_test: Crash # Issue 24485
diff --git a/tests/language/mixin_illegal_superclass_test.dart b/tests/language/mixin_illegal_superclass_test.dart
deleted file mode 100644
index 03d2e6a..0000000
--- a/tests/language/mixin_illegal_superclass_test.dart
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright (c) 2013, 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.
-
-class S0 { }
-class S1 extends Object { }
-class S2 extends S0 { }
-
-class M0 { }
-class M1 extends Object { }
-class M2 extends M0 { }
-
-class C00 = S0 with M0;
-class C01 = S0 with M1;
-class C02 = S0 with M2; /// 01: compile-time error
-class C03 = S0 with M0, M1;
-class C04 = S0 with M0, M2; /// 02: compile-time error
-class C05 = S0 with M2, M0; /// 03: compile-time error
-class C06 = S0 with M1, M2; /// 04: compile-time error
-class C07 = S0 with M2, M1; /// 05: compile-time error
-
-class C10 = S1 with M0;
-class C11 = S1 with M1;
-class C12 = S1 with M2; /// 06: compile-time error
-class C13 = S1 with M0, M1;
-class C14 = S1 with M0, M2; /// 07: compile-time error
-class C15 = S1 with M2, M0; /// 08: compile-time error
-class C16 = S1 with M1, M2; /// 09: compile-time error
-class C17 = S1 with M2, M1; /// 10: compile-time error
-
-class C20 = S2 with M0;
-class C21 = S2 with M1;
-class C22 = S2 with M2; /// 11: compile-time error
-class C23 = S2 with M0, M1;
-class C24 = S2 with M0, M2; /// 12: compile-time error
-class C25 = S2 with M2, M0; /// 13: compile-time error
-class C26 = S2 with M1, M2; /// 14: compile-time error
-class C27 = S2 with M2, M1; /// 15: compile-time error
-
-class D00 extends S0 with M0 { }
-class D01 extends S0 with M1 { }
-class D02 extends S0 with M2 { } /// 16: compile-time error
-class D03 extends S0 with M0, M1 { }
-class D04 extends S0 with M0, M2 { } /// 17: compile-time error
-class D05 extends S0 with M2, M0 { } /// 18: compile-time error
-class D06 extends S0 with M1, M2 { } /// 19: compile-time error
-class D07 extends S0 with M2, M1 { } /// 20: compile-time error
-
-class D10 extends S1 with M0 { }
-class D11 extends S1 with M1 { }
-class D12 extends S1 with M2 { } /// 21: compile-time error
-class D13 extends S1 with M0, M1 { }
-class D14 extends S1 with M0, M2 { } /// 22: compile-time error
-class D15 extends S1 with M2, M0 { } /// 23: compile-time error
-class D16 extends S1 with M1, M2 { } /// 24: compile-time error
-class D17 extends S1 with M2, M1 { } /// 25: compile-time error
-
-class D20 extends S2 with M0 { }
-class D21 extends S2 with M1 { }
-class D22 extends S2 with M2 { } /// 26: compile-time error
-class D23 extends S2 with M0, M1 { }
-class D24 extends S2 with M0, M2 { } /// 27: compile-time error
-class D25 extends S2 with M2, M0 { } /// 28: compile-time error
-class D26 extends S2 with M1, M2 { } /// 29: compile-time error
-class D27 extends S2 with M2, M1 { } /// 30: compile-time error
-
-main() {
- new C00();
- new C01();
- new C02(); /// 01: continued
- new C03();
- new C04(); /// 02: continued
- new C05(); /// 03: continued
- new C06(); /// 04: continued
- new C07(); /// 05: continued
-
- new C10();
- new C11();
- new C12(); /// 06: continued
- new C13();
- new C14(); /// 07: continued
- new C15(); /// 08: continued
- new C16(); /// 09: continued
- new C17(); /// 10: continued
-
- new C20();
- new C21();
- new C22(); /// 11: continued
- new C23();
- new C24(); /// 12: continued
- new C25(); /// 13: continued
- new C26(); /// 14: continued
- new C27(); /// 15: continued
-
- new D00();
- new D01();
- new D02(); /// 16: continued
- new D03();
- new D04(); /// 17: continued
- new D05(); /// 18: continued
- new D06(); /// 19: continued
- new D07(); /// 20: continued
-
- new D10();
- new D11();
- new D12(); /// 21: continued
- new D13();
- new D14(); /// 22: continued
- new D15(); /// 23: continued
- new D16(); /// 24: continued
- new D17(); /// 25: continued
-
- new D20();
- new D21();
- new D22(); /// 26: continued
- new D23();
- new D24(); /// 27: continued
- new D25(); /// 28: continued
- new D26(); /// 29: continued
- new D27(); /// 30: continued
-}
diff --git a/tests/language/mixin_super_2_test.dart b/tests/language/mixin_super_2_test.dart
new file mode 100644
index 0000000..ad86c08
--- /dev/null
+++ b/tests/language/mixin_super_2_test.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2015, 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 B {
+ // 'super' resolves to Object, and in some tests, multiple points in the
+ // inheritance chain.
+ toString() => 'B(' + super.toString() + ')';
+}
+
+class R {
+ toString() => 'R[' + super.toString() + ']';
+}
+
+class D extends R with B {
+ toString() => 'D<' + super.toString() + '>';
+}
+
+class E extends D with B {
+ toString() => 'E{' + super.toString() + '}';
+}
+
+class F = R with B, B;
+
+class G extends F with B {
+ toString() => 'G{' + super.toString() + '}';
+}
+
+main(){
+ check(object, String expected) {
+ Expect.equals(expected, object.toString());
+ }
+
+ check(new B(), "B(Instance of 'B')");
+ check(new R(), "R[Instance of 'R']");
+ check(new D(), "D<B(R[Instance of 'D'])>");
+ check(new E(), "E{B(D<B(R[Instance of 'E'])>)}");
+ check(new F(), "B(B(R[Instance of 'F']))");
+ check(new G(), "G{B(B(B(R[Instance of 'G'])))}");
+}
diff --git a/tests/language/mixin_super_bound2_test.dart b/tests/language/mixin_super_bound2_test.dart
index 87e8b7a..c6fcd7a 100644
--- a/tests/language/mixin_super_bound2_test.dart
+++ b/tests/language/mixin_super_bound2_test.dart
@@ -1,7 +1,6 @@
// Copyright (c) 2015, 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.
-// SharedOptions=--supermixin
import "package:expect/expect.dart";
diff --git a/tests/language/mixin_super_test.dart b/tests/language/mixin_super_test.dart
index 8a4ee98..6a5d5a3 100644
--- a/tests/language/mixin_super_test.dart
+++ b/tests/language/mixin_super_test.dart
@@ -1,7 +1,6 @@
// Copyright (c) 2015, 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.
-// SharedOptions=--supermixin
import "package:expect/expect.dart";
diff --git a/tests/language/mixin_illegal_super_use_test.dart b/tests/language/mixin_super_use_test.dart
similarity index 64%
rename from tests/language/mixin_illegal_super_use_test.dart
rename to tests/language/mixin_super_use_test.dart
index 7f0d64a..cd95846 100644
--- a/tests/language/mixin_illegal_super_use_test.dart
+++ b/tests/language/mixin_super_use_test.dart
@@ -9,21 +9,15 @@
class P0 {
foo() {
- super.toString(); /// 01: compile-time error
- super.foo(); /// 02: compile-time error
- super.bar = 100; /// 03: compile-time error
+ super.toString();
void inner() {
- super.toString(); /// 04: compile-time error
- super.foo(); /// 05: compile-time error
- super.bar = 100; /// 06: compile-time error
+ super.toString();
}
inner();
(() {
- super.toString(); /// 07: compile-time error
- super.foo(); /// 08: compile-time error
- super.bar = 100; /// 09: compile-time error
+ super.toString();
})();
return 42;
@@ -32,7 +26,7 @@
class P1 {
bar() {
- super.toString(); /// 10: compile-time error
+ super.toString();
return 87;
}
@@ -52,7 +46,7 @@
class P2 {
baz() {
- super.toString(); /// 11: compile-time error
+ super.toString();
return 99;
}
}
diff --git a/tests/language/mixin_superclass_test.dart b/tests/language/mixin_superclass_test.dart
new file mode 100644
index 0000000..ade41da
--- /dev/null
+++ b/tests/language/mixin_superclass_test.dart
@@ -0,0 +1,121 @@
+// Copyright (c) 2013, 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.
+
+class S0 { }
+class S1 extends Object { }
+class S2 extends S0 { }
+
+class M0 { }
+class M1 extends Object { }
+class M2 extends M0 { }
+
+class C00 = S0 with M0;
+class C01 = S0 with M1;
+class C02 = S0 with M2;
+class C03 = S0 with M0, M1;
+class C04 = S0 with M0, M2;
+class C05 = S0 with M2, M0;
+class C06 = S0 with M1, M2;
+class C07 = S0 with M2, M1;
+
+class C10 = S1 with M0;
+class C11 = S1 with M1;
+class C12 = S1 with M2;
+class C13 = S1 with M0, M1;
+class C14 = S1 with M0, M2;
+class C15 = S1 with M2, M0;
+class C16 = S1 with M1, M2;
+class C17 = S1 with M2, M1;
+
+class C20 = S2 with M0;
+class C21 = S2 with M1;
+class C22 = S2 with M2;
+class C23 = S2 with M0, M1;
+class C24 = S2 with M0, M2;
+class C25 = S2 with M2, M0;
+class C26 = S2 with M1, M2;
+class C27 = S2 with M2, M1;
+
+class D00 extends S0 with M0 { }
+class D01 extends S0 with M1 { }
+class D02 extends S0 with M2 { }
+class D03 extends S0 with M0, M1 { }
+class D04 extends S0 with M0, M2 { }
+class D05 extends S0 with M2, M0 { }
+class D06 extends S0 with M1, M2 { }
+class D07 extends S0 with M2, M1 { }
+
+class D10 extends S1 with M0 { }
+class D11 extends S1 with M1 { }
+class D12 extends S1 with M2 { }
+class D13 extends S1 with M0, M1 { }
+class D14 extends S1 with M0, M2 { }
+class D15 extends S1 with M2, M0 { }
+class D16 extends S1 with M1, M2 { }
+class D17 extends S1 with M2, M1 { }
+
+class D20 extends S2 with M0 { }
+class D21 extends S2 with M1 { }
+class D22 extends S2 with M2 { }
+class D23 extends S2 with M0, M1 { }
+class D24 extends S2 with M0, M2 { }
+class D25 extends S2 with M2, M0 { }
+class D26 extends S2 with M1, M2 { }
+class D27 extends S2 with M2, M1 { }
+
+main() {
+ new C00();
+ new C01();
+ new C02();
+ new C03();
+ new C04();
+ new C05();
+ new C06();
+ new C07();
+
+ new C10();
+ new C11();
+ new C12();
+ new C13();
+ new C14();
+ new C15();
+ new C16();
+ new C17();
+
+ new C20();
+ new C21();
+ new C22();
+ new C23();
+ new C24();
+ new C25();
+ new C26();
+ new C27();
+
+ new D00();
+ new D01();
+ new D02();
+ new D03();
+ new D04();
+ new D05();
+ new D06();
+ new D07();
+
+ new D10();
+ new D11();
+ new D12();
+ new D13();
+ new D14();
+ new D15();
+ new D16();
+ new D17();
+
+ new D20();
+ new D21();
+ new D22();
+ new D23();
+ new D24();
+ new D25();
+ new D26();
+ new D27();
+}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index c667970..473f375 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -350,3 +350,6 @@
mirrors/library_enumeration_deferred_loading_test: RuntimeError # L.loadLibrary is not a function
mirrors/symbol_validation_test/none: RuntimeError # Please triage this failure.
mirrors/typedef_deferred_library_test: RuntimeError # G.loadLibrary is not a function
+
+[ $compiler == dart2js && $cps_ir && $host_checked ]
+mirrors/circular_factory_redirection_test/02: Crash # Assertion failure: Constant constructor already computed for generative_constructor(A#circular2)
diff --git a/tests/standalone/io/http_proxy_advanced_test.dart b/tests/standalone/io/http_proxy_advanced_test.dart
new file mode 100644
index 0000000..aeafaf0
--- /dev/null
+++ b/tests/standalone/io/http_proxy_advanced_test.dart
@@ -0,0 +1,636 @@
+// Copyright (c) 2013, 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:crypto/crypto.dart";
+import "package:expect/expect.dart";
+import "package:path/path.dart";
+import "dart:async";
+import "dart:io";
+import 'dart:convert';
+
+String localFile(path) => Platform.script.resolve(path).toFilePath();
+
+SecurityContext serverContext = new SecurityContext()
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
+
+SecurityContext clientContext = new SecurityContext()
+ ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+
+class Server {
+ HttpServer server;
+ bool secure;
+ int proxyHops;
+ List<String> directRequestPaths;
+ int requestCount = 0;
+
+ Server(this.proxyHops, this.directRequestPaths, this.secure);
+
+ Future<Server> start() {
+ return (secure ?
+ HttpServer.bindSecure("localhost", 0, serverContext) :
+ HttpServer.bind("localhost", 0))
+ .then((s) {
+ server = s;
+ server.listen(requestHandler);
+ return this;
+ });
+ }
+
+ void requestHandler(HttpRequest request) {
+ var response = request.response;
+ requestCount++;
+ // Check whether a proxy or direct connection is expected.
+ bool direct = directRequestPaths.fold(
+ false,
+ (prev, path) => prev ? prev : path == request.uri.path);
+ if (!secure && !direct && proxyHops > 0) {
+ Expect.isNotNull(request.headers[HttpHeaders.VIA]);
+ Expect.equals(1, request.headers[HttpHeaders.VIA].length);
+ Expect.equals(
+ proxyHops,
+ request.headers[HttpHeaders.VIA][0].split(",").length);
+ } else {
+ Expect.isNull(request.headers[HttpHeaders.VIA]);
+ }
+ var body = new StringBuffer();
+ onRequestComplete() {
+ String path = request.uri.path.substring(1);
+ if (path != "A") {
+ String content = "$path$path$path";
+ Expect.equals(content, body.toString());
+ }
+ response.write(request.uri.path);
+ response.close();
+ }
+ request.listen((data) {
+ body.write(new String.fromCharCodes(data));
+ }, onDone: onRequestComplete);
+ }
+
+ void shutdown() {
+ server.close();
+ }
+
+ int get port => server.port;
+}
+
+Future<Server> setupServer(int proxyHops,
+ {List<String> directRequestPaths: const <String>[],
+ secure: false}) {
+ Server server = new Server(proxyHops, directRequestPaths, secure);
+ return server.start();
+}
+
+class ProxyServer {
+ final bool ipV6;
+ HttpServer server;
+ HttpClient client;
+ int requestCount = 0;
+ String authScheme;
+ String realm = "test";
+ String username;
+ String password;
+
+ var ha1;
+ String serverAlgorithm = "MD5";
+ String serverQop = "auth";
+ Set ncs = new Set();
+
+ var nonce = "12345678"; // No need for random nonce in test.
+
+ ProxyServer({this.ipV6: false}) : client = new HttpClient();
+
+ void useBasicAuthentication(String username, String password) {
+ this.username = username;
+ this.password = password;
+ authScheme = "Basic";
+ }
+
+ void useDigestAuthentication(String username, String password) {
+ this.username = username;
+ this.password = password;
+ authScheme = "Digest";
+
+ // Calculate ha1.
+ var hasher = new MD5();
+ hasher.add("${username}:${realm}:${password}".codeUnits);
+ ha1 = CryptoUtils.bytesToHex(hasher.close());
+ }
+
+ basicAuthenticationRequired(request) {
+ request.fold(null, (x, y) {}).then((_) {
+ var response = request.response;
+ response.headers.set(HttpHeaders.PROXY_AUTHENTICATE,
+ "Basic, realm=$realm");
+ response.statusCode = HttpStatus.PROXY_AUTHENTICATION_REQUIRED;
+ response.close();
+ });
+ }
+
+ digestAuthenticationRequired(request, {stale: false}) {
+ request.fold(null, (x, y) {}).then((_) {
+ var response = request.response;
+ response.statusCode = HttpStatus.PROXY_AUTHENTICATION_REQUIRED;
+ StringBuffer authHeader = new StringBuffer();
+ authHeader.write('Digest');
+ authHeader.write(', realm="$realm"');
+ authHeader.write(', nonce="$nonce"');
+ if (stale) authHeader.write(', stale="true"');
+ if (serverAlgorithm != null) {
+ authHeader.write(', algorithm=$serverAlgorithm');
+ }
+ if (serverQop != null) authHeader.write(', qop="$serverQop"');
+ response.headers.set(HttpHeaders.PROXY_AUTHENTICATE, authHeader);
+ response.close();
+ });
+ }
+
+ Future<ProxyServer> start() {
+ var x = new Completer();
+ var host = ipV6 ? "::1" : "localhost";
+ HttpServer.bind(host, 0).then((s) {
+ server = s;
+ x.complete(this);
+ server.listen((HttpRequest request) {
+ requestCount++;
+ if (username != null && password != null) {
+ if (request.headers[HttpHeaders.PROXY_AUTHORIZATION] == null) {
+ if (authScheme == "Digest") {
+ digestAuthenticationRequired(request);
+ } else {
+ basicAuthenticationRequired(request);
+ }
+ return;
+ } else {
+ Expect.equals(
+ 1, request.headers[HttpHeaders.PROXY_AUTHORIZATION].length);
+ String authorization =
+ request.headers[HttpHeaders.PROXY_AUTHORIZATION][0];
+ if (authScheme == "Basic") {
+ List<String> tokens = authorization.split(" ");
+ Expect.equals("Basic", tokens[0]);
+ String auth =
+ CryptoUtils.bytesToBase64(UTF8.encode("$username:$password"));
+ if (auth != tokens[1]) {
+ basicAuthenticationRequired(request);
+ return;
+ }
+ } else {
+ HeaderValue header =
+ HeaderValue.parse(
+ authorization, parameterSeparator: ",");
+ Expect.equals("Digest", header.value);
+ var uri = header.parameters["uri"];
+ var qop = header.parameters["qop"];
+ var cnonce = header.parameters["cnonce"];
+ var nc = header.parameters["nc"];
+ Expect.equals(username, header.parameters["username"]);
+ Expect.equals(realm, header.parameters["realm"]);
+ Expect.equals("MD5", header.parameters["algorithm"]);
+ Expect.equals(nonce, header.parameters["nonce"]);
+ Expect.equals(request.uri.toString(), uri);
+ if (qop != null) {
+ // A server qop of auth-int is downgraded to none by the client.
+ Expect.equals("auth", serverQop);
+ Expect.equals("auth", header.parameters["qop"]);
+ Expect.isNotNull(cnonce);
+ Expect.isNotNull(nc);
+ Expect.isFalse(ncs.contains(nc));
+ ncs.add(nc);
+ } else {
+ Expect.isNull(cnonce);
+ Expect.isNull(nc);
+ }
+ Expect.isNotNull(header.parameters["response"]);
+
+ var hasher = new MD5();
+ hasher.add("${request.method}:${uri}".codeUnits);
+ var ha2 = CryptoUtils.bytesToHex(hasher.close());
+
+ var x;
+ hasher = new MD5();
+ if (qop == null || qop == "" || qop == "none") {
+ hasher.add("$ha1:${nonce}:$ha2".codeUnits);
+ } else {
+ hasher.add(
+ "$ha1:${nonce}:${nc}:${cnonce}:${qop}:$ha2".codeUnits);
+ }
+ Expect.equals(CryptoUtils.bytesToHex(hasher.close()),
+ header.parameters["response"]);
+
+ // Add a bogus Proxy-Authentication-Info for testing.
+ var info = 'rspauth="77180d1ab3d6c9de084766977790f482", '
+ 'cnonce="8f971178", '
+ 'nc=000002c74, '
+ 'qop=auth';
+ request.response.headers.set("Proxy-Authentication-Info", info);
+ }
+ }
+ }
+ // Open the connection from the proxy.
+ if (request.method == "CONNECT") {
+ var tmp = request.uri.toString().split(":");
+ Socket.connect(tmp[0], int.parse(tmp[1]))
+ .then((socket) {
+ request.response.reasonPhrase = "Connection established";
+ request.response.detachSocket()
+ .then((detached) {
+ socket.pipe(detached);
+ detached.pipe(socket);
+ });
+ });
+ } else {
+ client.openUrl(request.method, request.uri)
+ .then((HttpClientRequest clientRequest) {
+ // Forward all headers.
+ request.headers.forEach((String name, List<String> values) {
+ values.forEach((String value) {
+ if (name != "content-length" && name != "via") {
+ clientRequest.headers.add(name, value);
+ }
+ });
+ });
+ // Special handling of Content-Length and Via.
+ clientRequest.contentLength = request.contentLength;
+ List<String> via = request.headers[HttpHeaders.VIA];
+ String viaPrefix = via == null ? "" : "${via[0]}, ";
+ clientRequest.headers.add(
+ HttpHeaders.VIA, "${viaPrefix}1.1 localhost:$port");
+ // Copy all content.
+ return request.pipe(clientRequest);
+ })
+ .then((HttpClientResponse clientResponse) {
+ clientResponse.pipe(request.response);
+ });
+ }
+ });
+ });
+ return x.future;
+ }
+
+ void shutdown() {
+ server.close();
+ client.close();
+ }
+
+ int get port => server.port;
+}
+
+Future<ProxyServer> setupProxyServer({ipV6: false}) {
+ ProxyServer proxyServer = new ProxyServer(ipV6: ipV6);
+ return proxyServer.start();
+}
+
+
+int testProxyIPV6DoneCount = 0;
+void testProxyIPV6() {
+ setupProxyServer(ipV6: true).then((proxyServer) {
+ setupServer(1, directRequestPaths: ["/4"]).then((server) {
+ setupServer(1, directRequestPaths: ["/4"], secure: true).then((secureServer) {
+ HttpClient client = new HttpClient(context: clientContext);
+
+ List<String> proxy = ["PROXY [::1]:${proxyServer.port}"];
+ client.findProxy = (Uri uri) {
+ // Pick the proxy configuration based on the request path.
+ int index = int.parse(uri.path.substring(1));
+ return proxy[index];
+ };
+
+ for (int i = 0; i < proxy.length; i++) {
+ test(bool secure) {
+ String url = secure
+ ? "https://localhost:${secureServer.port}/$i"
+ : "http://localhost:${server.port}/$i";
+
+ client.postUrl(Uri.parse(url))
+ .then((HttpClientRequest clientRequest) {
+ String content = "$i$i$i";
+ clientRequest.write(content);
+ return clientRequest.close();
+ })
+ .then((HttpClientResponse response) {
+ response.listen((_) {}, onDone: () {
+ testProxyIPV6DoneCount++;
+ if (testProxyIPV6DoneCount == proxy.length * 2) {
+ Expect.equals(proxy.length, server.requestCount);
+ Expect.equals(proxy.length, secureServer.requestCount);
+ proxyServer.shutdown();
+ server.shutdown();
+ secureServer.shutdown();
+ client.close();
+ }
+ });
+ });
+ }
+
+ test(false);
+ test(true);
+ }
+ });
+ });
+ });
+}
+
+
+int testProxyFromEnviromentDoneCount = 0;
+void testProxyFromEnviroment() {
+ setupProxyServer().then((proxyServer) {
+ setupServer(1).then((server) {
+ setupServer(1, secure: true).then((secureServer) {
+ HttpClient client = new HttpClient(context: clientContext);
+
+ client.findProxy = (Uri uri) {
+ return HttpClient.findProxyFromEnvironment(
+ uri,
+ environment: {"http_proxy": "localhost:${proxyServer.port}",
+ "https_proxy": "localhost:${proxyServer.port}"});
+ };
+
+ const int loopCount = 5;
+ for (int i = 0; i < loopCount; i++) {
+ test(bool secure) {
+ String url = secure
+ ? "https://localhost:${secureServer.port}/$i"
+ : "http://localhost:${server.port}/$i";
+
+ client.postUrl(Uri.parse(url))
+ .then((HttpClientRequest clientRequest) {
+ String content = "$i$i$i";
+ clientRequest.write(content);
+ return clientRequest.close();
+ })
+ .then((HttpClientResponse response) {
+ response.listen((_) {}, onDone: () {
+ testProxyFromEnviromentDoneCount++;
+ if (testProxyFromEnviromentDoneCount == loopCount * 2) {
+ Expect.equals(loopCount, server.requestCount);
+ Expect.equals(loopCount, secureServer.requestCount);
+ proxyServer.shutdown();
+ server.shutdown();
+ secureServer.shutdown();
+ client.close();
+ }
+ });
+ });
+ }
+
+ test(false);
+ test(true);
+ }
+ });
+ });
+ });
+}
+
+
+int testProxyAuthenticateCount = 0;
+Future testProxyAuthenticate(bool useDigestAuthentication) {
+ testProxyAuthenticateCount = 0;
+ var completer = new Completer();
+
+ setupProxyServer().then((proxyServer) {
+ setupServer(1).then((server) {
+ setupServer(1, secure: true).then((secureServer) {
+ HttpClient client = new HttpClient(context: clientContext);
+
+ Completer step1 = new Completer();
+ Completer step2 = new Completer();
+
+ if (useDigestAuthentication) {
+ proxyServer.useDigestAuthentication("dart", "password");
+ } else {
+ proxyServer.useBasicAuthentication("dart", "password");
+ }
+
+ // Test with no authentication.
+ client.findProxy = (Uri uri) {
+ return "PROXY localhost:${proxyServer.port}";
+ };
+
+ const int loopCount = 2;
+ for (int i = 0; i < loopCount; i++) {
+ test(bool secure) {
+ String url = secure
+ ? "https://localhost:${secureServer.port}/$i"
+ : "http://localhost:${server.port}/$i";
+
+ client.postUrl(Uri.parse(url))
+ .then((HttpClientRequest clientRequest) {
+ String content = "$i$i$i";
+ clientRequest.write(content);
+ return clientRequest.close();
+ })
+ .then((HttpClientResponse response) {
+ Expect.fail("No response expected");
+ }).
+ catchError((e) {
+ testProxyAuthenticateCount++;
+ if (testProxyAuthenticateCount == loopCount * 2) {
+ Expect.equals(0, server.requestCount);
+ Expect.equals(0, secureServer.requestCount);
+ step1.complete(null);
+ }
+ });
+ }
+
+ test(false);
+ test(true);
+ }
+ step1.future.then((_) {
+ testProxyAuthenticateCount = 0;
+ if (useDigestAuthentication) {
+ client.findProxy = (Uri uri) => "PROXY localhost:${proxyServer.port}";
+ client.addProxyCredentials(
+ "localhost",
+ proxyServer.port,
+ "test",
+ new HttpClientDigestCredentials("dart", "password"));
+ } else {
+ client.findProxy = (Uri uri) {
+ return "PROXY dart:password@localhost:${proxyServer.port}";
+ };
+ }
+
+ for (int i = 0; i < loopCount; i++) {
+ test(bool secure) {
+ var path = useDigestAuthentication ? "A" : "$i";
+ String url = secure
+ ? "https://localhost:${secureServer.port}/$path"
+ : "http://localhost:${server.port}/$path";
+
+ client.postUrl(Uri.parse(url))
+ .then((HttpClientRequest clientRequest) {
+ String content = "$i$i$i";
+ clientRequest.write(content);
+ return clientRequest.close();
+ })
+ .then((HttpClientResponse response) {
+ response.listen((_) {}, onDone: () {
+ testProxyAuthenticateCount++;
+ Expect.equals(HttpStatus.OK, response.statusCode);
+ if (testProxyAuthenticateCount == loopCount * 2) {
+ Expect.equals(loopCount, server.requestCount);
+ Expect.equals(loopCount, secureServer.requestCount);
+ step2.complete(null);
+ }
+ });
+ });
+ }
+
+ test(false);
+ test(true);
+ }
+ });
+
+ step2.future.then((_) {
+ testProxyAuthenticateCount = 0;
+ client.findProxy = (Uri uri) {
+ return "PROXY localhost:${proxyServer.port}";
+ };
+
+ client.authenticateProxy = (host, port, scheme, realm) {
+ client.addProxyCredentials(
+ "localhost",
+ proxyServer.port,
+ "realm",
+ new HttpClientBasicCredentials("dart", "password"));
+ return new Future.value(true);
+ };
+
+ for (int i = 0; i < loopCount; i++) {
+ test(bool secure) {
+ String url = secure
+ ? "https://localhost:${secureServer.port}/A"
+ : "http://localhost:${server.port}/A";
+
+ client.postUrl(Uri.parse(url))
+ .then((HttpClientRequest clientRequest) {
+ String content = "$i$i$i";
+ clientRequest.write(content);
+ return clientRequest.close();
+ })
+ .then((HttpClientResponse response) {
+ response.listen((_) {}, onDone: () {
+ testProxyAuthenticateCount++;
+ Expect.equals(HttpStatus.OK, response.statusCode);
+ if (testProxyAuthenticateCount == loopCount * 2) {
+ Expect.equals(loopCount * 2, server.requestCount);
+ Expect.equals(loopCount * 2, secureServer.requestCount);
+ proxyServer.shutdown();
+ server.shutdown();
+ secureServer.shutdown();
+ client.close();
+ completer.complete(null);
+ }
+ });
+ });
+ }
+ test(false);
+ test(true);
+ }
+ });
+
+ });
+ });
+ });
+
+ return completer.future;
+}
+
+int testRealProxyDoneCount = 0;
+void testRealProxy() {
+ setupServer(1).then((server) {
+ HttpClient client = new HttpClient(context: clientContext);
+ client.addProxyCredentials(
+ "localhost",
+ 8080,
+ "test",
+ new HttpClientBasicCredentials("dart", "password"));
+
+ List<String> proxy =
+ ["PROXY localhost:8080",
+ "PROXY localhost:8080; PROXY hede.hule.hest:8080",
+ "PROXY hede.hule.hest:8080; PROXY localhost:8080",
+ "PROXY localhost:8080; DIRECT"];
+
+ client.findProxy = (Uri uri) {
+ // Pick the proxy configuration based on the request path.
+ int index = int.parse(uri.path.substring(1));
+ return proxy[index];
+ };
+
+ for (int i = 0; i < proxy.length; i++) {
+ client.getUrl(Uri.parse("http://localhost:${server.port}/$i"))
+ .then((HttpClientRequest clientRequest) {
+ String content = "$i$i$i";
+ clientRequest.contentLength = content.length;
+ clientRequest.write(content);
+ return clientRequest.close();
+ })
+ .then((HttpClientResponse response) {
+ response.listen((_) {}, onDone: () {
+ if (++testRealProxyDoneCount == proxy.length) {
+ Expect.equals(proxy.length, server.requestCount);
+ server.shutdown();
+ client.close();
+ }
+ });
+ });
+ }
+ });
+}
+
+int testRealProxyAuthDoneCount = 0;
+void testRealProxyAuth() {
+ setupServer(1).then((server) {
+ HttpClient client = new HttpClient(context: clientContext);
+
+ List<String> proxy =
+ ["PROXY dart:password@localhost:8080",
+ "PROXY dart:password@localhost:8080; PROXY hede.hule.hest:8080",
+ "PROXY hede.hule.hest:8080; PROXY dart:password@localhost:8080",
+ "PROXY dart:password@localhost:8080; DIRECT"];
+
+ client.findProxy = (Uri uri) {
+ // Pick the proxy configuration based on the request path.
+ int index = int.parse(uri.path.substring(1));
+ return proxy[index];
+ };
+
+ for (int i = 0; i < proxy.length; i++) {
+ client.getUrl(Uri.parse("http://localhost:${server.port}/$i"))
+ .then((HttpClientRequest clientRequest) {
+ String content = "$i$i$i";
+ clientRequest.contentLength = content.length;
+ clientRequest.write(content);
+ return clientRequest.close();
+ })
+ .then((HttpClientResponse response) {
+ response.listen((_) {}, onDone: () {
+ if (++testRealProxyAuthDoneCount == proxy.length) {
+ Expect.equals(proxy.length, server.requestCount);
+ server.shutdown();
+ client.close();
+ }
+ });
+ });
+ }
+ });
+}
+
+main() {
+ testProxyIPV6();
+ testProxyFromEnviroment();
+ // The two invocations use the same global variable for state -
+ // run one after the other.
+ testProxyAuthenticate(false)
+ .then((_) => testProxyAuthenticate(true));
+
+ // This test is not normally run. It can be used for locally testing
+ // with a real proxy server (e.g. Apache).
+ // testRealProxy();
+ // testRealProxyAuth();
+}
diff --git a/tests/standalone/io/http_proxy_test.dart b/tests/standalone/io/http_proxy_test.dart
index 9b8803b..e5607e9 100644
--- a/tests/standalone/io/http_proxy_test.dart
+++ b/tests/standalone/io/http_proxy_test.dart
@@ -285,7 +285,7 @@
}
testInvalidProxy() {
- HttpClient client = new HttpClient();
+ HttpClient client = new HttpClient(context: clientContext);
client.findProxy = (Uri uri) => "";
client.getUrl(Uri.parse("http://www.google.com/test"))
@@ -307,7 +307,7 @@
int testDirectDoneCount = 0;
void testDirectProxy() {
setupServer(0).then((server) {
- HttpClient client = new HttpClient();
+ HttpClient client = new HttpClient(context: clientContext);
List<String> proxy =
["DIRECT", " DIRECT ", "DIRECT ;", " DIRECT ; ",
";DIRECT", " ; DIRECT ", ";;DIRECT;;"];
@@ -407,54 +407,6 @@
});
}
-int testProxyIPV6DoneCount = 0;
-void testProxyIPV6() {
- setupProxyServer(ipV6: true).then((proxyServer) {
- setupServer(1, directRequestPaths: ["/4"]).then((server) {
- setupServer(1, directRequestPaths: ["/4"], secure: true).then((secureServer) {
- HttpClient client = new HttpClient();
-
- List<String> proxy = ["PROXY [::1]:${proxyServer.port}"];
- client.findProxy = (Uri uri) {
- // Pick the proxy configuration based on the request path.
- int index = int.parse(uri.path.substring(1));
- return proxy[index];
- };
-
- for (int i = 0; i < proxy.length; i++) {
- test(bool secure) {
- String url = secure
- ? "https://localhost:${secureServer.port}/$i"
- : "http://localhost:${server.port}/$i";
-
- client.postUrl(Uri.parse(url))
- .then((HttpClientRequest clientRequest) {
- String content = "$i$i$i";
- clientRequest.write(content);
- return clientRequest.close();
- })
- .then((HttpClientResponse response) {
- response.listen((_) {}, onDone: () {
- testProxyIPV6DoneCount++;
- if (testProxyIPV6DoneCount == proxy.length * 2) {
- Expect.equals(proxy.length, server.requestCount);
- Expect.equals(proxy.length, secureServer.requestCount);
- proxyServer.shutdown();
- server.shutdown();
- secureServer.shutdown();
- client.close();
- }
- });
- });
- }
-
- test(false);
- test(true);
- }
- });
- });
- });
-}
int testProxyChainDoneCount = 0;
void testProxyChain() {
@@ -464,7 +416,7 @@
proxyServer1.client.findProxy = (_) => "PROXY localhost:${proxyServer2.port}";
setupServer(2, directRequestPaths: ["/4"]).then((server) {
- HttpClient client = new HttpClient();
+ HttpClient client = new HttpClient(context: clientContext);
List<String> proxy;
if (Platform.operatingSystem == "windows") {
@@ -518,308 +470,9 @@
});
}
-int testProxyFromEnviromentDoneCount = 0;
-void testProxyFromEnviroment() {
- setupProxyServer().then((proxyServer) {
- setupServer(1).then((server) {
- setupServer(1, secure: true).then((secureServer) {
- HttpClient client = new HttpClient();
-
- client.findProxy = (Uri uri) {
- return HttpClient.findProxyFromEnvironment(
- uri,
- environment: {"http_proxy": "localhost:${proxyServer.port}",
- "https_proxy": "localhost:${proxyServer.port}"});
- };
-
- const int loopCount = 5;
- for (int i = 0; i < loopCount; i++) {
- test(bool secure) {
- String url = secure
- ? "https://localhost:${secureServer.port}/$i"
- : "http://localhost:${server.port}/$i";
-
- client.postUrl(Uri.parse(url))
- .then((HttpClientRequest clientRequest) {
- String content = "$i$i$i";
- clientRequest.write(content);
- return clientRequest.close();
- })
- .then((HttpClientResponse response) {
- response.listen((_) {}, onDone: () {
- testProxyFromEnviromentDoneCount++;
- if (testProxyFromEnviromentDoneCount == loopCount * 2) {
- Expect.equals(loopCount, server.requestCount);
- Expect.equals(loopCount, secureServer.requestCount);
- proxyServer.shutdown();
- server.shutdown();
- secureServer.shutdown();
- client.close();
- }
- });
- });
- }
-
- test(false);
- test(true);
- }
- });
- });
- });
-}
-
-
-int testProxyAuthenticateCount = 0;
-Future testProxyAuthenticate(bool useDigestAuthentication) {
- testProxyAuthenticateCount = 0;
- var completer = new Completer();
-
- setupProxyServer().then((proxyServer) {
- setupServer(1).then((server) {
- setupServer(1, secure: true).then((secureServer) {
- HttpClient client = new HttpClient();
-
- Completer step1 = new Completer();
- Completer step2 = new Completer();
-
- if (useDigestAuthentication) {
- proxyServer.useDigestAuthentication("dart", "password");
- } else {
- proxyServer.useBasicAuthentication("dart", "password");
- }
-
- // Test with no authentication.
- client.findProxy = (Uri uri) {
- return "PROXY localhost:${proxyServer.port}";
- };
-
- const int loopCount = 2;
- for (int i = 0; i < loopCount; i++) {
- test(bool secure) {
- String url = secure
- ? "https://localhost:${secureServer.port}/$i"
- : "http://localhost:${server.port}/$i";
-
- client.postUrl(Uri.parse(url))
- .then((HttpClientRequest clientRequest) {
- String content = "$i$i$i";
- clientRequest.write(content);
- return clientRequest.close();
- })
- .then((HttpClientResponse response) {
- Expect.fail("No response expected");
- }).
- catchError((e) {
- testProxyAuthenticateCount++;
- if (testProxyAuthenticateCount == loopCount * 2) {
- Expect.equals(0, server.requestCount);
- Expect.equals(0, secureServer.requestCount);
- step1.complete(null);
- }
- });
- }
-
- test(false);
- test(true);
- }
- step1.future.then((_) {
- testProxyAuthenticateCount = 0;
- if (useDigestAuthentication) {
- client.findProxy = (Uri uri) => "PROXY localhost:${proxyServer.port}";
- client.addProxyCredentials(
- "localhost",
- proxyServer.port,
- "test",
- new HttpClientDigestCredentials("dart", "password"));
- } else {
- client.findProxy = (Uri uri) {
- return "PROXY dart:password@localhost:${proxyServer.port}";
- };
- }
-
- for (int i = 0; i < loopCount; i++) {
- test(bool secure) {
- var path = useDigestAuthentication ? "A" : "$i";
- String url = secure
- ? "https://localhost:${secureServer.port}/$path"
- : "http://localhost:${server.port}/$path";
-
- client.postUrl(Uri.parse(url))
- .then((HttpClientRequest clientRequest) {
- String content = "$i$i$i";
- clientRequest.write(content);
- return clientRequest.close();
- })
- .then((HttpClientResponse response) {
- response.listen((_) {}, onDone: () {
- testProxyAuthenticateCount++;
- Expect.equals(HttpStatus.OK, response.statusCode);
- if (testProxyAuthenticateCount == loopCount * 2) {
- Expect.equals(loopCount, server.requestCount);
- Expect.equals(loopCount, secureServer.requestCount);
- step2.complete(null);
- }
- });
- });
- }
-
- test(false);
- test(true);
- }
- });
-
- step2.future.then((_) {
- testProxyAuthenticateCount = 0;
- client.findProxy = (Uri uri) {
- return "PROXY localhost:${proxyServer.port}";
- };
-
- client.authenticateProxy = (host, port, scheme, realm) {
- client.addProxyCredentials(
- "localhost",
- proxyServer.port,
- "realm",
- new HttpClientBasicCredentials("dart", "password"));
- return new Future.value(true);
- };
-
- for (int i = 0; i < loopCount; i++) {
- test(bool secure) {
- String url = secure
- ? "https://localhost:${secureServer.port}/A"
- : "http://localhost:${server.port}/A";
-
- client.postUrl(Uri.parse(url))
- .then((HttpClientRequest clientRequest) {
- String content = "$i$i$i";
- clientRequest.write(content);
- return clientRequest.close();
- })
- .then((HttpClientResponse response) {
- response.listen((_) {}, onDone: () {
- testProxyAuthenticateCount++;
- Expect.equals(HttpStatus.OK, response.statusCode);
- if (testProxyAuthenticateCount == loopCount * 2) {
- Expect.equals(loopCount * 2, server.requestCount);
- Expect.equals(loopCount * 2, secureServer.requestCount);
- proxyServer.shutdown();
- server.shutdown();
- secureServer.shutdown();
- client.close();
- completer.complete(null);
- }
- });
- });
- }
- test(false);
- test(true);
- }
- });
-
- });
- });
- });
-
- return completer.future;
-}
-
-int testRealProxyDoneCount = 0;
-void testRealProxy() {
- setupServer(1).then((server) {
- HttpClient client = new HttpClient();
- client.addProxyCredentials(
- "localhost",
- 8080,
- "test",
- new HttpClientBasicCredentials("dart", "password"));
-
- List<String> proxy =
- ["PROXY localhost:8080",
- "PROXY localhost:8080; PROXY hede.hule.hest:8080",
- "PROXY hede.hule.hest:8080; PROXY localhost:8080",
- "PROXY localhost:8080; DIRECT"];
-
- client.findProxy = (Uri uri) {
- // Pick the proxy configuration based on the request path.
- int index = int.parse(uri.path.substring(1));
- return proxy[index];
- };
-
- for (int i = 0; i < proxy.length; i++) {
- client.getUrl(Uri.parse("http://localhost:${server.port}/$i"))
- .then((HttpClientRequest clientRequest) {
- String content = "$i$i$i";
- clientRequest.contentLength = content.length;
- clientRequest.write(content);
- return clientRequest.close();
- })
- .then((HttpClientResponse response) {
- response.listen((_) {}, onDone: () {
- if (++testRealProxyDoneCount == proxy.length) {
- Expect.equals(proxy.length, server.requestCount);
- server.shutdown();
- client.close();
- }
- });
- });
- }
- });
-}
-
-int testRealProxyAuthDoneCount = 0;
-void testRealProxyAuth() {
- setupServer(1).then((server) {
- HttpClient client = new HttpClient();
-
- List<String> proxy =
- ["PROXY dart:password@localhost:8080",
- "PROXY dart:password@localhost:8080; PROXY hede.hule.hest:8080",
- "PROXY hede.hule.hest:8080; PROXY dart:password@localhost:8080",
- "PROXY dart:password@localhost:8080; DIRECT"];
-
- client.findProxy = (Uri uri) {
- // Pick the proxy configuration based on the request path.
- int index = int.parse(uri.path.substring(1));
- return proxy[index];
- };
-
- for (int i = 0; i < proxy.length; i++) {
- client.getUrl(Uri.parse("http://localhost:${server.port}/$i"))
- .then((HttpClientRequest clientRequest) {
- String content = "$i$i$i";
- clientRequest.contentLength = content.length;
- clientRequest.write(content);
- return clientRequest.close();
- })
- .then((HttpClientResponse response) {
- response.listen((_) {}, onDone: () {
- if (++testRealProxyAuthDoneCount == proxy.length) {
- Expect.equals(proxy.length, server.requestCount);
- server.shutdown();
- client.close();
- }
- });
- });
- }
- });
-}
-
main() {
testInvalidProxy();
testDirectProxy();
testProxy();
- // testProxyIPV6(); // TODO(24074): Move failing tests to separate files.
testProxyChain();
- // TODO(24074): Move failing tests to separate files.
- // testProxyFromEnviroment();
- // The two invocations of uses the same global variable for state -
- // run one after the other.
- // TODO(24074): Move failing tests to separate files.
- // testProxyAuthenticate(false)
- // .then((_) => testProxyAuthenticate(true));
-
- // This test is not normally run. It can be used for locally testing
- // with a real proxy server (e.g. Apache).
- // testRealProxy();
- // testRealProxyAuth();
}
diff --git a/tests/standalone/io/raw_datagram_socket_test.dart b/tests/standalone/io/raw_datagram_socket_test.dart
index 9b952d6..20d841e 100644
--- a/tests/standalone/io/raw_datagram_socket_test.dart
+++ b/tests/standalone/io/raw_datagram_socket_test.dart
@@ -127,7 +127,8 @@
asyncEnd();
}
}
- broadcastTimer = new Timer.periodic(new Duration(milliseconds: 10), send);
+ broadcastTimer =
+ new Timer.periodic(new Duration(milliseconds: 10), send);
});
}
@@ -194,7 +195,7 @@
}
}
-testSendReceive(InternetAddress bindAddress) {
+testSendReceive(InternetAddress bindAddress, int dataSize) {
asyncStart();
var total = 1000;
@@ -218,7 +219,7 @@
}
Uint8List createDataPackage(int seq) {
- var data = new Uint8List(1000);
+ var data = new Uint8List(dataSize);
(new ByteData.view(data.buffer, 0, 4)).setUint32(0, seq);
return data;
}
@@ -236,7 +237,7 @@
// Send a datagram acknowledging the received sequence.
int bytes = sender.send(
createDataPackage(seq), bindAddress, receiver.port);
- Expect.isTrue(bytes == 0 || bytes == 1000);
+ Expect.isTrue(bytes == 0 || bytes == dataSize);
}
void sendAck(address, port) {
@@ -287,6 +288,7 @@
var datagram = receiver.receive();
if (datagram != null) {
Expect.equals(datagram.port, sender.port);
+ Expect.equals(dataSize, datagram.data.length);
if (!bindAddress.isMulticast) {
Expect.equals(receiver.address, datagram.address);
}
@@ -318,6 +320,12 @@
}
testBroadcast();
testLoopbackMulticast();
- testSendReceive(InternetAddress.LOOPBACK_IP_V4);
- testSendReceive(InternetAddress.LOOPBACK_IP_V6);
+ testSendReceive(InternetAddress.LOOPBACK_IP_V4, 1000);
+ testSendReceive(InternetAddress.LOOPBACK_IP_V6, 1000);
+ if (!Platform.isMacOS) {
+ testSendReceive(InternetAddress.LOOPBACK_IP_V4, 32 * 1024);
+ testSendReceive(InternetAddress.LOOPBACK_IP_V6, 32 * 1024);
+ testSendReceive(InternetAddress.LOOPBACK_IP_V4, 64 * 1024 - 32);
+ testSendReceive(InternetAddress.LOOPBACK_IP_V6, 64 * 1024 - 32);
+ }
}
diff --git a/tests/standalone/io/security_context_argument_test.dart b/tests/standalone/io/security_context_argument_test.dart
new file mode 100644
index 0000000..5e263f6
--- /dev/null
+++ b/tests/standalone/io/security_context_argument_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2015, 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";
+import "dart:io";
+
+String localFile(path) => Platform.script.resolve(path).toFilePath();
+
+bool printException(e) { print(e); return true; }
+bool argumentError(e) => e is ArgumentError;
+bool argumentOrTypeError(e) => e is ArgumentError || e is TypeError;
+bool tlsException(e) => e is TlsException;
+
+void testUsePrivateKeyArguments() {
+ var c = new SecurityContext();
+ c.useCertificateChain(localFile('certificates/server_chain.pem'));
+ Expect.throws(() => c.usePrivateKey(
+ localFile('certificates/server_key.pem'), password: "dart" * 1000),
+ argumentError);
+ Expect.throws(() => c.usePrivateKey(
+ localFile('certificates/server_key.pem')),
+ tlsException);
+ Expect.throws(() => c.usePrivateKey(
+ localFile('certificates/server_key.pem'), password: "iHackSites"),
+ tlsException);
+ Expect.throws(() => c.usePrivateKey(
+ localFile('certificates/server_key_oops.pem'), password: "dartdart"),
+ tlsException);
+ Expect.throws(() => c.usePrivateKey(1), argumentOrTypeError);
+ Expect.throws(() => c.usePrivateKey(null), argumentError);
+ Expect.throws(() => c.usePrivateKey(
+ localFile('certificates/server_key_oops.pem'), password: 3),
+ argumentOrTypeError);
+ c.usePrivateKey(
+ localFile('certificates/server_key.pem'), password: "dartdart");
+}
+
+void main() {
+ testUsePrivateKeyArguments();
+}
diff --git a/tests/standalone/io/server_socket_reference_issue21383_and_issue21384_test.dart b/tests/standalone/io/server_socket_reference_issue21383_and_issue21384_test.dart
deleted file mode 100644
index 95e0363..0000000
--- a/tests/standalone/io/server_socket_reference_issue21383_and_issue21384_test.dart
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:io';
-
-import 'package:async_helper/async_helper.dart';
-
-
-testBothListen() {
- asyncStart();
- ServerSocket.bind('127.0.0.1', 0).then((mainServer) {
- mainServer.reference.create().then((refServer) {
- refServer.listen((_) {});
- mainServer.listen((_) {});
- Timer.run(() {
- mainServer.close();
- refServer.close();
- asyncEnd();
- });
- });
- });
-}
-
-testRefServerListen() {
- asyncStart();
- ServerSocket.bind('127.0.0.1', 0).then((mainServer) {
- mainServer.reference.create().then((refServer) {
- refServer.listen((_) {});
- Timer.run(() {
- mainServer.close();
- refServer.close();
- asyncEnd();
- });
- });
- });
-}
-
-testMainServerListen() {
- asyncStart();
- ServerSocket.bind('127.0.0.1', 0).then((mainServer) {
- mainServer.reference.create().then((refServer) {
- mainServer.listen((_) {});
- Timer.run(() {
- mainServer.close();
- refServer.close();
- asyncEnd();
- });
- });
- });
-}
-
-testNoneListen() {
- asyncStart();
- ServerSocket.bind('127.0.0.1', 0).then((mainServer) {
- mainServer.reference.create().then((refServer) {
- Timer.run(() {
- mainServer.close();
- refServer.close();
- asyncEnd();
- });
- });
- });
-}
-
-main() {
- testNoneListen();
- testMainServerListen();
- testRefServerListen();
- testBothListen();
-}
-
diff --git a/tests/standalone/io/socket_bind_test.dart b/tests/standalone/io/socket_bind_test.dart
index 9d36c22..9c4e1ed 100644
--- a/tests/standalone/io/socket_bind_test.dart
+++ b/tests/standalone/io/socket_bind_test.dart
@@ -82,69 +82,6 @@
});
}
-testSocketReferenceInteroperability(String host) {
- asyncStart();
- ServerSocket.bind(host, 0).then((ServerSocket socket) {
- Expect.isTrue(socket.port > 0);
-
- asyncStart();
- socket.reference.create().then((socket2) {
- bool gotResponseFrom1;
- bool gotResponseFrom2;
-
- Expect.isTrue(socket.port > 0);
- Expect.equals(socket.port, socket2.port);
-
- asyncStart();
- asyncStart();
- asyncStart();
- socket.listen((client) {
- client.drain().whenComplete(asyncEnd);
- client.write('1: hello world');
- client.close().whenComplete(asyncEnd);
- // NOTE: Closing the socket un-subscribes as well, which means the
- // other client connection must go to the other socket.
- socket.close().whenComplete(asyncEnd);
- }, onDone: asyncEnd);
-
- asyncStart();
- asyncStart();
- asyncStart();
- socket2.listen((client) {
- client.drain().whenComplete(asyncEnd);
- client.write('2: hello world');
- client.close().whenComplete(asyncEnd);
- // NOTE: Closing the socket un-subscribes as well, which means the
- // other client connection must go to the other socket.
- socket2.close().whenComplete(asyncEnd);
- }, onDone: asyncEnd);
-
- var futures = [];
- for (int i = 0; i < 2; i++) {
- asyncStart();
- futures.add(
- Socket.connect(socket.address, socket.port).then((Socket socket) {
- socket.close().whenComplete(asyncEnd);
- asyncStart();
- return socket
- .transform(ASCII.decoder).join('').then((String result) {
- if (result == '1: hello world') gotResponseFrom1 = true;
- else if (result == '2: hello world') gotResponseFrom2 = true;
- else throw 'Unexpected result from server: $result';
- asyncEnd();
- });
- }));
- }
- asyncStart();
- Future.wait(futures).then((_) {
- Expect.isTrue(gotResponseFrom1);
- Expect.isTrue(gotResponseFrom2);
- asyncEnd();
- });
- });
- });
-}
-
testListenCloseListenClose(String host) async {
asyncStart();
@@ -184,8 +121,6 @@
negTestBindV6OnlyMismatch(host, true);
negTestBindV6OnlyMismatch(host, false);
- testSocketReferenceInteroperability(host);
-
testListenCloseListenClose(host);
}
diff --git a/tests/standalone/noopt_test.dart b/tests/standalone/noopt_test.dart
new file mode 100644
index 0000000..171f3a5
--- /dev/null
+++ b/tests/standalone/noopt_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2015, 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.
+
+/// VMOptions=--noopt
+
+main() {
+ print("Hello, --noopt World!");
+}
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index f552859..a1b6c50 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -62,6 +62,7 @@
out_of_memory_test: Skip
verbose_gc_to_bmu_test: Skip
precompilation_test: Skip # Standalone only test.
+noopt_test: Skip # Standalone only test.
[ $compiler == dartanalyzer || $compiler == dart2analyzer ]
javascript_int_overflow_literal_test/01: Fail, OK
@@ -105,9 +106,11 @@
unboxed_int_converter_test: Skip
pair_location_remapping_test: Skip
precompilation_test: Skip # Standalone only test.
+noopt_test: Skip # Standalone only test.
[ $runtime == vm && $arch == ia32]
precompilation_test: Skip # Not expected to pass on ia32.
+noopt_test: Skip # Not expected to pass on ia32.
[ $runtime == vm && $arch == arm]
precompilation_test: Skip # Issue 24427
diff --git a/tests/try/poi/apply_updates_test.dart b/tests/try/poi/apply_updates_test.dart
index 361ee03..e8c8429 100644
--- a/tests/try/poi/apply_updates_test.dart
+++ b/tests/try/poi/apply_updates_test.dart
@@ -40,7 +40,7 @@
Future run() => loadMainApp().then((LibraryElement library) {
// Capture the current version of [before] before invoking the [updater].
PartialFunctionElement before = library.localLookup(expectedUpdate);
- var beforeNode = before.parseNode(compiler);
+ var beforeNode = before.parseNode(compiler.parsing);
var context = new IncrementalCompilerContext();
LibraryUpdater updater =
@@ -56,10 +56,10 @@
// Check that the [updater] didn't modify the changed element.
Expect.identical(before, update.before);
- Expect.identical(beforeNode, before.parseNode(compiler));
+ Expect.identical(beforeNode, before.parseNode(compiler.parsing));
PartialFunctionElement after = update.after;
- var afterNode = after.parseNode(compiler);
+ var afterNode = after.parseNode(compiler.parsing);
// Check that pretty-printing the elements match [source] (before), and
// [newSource] (after).
@@ -72,7 +72,7 @@
// Check that the update was applied by pretty-printing [before]. Make no
// assumptions about [after], as the update may destroy that element.
- beforeNode = before.parseNode(compiler);
+ beforeNode = before.parseNode(compiler.parsing);
Expect.notEquals(source, '$beforeNode');
Expect.stringEquals(newSource, '$beforeNode');
});
diff --git a/tools/VERSION b/tools/VERSION
index 774c773..6143c4e 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 1
MINOR 13
PATCH 0
-PRERELEASE 5
+PRERELEASE 6
PRERELEASE_PATCH 0
diff --git a/tools/deps/dartium.deps/DEPS b/tools/deps/dartium.deps/DEPS
index 3c6dd66..0662675 100644
--- a/tools/deps/dartium.deps/DEPS
+++ b/tools/deps/dartium.deps/DEPS
@@ -14,7 +14,7 @@
"dartium_chromium_commit": "62a7524d4f71c9e0858d24b0aa1bbff3a2d09bff",
"chromium_base_revision": "297060",
"dartium_webkit_branch": "/blink/branches/dart/dartium",
- "dartium_webkit_revision": "202671",
+ "dartium_webkit_revision": "202673",
# We use mirrors of all github repos to guarantee reproducibility and
# consistency between what users see and what the bots see.
@@ -36,7 +36,7 @@
"collection_rev": "@1da9a07f32efa2ba0c391b289e2037391e31da0e",
"crypto_rev" : "@2df57a1e26dd88e8d0614207d4b062c73209917d",
"csslib_tag" : "@0.12.0",
- "dart2js_info_rev" : "@bad01369f1f605ab688d505c135db54de927318f",
+ "dart2js_info_rev" : "@ffd03ee45f7459efd3039ff565b4d0aa2e7cd9e7",
"glob_rev": "@704cf75e4f26b417505c5c611bdaacd8808467dd",
"html_tag" : "@0.12.1+1",
"http_rev" : "@9b93e1542c753090c50b46ef1592d44bc858bfe7",
diff --git a/tools/dom/scripts/generator.py b/tools/dom/scripts/generator.py
index fe4e03e..6f31a7d 100644
--- a/tools/dom/scripts/generator.py
+++ b/tools/dom/scripts/generator.py
@@ -515,7 +515,7 @@
return ', '.join(map(param_name, self.param_infos[:parameter_count]))
def isCallback(self, type_registry, type_id):
- if type_id:
+ if type_id and not type_id.endswith('[]'):
callback_type = type_registry._database._all_interfaces[type_id]
return callback_type.operations[0].id == 'handleEvent' if len(callback_type.operations) > 0 else False
else:
@@ -1446,7 +1446,8 @@
return_type == 'Future' or
return_type == 'SqlDatabase' or # renamed to Database
return_type == 'HTMLElement' or
- return_type == 'MutationObserver')
+ return_type == 'MutationObserver' or
+ return_type.endswith('[]'))
def wrap_type_blink(return_type, type_registry):
"""Returns True if the type is a blink type that requires wrap_jso but
diff --git a/tools/dom/src/dartium_CustomElementSupport.dart b/tools/dom/src/dartium_CustomElementSupport.dart
index a14e07f..d80f2c4 100644
--- a/tools/dom/src/dartium_CustomElementSupport.dart
+++ b/tools/dom/src/dartium_CustomElementSupport.dart
@@ -26,11 +26,12 @@
}
}
- Element upgrade(Element element) {
- if (element.runtimeType != _nativeType) {
+ Element upgrade(element) {
+ if (element.runtimeType != js.JsObjectImpl) {
throw new UnsupportedError('Element is incorrect type');
}
- return _Utils.changeElementWrapper(element, _type);
+
+ return createCustomUpgrader(_nativeType, element);
}
}
diff --git a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
index 952f556..30400a1 100644
--- a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
@@ -149,3 +149,8 @@
// TODO(17738): Implement this.
throw new UnimplementedError();
}
+
+/// Dartium functions that are a NOOP in dart2js.
+unwrap_jso(dartClass_instance) => dartClass_instance;
+wrap_jso(jsObject) => jsObject;
+createCustomUpgrader(Type customElementClass, $this) => $this;
diff --git a/tools/dom/templates/html/dartium/html_dartium.darttemplate b/tools/dom/templates/html/dartium/html_dartium.darttemplate
index b15dab2..25336a7 100644
--- a/tools/dom/templates/html/dartium/html_dartium.darttemplate
+++ b/tools/dom/templates/html/dartium/html_dartium.darttemplate
@@ -351,6 +351,9 @@
********** **********
******************************************************************************/
+// List of known tagName to DartClass for custom elements, used for upgrade.
+var _knownCustomeElements = new Map<String, Type>();
+
Rectangle make_dart_rectangle(r) =>
r == null ? null : new Rectangle(r['left'], r['top'], r['width'], r['height']);
@@ -370,19 +373,7 @@
/**
* Return the JsObject associated with a Dart class [dartClass_instance].
*/
-unwrap_jso(dartClass_instance) {
- try {
- if (dartClass_instance != null)
- return dartClass_instance is NativeFieldWrapperClass2 ?
- dartClass_instance.blink_jsObject : dartClass_instance;
- else
- return null;
- } catch(NoSuchMethodException) {
- // No blink_jsObject then return the dartClass_instance is probably an
- // array that was already converted to a Dart class e.g., Uint8ClampedList.
- return dartClass_instance;
- }
-}
+unwrap_jso(dartClass_instance) => js.unwrap_jso(dartClass_instance);
/**
* Create Dart class that maps to the JS Type, add the JsObject as an expando
@@ -390,10 +381,26 @@
*/
wrap_jso(jsObject) {
try {
- if (jsObject is! js.JsObject) {
+ if (jsObject is! js.JsObject || jsObject == null) {
// JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
+ // or it's a simple type.
return jsObject;
}
+
+ // TODO(alanknight): With upgraded custom elements this causes a failure because
+ // we need a new wrapper after the type changes. We could possibly invalidate this
+ // if the constructor name didn't match?
+ var wrapper = js.getDartHtmlWrapperFor(jsObject);
+ if (wrapper != null) {
+ return wrapper;
+ }
+
+ if (jsObject is js.JsArray) {
+ var wrappingList = new _DartHtmlWrappingList(jsObject);
+ js.setDartHtmlWrapperFor(jsObject, wrappingList);
+ return wrappingList;
+ }
+
// Try the most general type conversions on it.
// TODO(alanknight): We may be able to do better. This maintains identity,
// which is useful, but expensive. And if we nest something that only
@@ -416,10 +423,24 @@
// Got a dart_class (it's a custom element) use it it's already set up.
dartClass_instance = jsObject['dart_class'];
} else {
- var func = getHtmlCreateFunction(jsTypeName);
- if (func != null) {
- dartClass_instance = func();
- dartClass_instance.blink_jsObject = jsObject;
+ var localName = jsObject['localName'];
+ var customElementClass = _knownCustomeElements[localName];
+ // Custom Element to upgrade.
+ if (jsTypeName == 'HTMLElement' && customElementClass != null) {
+ try {
+ dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
+ } finally {
+ dartClass_instance.blink_jsObject = jsObject;
+ jsObject['dart_class'] = dartClass_instance;
+ js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
+ }
+ } else {
+ var func = getHtmlCreateFunction(jsTypeName);
+ if (func != null) {
+ dartClass_instance = func();
+ dartClass_instance.blink_jsObject = jsObject;
+ js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
+ }
}
}
return dartClass_instance;
@@ -538,6 +559,41 @@
// Conversion function place holder (currently not used in dart2js or dartium).
List convertDartToNative_StringArray(List<String> input) => input;
+/**
+ * Wraps a JsArray and will call wrap_jso on its entries.
+ */
+class _DartHtmlWrappingList extends ListBase {
+ _DartHtmlWrappingList(this._basicList);
+
+ final js.JsArray _basicList;
+
+ operator [](int index) => wrap_jso(_basicList[index]);
+
+ operator []=(int index, value) => _basicList[index] = unwrap_jso(value);
+
+ int get length => _basicList.length;
+ int set length(int newLength) => _basicList.length = newLength;
+}
+
+/**
+ * Upgrade the JS HTMLElement to the Dart class. Used by Dart's Polymer.
+ */
+createCustomUpgrader(Type customElementClass, $this) {
+ var dartClass;
+ try {
+ dartClass = _blink.Blink_Utils.constructElement(customElementClass, $this);
+ } catch (e) {
+ throw e;
+ } finally {
+ // Need to remember the Dart class that was created for this custom so
+ // return it and setup the blink_jsObject to the $this that we'll be working
+ // with as we talk to blink.
+ $this['dart_class'] = dartClass;
+ }
+
+ return dartClass;
+}
+
$else
class JsoNativeFieldWrapper extends NativeFieldWrapperClass2 {}
@@ -547,5 +603,6 @@
convertDartToNative_Dictionary(Map dict) => dict;
List convertDartToNative_StringArray(List<String> input) => input;
convertDartToNative_List(List input) => input;
+createCustomUpgrader(Type customElementClass, $this) => $this;
$endif
diff --git a/tools/dom/templates/html/impl/impl_Document.darttemplate b/tools/dom/templates/html/impl/impl_Document.darttemplate
index fb6d6b18..99b2dc0 100644
--- a/tools/dom/templates/html/impl/impl_Document.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Document.darttemplate
@@ -83,6 +83,8 @@
wrapped = wrap_jso(newElement);
if (wrapped == null) {
wrapped = wrap_jso_custom_element(newElement);
+ } else {
+ wrapped.blink_jsObject['dart_class'] = wrapped;
}
}
@@ -126,6 +128,8 @@
wrapped = wrap_jso(newElement);
if (wrapped == null) {
wrapped = wrap_jso_custom_element(newElement);
+ } else {
+ wrapped.blink_jsObject['dart_class'] = wrapped;
}
}
diff --git a/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate b/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
index 0a0ff4c..6bc60a1 100644
--- a/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
+++ b/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
@@ -377,6 +377,9 @@
}
var elemProto = js.context['Object'].callMethod("create", [baseElement['prototype']]);
+ // Remember for any upgrading done in wrap_jso.
+ _knownCustomeElements[tag] = customElementClass;
+
// TODO(terry): Hack to stop recursion re-creating custom element when the
// created() constructor of the custom element does e.g.,
//
diff --git a/tools/dom/templates/html/impl/impl_MutationObserver.darttemplate b/tools/dom/templates/html/impl/impl_MutationObserver.darttemplate
index 079ca0f..de07dcb 100644
--- a/tools/dom/templates/html/impl/impl_MutationObserver.darttemplate
+++ b/tools/dom/templates/html/impl/impl_MutationObserver.darttemplate
@@ -22,7 +22,7 @@
@DocsEditable()
$if JSINTEROP
static MutationObserver _create(callback) => wrap_jso(_blink.BlinkMutationObserver.instance.constructorCallback_1_((mutations, observer) {
- callback(mutations, wrap_jso(observer));
+ callback(wrap_jso(mutations), wrap_jso(observer));
}));
$else
static MutationObserver _create(callback) => _blink.BlinkMutationObserver.instance.constructorCallback_1_(callback);