Version 1.12.0-dev.3.0
Merge commit '10b7db100ffec216aa09d1d7816f1c59677eb70b' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 164dd2c..bb3f571 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,8 @@
* Added two new file modes, `WRITE_ONLY` and `WRITE_ONLY_APPEND` for
opening a file write only.
[eaeecf2](https://github.com/dart-lang/sdk/commit/eaeecf2ed13ba6c7fbfd653c3c592974a7120960)
+ * Change stdout/stderr to binary mode on Windows.
+ [4205b29](https://github.com/dart-lang/sdk/commit/4205b2997e01f2cea8e2f44c6f46ed6259ab7277)
### Tool changes
@@ -27,6 +29,15 @@
* `pub run` starts up faster for executables that don't import transformed
code.
+ * An issue where HTTP requests were sometimes made even though `--offline` was
+ passed to `pub get` or `pub upgrade` has been fixed.
+
+ * A bug with `--offline` that caused an unhelpful error message has been
+ fixed.
+
+ * A crashing bug involving transformers that only apply to non-public code has
+ been fixed.
+
[package spec proposal]: https://github.com/lrhn/dep-pkgspec
## 1.11.1
diff --git a/DEPS b/DEPS
index ef0d4fa..ee3e737 100644
--- a/DEPS
+++ b/DEPS
@@ -38,7 +38,7 @@
# Revisions of /third_party/* dependencies.
"7zip_rev" : "@19997",
- "analyzer_cli_rev" : "@8bf3516dd645ca289d7ebc641f7c228d5b3d37c4",
+ "analyzer_cli_rev" : "@5069b75f6ccef59b2ba4e2c382bc000037290125",
"args_tag": "@0.13.0",
"async_tag": "@1.2.0",
"barback_rev" : "@29ee90dbcf77cfd64632fa2797a4c8a4f29a4b51",
@@ -49,7 +49,7 @@
"collection_rev": "@1da9a07f32efa2ba0c391b289e2037391e31da0e",
"crypto_rev" : "@2df57a1e26dd88e8d0614207d4b062c73209917d",
"csslib_tag" : "@0.12.0",
- "dartdoc_rev" : "@9f677ec40f9beeb8933374885ef3af4c63d35d25",
+ "dartdoc_tag" : "@v0.0.3",
"dart_services_rev" : "@7aea2574e6f3924bf409a80afb8ad52aa2be4f97",
"dart_style_tag": "@0.1.8+1",
"dev_compiler_rev": "@0.1.1",
@@ -79,12 +79,12 @@
"observe_rev": "@eee2b8ec34236fa46982575fbccff84f61202ac6",
"observatory_pub_packages_rev": "@45565",
"package_config_tag": "@0.1.1",
- "path_rev": "@93b3e2aa1db0ac0c8bab9d341588d77acda60320",
+ "path_tag": "@1.3.6",
"petitparser_rev" : "@37878",
"ply_rev": "@604b32590ffad5cbb82e4afef1d305512d06ae93",
"plugin_tag": "@0.1.0",
"pool_rev": "@e454b4b54d2987e8d2f0fbd3ac519641ada9bd0f",
- "pub_rev": "@e05cfca67574acfdbce55a8422c6bc458be93d10",
+ "pub_rev": "@072c5d85f4741bd4eede3eb8d309669b887e3c54",
"pub_cache_tag": "@v0.0.1+2",
"pub_semver_tag": "@1.2.1",
"quiver_tag": "@0.21.4",
@@ -199,7 +199,7 @@
Var("dart_root") + "/third_party/pkg_tested/dart_style":
(Var("github_mirror") % "dart_style") + Var("dart_style_tag"),
Var("dart_root") + "/third_party/pkg/dartdoc":
- "https://github.com/dart-lang/dartdoc.git" + Var("dartdoc_rev"),
+ "https://github.com/dart-lang/dartdoc.git" + Var("dartdoc_tag"),
Var("dart_root") + "/third_party/pkg/dev_compiler":
"https://github.com/dart-lang/dev_compiler.git" + Var("dev_compiler_rev"),
Var("dart_root") + "/third_party/pkg/glob":
@@ -245,7 +245,7 @@
(Var("github_mirror") % "package_config") +
Var("package_config_tag"),
Var("dart_root") + "/third_party/pkg/path":
- (Var("github_mirror") % "path") + Var("path_rev"),
+ (Var("github_mirror") % "path") + Var("path_tag"),
Var("dart_root") + "/third_party/pkg/plugin":
(Var("github_mirror") % "plugin") + Var("plugin_tag"),
Var("dart_root") + "/third_party/pkg/pool":
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 4353e57..38a28ab 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -555,6 +555,13 @@
always choosing a region that starts at the beginning of a line and
ends at the end of a (possibly different) line in the file.
</p>
+ <p>
+ If a request is made for a file which does not exist, or
+ which is not currently subject to analysis (e.g. because it
+ is not associated with any analysis root specified to
+ analysis.setAnalysisRoots), an error of type
+ <tt>GET_NAVIGATION_INVALID_FILE</tt> will be generated.
+ </p>
<h4>Parameters</h4><dl><dt class="field"><b><i>file ( <a href="#type_FilePath">FilePath</a> )</i></b></dt><dd>
@@ -3161,6 +3168,13 @@
which does not match a file currently subject to
analysis.
</p>
+ </dd><dt class="value">GET_NAVIGATION_INVALID_FILE</dt><dd>
+
+ <p>
+ An "analysis.getErrors" request specified a FilePath
+ which does not match a file currently subject to
+ analysis.
+ </p>
</dd><dt class="value">INVALID_ANALYSIS_ROOT</dt><dd>
<p>
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 6d8be8a..7f135d2 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -25,6 +25,8 @@
import 'package:analysis_server/uri/resolver_provider.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
+import 'package:analyzer/source/package_map_resolver.dart';
+import 'package:analyzer/source/sdk_ext.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -1429,9 +1431,17 @@
SourceFactory _createSourceFactory(UriResolver packageUriResolver) {
UriResolver dartResolver = new DartUriResolver(analysisServer.defaultSdk);
UriResolver resourceResolver = new ResourceUriResolver(resourceProvider);
- List<UriResolver> resolvers = packageUriResolver != null
- ? <UriResolver>[dartResolver, packageUriResolver, resourceResolver]
- : <UriResolver>[dartResolver, resourceResolver];
+ List<UriResolver> resolvers = [];
+ resolvers.add(dartResolver);
+ if (packageUriResolver is PackageMapUriResolver) {
+ UriResolver sdkExtResolver =
+ new SdkExtUriResolver(packageUriResolver.packageMap);
+ resolvers.add(sdkExtResolver);
+ }
+ if (packageUriResolver != null) {
+ resolvers.add(packageUriResolver);
+ }
+ resolvers.add(resourceResolver);
return new SourceFactory(resolvers);
}
}
diff --git a/pkg/analysis_server/lib/src/computer/computer_navigation.dart b/pkg/analysis_server/lib/src/computer/computer_navigation.dart
index 14a47ec..1297379 100644
--- a/pkg/analysis_server/lib/src/computer/computer_navigation.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_navigation.dart
@@ -16,21 +16,17 @@
* A computer for navigation regions in a Dart [CompilationUnit].
*/
class DartUnitNavigationComputer {
- final CompilationUnit _unit;
-
final List<String> files = <String>[];
final Map<String, int> fileMap = new HashMap<String, int>();
final List<protocol.NavigationTarget> targets = <protocol.NavigationTarget>[];
final Map<Element, int> targetMap = new HashMap<Element, int>();
final List<protocol.NavigationRegion> regions = <protocol.NavigationRegion>[];
- DartUnitNavigationComputer(this._unit);
-
/**
* Computes [regions], [targets] and [files].
*/
- void compute() {
- _unit.accept(new _DartUnitNavigationComputerVisitor(this));
+ void compute(AstNode node) {
+ node.accept(new _DartUnitNavigationComputerVisitor(this));
}
int _addFile(String file) {
diff --git a/pkg/analysis_server/lib/src/constants.dart b/pkg/analysis_server/lib/src/constants.dart
index 4f5e232..63dc297 100644
--- a/pkg/analysis_server/lib/src/constants.dart
+++ b/pkg/analysis_server/lib/src/constants.dart
@@ -25,6 +25,7 @@
const String ANALYSIS_GET_HOVER = 'analysis.getHover';
const String ANALYSIS_GET_LIBRARY_DEPENDENCIES =
'analysis.getLibraryDependencies';
+const String ANALYSIS_GET_NAVIGATION = 'analysis.getNavigation';
const String ANALYSIS_REANALYZE = 'analysis.reanalyze';
const String ANALYSIS_SET_ANALYSIS_ROOTS = 'analysis.setAnalysisRoots';
const String ANALYSIS_SET_PRIORITY_FILES = 'analysis.setPriorityFiles';
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index fd32646..c09c511 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -9,6 +9,7 @@
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/computer/computer_hover.dart';
+import 'package:analysis_server/src/computer/computer_navigation.dart';
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol_server.dart';
import 'package:analysis_server/src/services/dependencies/library_dependencies.dart';
@@ -105,6 +106,52 @@
return Response.DELAYED_RESPONSE;
}
+ /**
+ * Implement the `analysis.getNavigation` request.
+ */
+ Response getNavigation(Request request) {
+ var params = new AnalysisGetNavigationParams.fromRequest(request);
+ String file = params.file;
+ int offset = params.offset;
+ Future<AnalysisDoneReason> completionFuture =
+ server.onFileAnalysisComplete(file);
+ if (completionFuture == null) {
+ return new Response.getNavigationInvalidFile(request);
+ }
+ completionFuture.then((AnalysisDoneReason reason) {
+ switch (reason) {
+ case AnalysisDoneReason.COMPLETE:
+ List<CompilationUnit> units =
+ server.getResolvedCompilationUnits(file);
+ if (units.isEmpty) {
+ server.sendResponse(new Response.getNavigationInvalidFile(request));
+ } else {
+ DartUnitNavigationComputer computer =
+ new DartUnitNavigationComputer();
+ for (CompilationUnit unit in units) {
+ AstNode node = new NodeLocator(offset).searchWithin(unit);
+ if (node != null) {
+ computer.compute(node);
+ }
+ }
+ server.sendResponse(new AnalysisGetNavigationResult(
+ computer.files, computer.targets, computer.regions)
+ .toResponse(request.id));
+ }
+ break;
+ case AnalysisDoneReason.CONTEXT_REMOVED:
+ // The active contexts have changed, so try again.
+ Response response = getNavigation(request);
+ if (response != Response.DELAYED_RESPONSE) {
+ server.sendResponse(response);
+ }
+ break;
+ }
+ });
+ // delay response
+ return Response.DELAYED_RESPONSE;
+ }
+
@override
Response handleRequest(Request request) {
try {
@@ -115,6 +162,8 @@
return getHover(request);
} else if (requestName == ANALYSIS_GET_LIBRARY_DEPENDENCIES) {
return getLibraryDependencies(request);
+ } else if (requestName == ANALYSIS_GET_NAVIGATION) {
+ return getNavigation(request);
} else if (requestName == ANALYSIS_REANALYZE) {
return reanalyze(request);
} else if (requestName == ANALYSIS_SET_ANALYSIS_ROOTS) {
diff --git a/pkg/analysis_server/lib/src/generated_protocol.dart b/pkg/analysis_server/lib/src/generated_protocol.dart
index 9a7d1f2..66e92ba 100644
--- a/pkg/analysis_server/lib/src/generated_protocol.dart
+++ b/pkg/analysis_server/lib/src/generated_protocol.dart
@@ -12121,6 +12121,7 @@
* FORMAT_INVALID_FILE
* FORMAT_WITH_ERRORS
* GET_ERRORS_INVALID_FILE
+ * GET_NAVIGATION_INVALID_FILE
* INVALID_ANALYSIS_ROOT
* INVALID_EXECUTION_CONTEXT
* INVALID_OVERLAY_CHANGE
@@ -12164,6 +12165,12 @@
static const GET_ERRORS_INVALID_FILE = const RequestErrorCode._("GET_ERRORS_INVALID_FILE");
/**
+ * An "analysis.getErrors" request specified a FilePath which does not match
+ * a file currently subject to analysis.
+ */
+ static const GET_NAVIGATION_INVALID_FILE = const RequestErrorCode._("GET_NAVIGATION_INVALID_FILE");
+
+ /**
* A path passed as an argument to a request (such as analysis.reanalyze) is
* required to be an analysis root, but isn't.
*/
@@ -12263,7 +12270,7 @@
/**
* A list containing all of the enum values that are defined.
*/
- static const List<RequestErrorCode> VALUES = const <RequestErrorCode>[CONTENT_MODIFIED, FORMAT_INVALID_FILE, FORMAT_WITH_ERRORS, GET_ERRORS_INVALID_FILE, INVALID_ANALYSIS_ROOT, INVALID_EXECUTION_CONTEXT, INVALID_OVERLAY_CHANGE, INVALID_PARAMETER, INVALID_REQUEST, NO_INDEX_GENERATED, REFACTORING_REQUEST_CANCELLED, SERVER_ALREADY_STARTED, SERVER_ERROR, SORT_MEMBERS_INVALID_FILE, SORT_MEMBERS_PARSE_ERRORS, UNANALYZED_PRIORITY_FILES, UNKNOWN_REQUEST, UNKNOWN_SOURCE, UNSUPPORTED_FEATURE];
+ static const List<RequestErrorCode> VALUES = const <RequestErrorCode>[CONTENT_MODIFIED, FORMAT_INVALID_FILE, FORMAT_WITH_ERRORS, GET_ERRORS_INVALID_FILE, GET_NAVIGATION_INVALID_FILE, INVALID_ANALYSIS_ROOT, INVALID_EXECUTION_CONTEXT, INVALID_OVERLAY_CHANGE, INVALID_PARAMETER, INVALID_REQUEST, NO_INDEX_GENERATED, REFACTORING_REQUEST_CANCELLED, SERVER_ALREADY_STARTED, SERVER_ERROR, SORT_MEMBERS_INVALID_FILE, SORT_MEMBERS_PARSE_ERRORS, UNANALYZED_PRIORITY_FILES, UNKNOWN_REQUEST, UNKNOWN_SOURCE, UNSUPPORTED_FEATURE];
final String name;
@@ -12279,6 +12286,8 @@
return FORMAT_WITH_ERRORS;
case "GET_ERRORS_INVALID_FILE":
return GET_ERRORS_INVALID_FILE;
+ case "GET_NAVIGATION_INVALID_FILE":
+ return GET_NAVIGATION_INVALID_FILE;
case "INVALID_ANALYSIS_ROOT":
return INVALID_ANALYSIS_ROOT;
case "INVALID_EXECUTION_CONTEXT":
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index 1e71683..ebe71e7 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -133,8 +133,8 @@
void sendAnalysisNotificationNavigation(
AnalysisServer server, String file, CompilationUnit dartUnit) {
_sendNotification(server, () {
- var computer = new DartUnitNavigationComputer(dartUnit);
- computer.compute();
+ var computer = new DartUnitNavigationComputer();
+ computer.compute(dartUnit);
var params = new protocol.AnalysisNavigationParams(
file, computer.regions, computer.targets, computer.files);
server.sendNotification(params.toNotification());
diff --git a/pkg/analysis_server/lib/src/protocol.dart b/pkg/analysis_server/lib/src/protocol.dart
index 8a15ebe..f633eb8 100644
--- a/pkg/analysis_server/lib/src/protocol.dart
+++ b/pkg/analysis_server/lib/src/protocol.dart
@@ -513,37 +513,6 @@
: _params = params != null ? params : new HashMap<String, Object>();
/**
- * Return a request parsed from the given [data], or `null` if the [data] is
- * not a valid json representation of a request. The [data] is expected to
- * have the following format:
- *
- * {
- * 'clientRequestTime': millisecondsSinceEpoch
- * 'id': String,
- * 'method': methodName,
- * 'params': {
- * paramter_name: value
- * }
- * }
- *
- * where both the parameters and clientRequestTime are optional.
- * The parameters can contain any number of name/value pairs.
- * The clientRequestTime must be an int representing the time at which
- * the client issued the request (milliseconds since epoch).
- */
- factory Request.fromString(String data) {
- try {
- var result = JSON.decode(data);
- if (result is Map) {
- return new Request.fromJson(result);
- }
- return null;
- } catch (exception) {
- return null;
- }
- }
-
- /**
* Return a request parsed from the given json, or `null` if the [data] is
* not a valid json representation of a request. The [data] is expected to
* have the following format:
@@ -581,6 +550,37 @@
}
/**
+ * Return a request parsed from the given [data], or `null` if the [data] is
+ * not a valid json representation of a request. The [data] is expected to
+ * have the following format:
+ *
+ * {
+ * 'clientRequestTime': millisecondsSinceEpoch
+ * 'id': String,
+ * 'method': methodName,
+ * 'params': {
+ * paramter_name: value
+ * }
+ * }
+ *
+ * where both the parameters and clientRequestTime are optional.
+ * The parameters can contain any number of name/value pairs.
+ * The clientRequestTime must be an int representing the time at which
+ * the client issued the request (milliseconds since epoch).
+ */
+ factory Request.fromString(String data) {
+ try {
+ var result = JSON.decode(data);
+ if (result is Map) {
+ return new Request.fromJson(result);
+ }
+ return null;
+ } catch (exception) {
+ return null;
+ }
+ }
+
+ /**
* Return a table representing the structure of the Json object that will be
* sent to the client to represent this response.
*/
@@ -763,6 +763,14 @@
'Error during `analysis.getErrors`: invalid file.'));
/**
+ * Initialize a newly created instance to represent the
+ * GET_NAVIGATION_INVALID_FILE error condition.
+ */
+ Response.getNavigationInvalidFile(Request request) : this(request.id,
+ error: new RequestError(RequestErrorCode.GET_NAVIGATION_INVALID_FILE,
+ 'Error during `analysis.getNavigation`: invalid file.'));
+
+ /**
* Initialize a newly created instance to represent an error condition caused
* by an analysis.reanalyze [request] that specifies an analysis root that is
* not in the current list of analysis roots.
diff --git a/pkg/analysis_server/test/analysis/get_navigation_test.dart b/pkg/analysis_server/test/analysis/get_navigation_test.dart
new file mode 100644
index 0000000..b5c224e
--- /dev/null
+++ b/pkg/analysis_server/test/analysis/get_navigation_test.dart
@@ -0,0 +1,114 @@
+// 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.
+
+library test.analysis.get_navigation;
+
+import 'package:analysis_server/src/domain_analysis.dart';
+import 'package:analysis_server/src/protocol.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:unittest/unittest.dart';
+
+import 'notification_navigation_test.dart';
+
+main() {
+ groupSep = ' | ';
+ defineReflectiveTests(GetNavigationTest);
+}
+
+@reflectiveTest
+class GetNavigationTest extends AbstractNavigationTest {
+ static const String requestId = 'test-getNavigtion';
+
+ @override
+ void setUp() {
+ super.setUp();
+ server.handlers = [new AnalysisDomainHandler(server),];
+ createProject();
+ }
+
+ test_afterAnalysisComplete() async {
+ addTestFile('''
+main() {
+ var test = 0;
+ print(test);
+}
+''');
+ await waitForTasksFinished();
+ await _getNavigation(testFile, testCode.indexOf('test);'), 0);
+ assertHasRegion('test);');
+ assertHasTarget('test = 0');
+ }
+
+ test_beforeAnalysisComplete() async {
+ addTestFile('''
+main() {
+ var test = 0;
+ print(test);
+}
+''');
+ await _getNavigation(testFile, testCode.indexOf('test);'), 0);
+ assertHasRegion('test);');
+ assertHasTarget('test = 0');
+ }
+
+ test_fileDoesNotExist() {
+ String file = '$projectPath/doesNotExist.dart';
+ return _checkInvalid(file, -1, -1);
+ }
+
+ test_fileWithoutContext() {
+ String file = '/outside.dart';
+ addFile(file, '''
+main() {
+ print(42);
+}
+''');
+ return _checkInvalid(file, -1, -1);
+ }
+
+ test_removeContextAfterRequest() async {
+ addTestFile('''
+main() {
+ var test = 0;
+ print(test);
+}
+''');
+ // handle the request synchronously
+ Request request =
+ _createGetNavigationRequest(testFile, testCode.indexOf('test);'), 0);
+ server.handleRequest(request);
+ // remove context, causes sending an "invalid file" error
+ {
+ Folder projectFolder = resourceProvider.getResource(projectPath);
+ server.contextDirectoryManager.removeContext(projectFolder);
+ }
+ // wait for an error response
+ Response response = await serverChannel.waitForResponse(request);
+ expect(response.error, isNotNull);
+ expect(response.error.code, RequestErrorCode.GET_NAVIGATION_INVALID_FILE);
+ }
+
+ _checkInvalid(String file, int offset, int length) async {
+ Request request = _createGetNavigationRequest(file, offset, length);
+ Response response = await serverChannel.sendRequest(request);
+ expect(response.error, isNotNull);
+ expect(response.error.code, RequestErrorCode.GET_NAVIGATION_INVALID_FILE);
+ }
+
+ Request _createGetNavigationRequest(String file, int offset, int length) {
+ return new AnalysisGetNavigationParams(file, offset, length)
+ .toRequest(requestId);
+ }
+
+ _getNavigation(String file, int offset, int length) async {
+ Request request = _createGetNavigationRequest(file, offset, length);
+ Response response = await serverChannel.sendRequest(request);
+ AnalysisGetNavigationResult result =
+ new AnalysisGetNavigationResult.fromResponse(response);
+ targetFiles = result.files;
+ targets = result.targets;
+ regions = result.regions;
+ }
+}
diff --git a/pkg/analysis_server/test/analysis/notification_navigation_test.dart b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
index 16d1bcd..13d54cd 100644
--- a/pkg/analysis_server/test/analysis/notification_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
@@ -19,154 +19,7 @@
}
@reflectiveTest
-class AnalysisNotificationNavigationTest extends AbstractAnalysisTest {
- List<NavigationRegion> regions;
- List<NavigationTarget> targets;
- List<String> targetFiles;
-
- NavigationRegion testRegion;
- List<int> testTargetIndexes;
- NavigationTarget testTarget;
-
- /**
- * Validates that there is a target in [testTargetIndexes] with [file],
- * at [offset] and with the given [length].
- */
- void assertHasFileTarget(String file, int offset, int length) {
- List<NavigationTarget> testTargets =
- testTargetIndexes.map((int index) => targets[index]).toList();
- for (NavigationTarget target in testTargets) {
- if (targetFiles[target.fileIndex] == file &&
- target.offset == offset &&
- target.length == length) {
- testTarget = target;
- return;
- }
- }
- fail(
- 'Expected to find target (file=$file; offset=$offset; length=$length) in\n'
- '${testRegion} in\n' '${testTargets.join('\n')}');
- }
-
- void assertHasOperatorRegion(String regionSearch, int regionLength,
- String targetSearch, int targetLength) {
- assertHasRegion(regionSearch, regionLength);
- assertHasTarget(targetSearch, targetLength);
- }
-
- /**
- * Validates that there is a region at the offset of [search] in [testFile].
- * If [length] is not specified explicitly, then length of an identifier
- * from [search] is used.
- */
- void assertHasRegion(String search, [int length = -1]) {
- int offset = findOffset(search);
- if (length == -1) {
- length = findIdentifierLength(search);
- }
- findRegion(offset, length, true);
- }
-
- /**
- * Validates that there is a region at the offset of [search] in [testFile]
- * with the given [length] or the length of [search].
- */
- void assertHasRegionString(String search, [int length = -1]) {
- int offset = findOffset(search);
- if (length == -1) {
- length = search.length;
- }
- findRegion(offset, length, true);
- }
-
- /**
- * Validates that there is an identifier region at [regionSearch] with target
- * at [targetSearch].
- */
- void assertHasRegionTarget(String regionSearch, String targetSearch) {
- assertHasRegion(regionSearch);
- assertHasTarget(targetSearch);
- }
-
- /**
- * Validates that there is a target in [testTargets] with [testFile], at the
- * offset of [search] in [testFile], and with the given [length] or the length
- * of an leading identifier in [search].
- */
- void assertHasTarget(String search, [int length = -1]) {
- int offset = findOffset(search);
- if (length == -1) {
- length = findIdentifierLength(search);
- }
- assertHasFileTarget(testFile, offset, length);
- }
-
- /**
- * Validates that there is no a region at [search] and with the given
- * [length].
- */
- void assertNoRegion(String search, int length) {
- int offset = findOffset(search);
- findRegion(offset, length, false);
- }
-
- /**
- * Validates that there is no a region at [search] with any length.
- */
- void assertNoRegionAt(String search) {
- int offset = findOffset(search);
- findRegion(offset, -1, false);
- }
-
- /**
- * Validates that there is no a region for [search] string.
- */
- void assertNoRegionString(String search) {
- int offset = findOffset(search);
- int length = search.length;
- findRegion(offset, length, false);
- }
-
- void assertRegionsSorted() {
- int lastEnd = -1;
- for (NavigationRegion region in regions) {
- int offset = region.offset;
- if (offset < lastEnd) {
- fail('$lastEnd was expected to be > $offset in\n' + regions.join('\n'));
- }
- lastEnd = offset + region.length;
- }
- }
-
- /**
- * Finds the navigation region with the given [offset] and [length].
- * If [length] is `-1`, then it is ignored.
- *
- * If [exists] is `true`, then fails if such region does not exist.
- * Otherwise remembers this it into [testRegion].
- * Also fills [testTargets] with its targets.
- *
- * If [exists] is `false`, then fails if such region exists.
- */
- void findRegion(int offset, int length, bool exists) {
- for (NavigationRegion region in regions) {
- if (region.offset == offset &&
- (length == -1 || region.length == length)) {
- if (exists == false) {
- fail('Not expected to find (offset=$offset; length=$length) in\n'
- '${regions.join('\n')}');
- }
- testRegion = region;
- testTargetIndexes = region.targets;
- return;
- }
- }
- if (exists == true) {
- fail('Expected to find (offset=$offset; length=$length) in\n'
- '${regions.join('\n')}');
- }
- }
-
+class AnalysisNotificationNavigationTest extends AbstractNavigationTest {
Future prepareNavigation() {
addAnalysisSubscription(AnalysisService.NAVIGATION, testFile);
return waitForTasksFinished().then((_) {
@@ -785,3 +638,152 @@
});
}
}
+
+class AbstractNavigationTest extends AbstractAnalysisTest {
+ List<NavigationRegion> regions;
+ List<NavigationTarget> targets;
+ List<String> targetFiles;
+
+ NavigationRegion testRegion;
+ List<int> testTargetIndexes;
+ NavigationTarget testTarget;
+
+ /**
+ * Validates that there is a target in [testTargetIndexes] with [file],
+ * at [offset] and with the given [length].
+ */
+ void assertHasFileTarget(String file, int offset, int length) {
+ List<NavigationTarget> testTargets =
+ testTargetIndexes.map((int index) => targets[index]).toList();
+ for (NavigationTarget target in testTargets) {
+ if (targetFiles[target.fileIndex] == file &&
+ target.offset == offset &&
+ target.length == length) {
+ testTarget = target;
+ return;
+ }
+ }
+ fail(
+ 'Expected to find target (file=$file; offset=$offset; length=$length) in\n'
+ '${testRegion} in\n' '${testTargets.join('\n')}');
+ }
+
+ void assertHasOperatorRegion(String regionSearch, int regionLength,
+ String targetSearch, int targetLength) {
+ assertHasRegion(regionSearch, regionLength);
+ assertHasTarget(targetSearch, targetLength);
+ }
+
+ /**
+ * Validates that there is a region at the offset of [search] in [testFile].
+ * If [length] is not specified explicitly, then length of an identifier
+ * from [search] is used.
+ */
+ void assertHasRegion(String search, [int length = -1]) {
+ int offset = findOffset(search);
+ if (length == -1) {
+ length = findIdentifierLength(search);
+ }
+ findRegion(offset, length, true);
+ }
+
+ /**
+ * Validates that there is a region at the offset of [search] in [testFile]
+ * with the given [length] or the length of [search].
+ */
+ void assertHasRegionString(String search, [int length = -1]) {
+ int offset = findOffset(search);
+ if (length == -1) {
+ length = search.length;
+ }
+ findRegion(offset, length, true);
+ }
+
+ /**
+ * Validates that there is an identifier region at [regionSearch] with target
+ * at [targetSearch].
+ */
+ void assertHasRegionTarget(String regionSearch, String targetSearch) {
+ assertHasRegion(regionSearch);
+ assertHasTarget(targetSearch);
+ }
+
+ /**
+ * Validates that there is a target in [testTargets] with [testFile], at the
+ * offset of [search] in [testFile], and with the given [length] or the length
+ * of an leading identifier in [search].
+ */
+ void assertHasTarget(String search, [int length = -1]) {
+ int offset = findOffset(search);
+ if (length == -1) {
+ length = findIdentifierLength(search);
+ }
+ assertHasFileTarget(testFile, offset, length);
+ }
+
+ /**
+ * Validates that there is no a region at [search] and with the given
+ * [length].
+ */
+ void assertNoRegion(String search, int length) {
+ int offset = findOffset(search);
+ findRegion(offset, length, false);
+ }
+
+ /**
+ * Validates that there is no a region at [search] with any length.
+ */
+ void assertNoRegionAt(String search) {
+ int offset = findOffset(search);
+ findRegion(offset, -1, false);
+ }
+
+ /**
+ * Validates that there is no a region for [search] string.
+ */
+ void assertNoRegionString(String search) {
+ int offset = findOffset(search);
+ int length = search.length;
+ findRegion(offset, length, false);
+ }
+
+ void assertRegionsSorted() {
+ int lastEnd = -1;
+ for (NavigationRegion region in regions) {
+ int offset = region.offset;
+ if (offset < lastEnd) {
+ fail('$lastEnd was expected to be > $offset in\n' + regions.join('\n'));
+ }
+ lastEnd = offset + region.length;
+ }
+ }
+
+ /**
+ * Finds the navigation region with the given [offset] and [length].
+ * If [length] is `-1`, then it is ignored.
+ *
+ * If [exists] is `true`, then fails if such region does not exist.
+ * Otherwise remembers this it into [testRegion].
+ * Also fills [testTargets] with its targets.
+ *
+ * If [exists] is `false`, then fails if such region exists.
+ */
+ void findRegion(int offset, int length, bool exists) {
+ for (NavigationRegion region in regions) {
+ if (region.offset == offset &&
+ (length == -1 || region.length == length)) {
+ if (exists == false) {
+ fail('Not expected to find (offset=$offset; length=$length) in\n'
+ '${regions.join('\n')}');
+ }
+ testRegion = region;
+ testTargetIndexes = region.targets;
+ return;
+ }
+ }
+ if (exists == true) {
+ fail('Expected to find (offset=$offset; length=$length) in\n'
+ '${regions.join('\n')}');
+ }
+ }
+}
diff --git a/pkg/analysis_server/test/analysis/test_all.dart b/pkg/analysis_server/test/analysis/test_all.dart
index e9867c2..b28a687 100644
--- a/pkg/analysis_server/test/analysis/test_all.dart
+++ b/pkg/analysis_server/test/analysis/test_all.dart
@@ -7,6 +7,7 @@
import 'get_errors_test.dart' as get_errors_test;
import 'get_hover_test.dart' as get_hover_test;
+import 'get_navigation_test.dart' as get_navigation_test;
import 'notification_errors_test.dart' as notification_errors_test;
import 'notification_highlights_test.dart' as notification_highlights_test;
import 'notification_navigation_test.dart' as notification_navigation_test;
@@ -23,6 +24,7 @@
group('search', () {
get_errors_test.main();
get_hover_test.main();
+ get_navigation_test.main();
notification_errors_test.main();
notification_highlights_test.main();
notification_navigation_test.main();
diff --git a/pkg/analysis_server/test/integration/integration_test_methods.dart b/pkg/analysis_server/test/integration/integration_test_methods.dart
index 3b609f2..5794acb 100644
--- a/pkg/analysis_server/test/integration/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/integration_test_methods.dart
@@ -277,6 +277,11 @@
* region that starts at the beginning of a line and ends at the end of a
* (possibly different) line in the file.
*
+ * If a request is made for a file which does not exist, or which is not
+ * currently subject to analysis (e.g. because it is not associated with any
+ * analysis root specified to analysis.setAnalysisRoots), an error of type
+ * GET_NAVIGATION_INVALID_FILE will be generated.
+ *
* Parameters
*
* file ( FilePath )
diff --git a/pkg/analysis_server/test/integration/protocol_matchers.dart b/pkg/analysis_server/test/integration/protocol_matchers.dart
index 60515ea..fbb40a8 100644
--- a/pkg/analysis_server/test/integration/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/protocol_matchers.dart
@@ -1829,6 +1829,7 @@
* FORMAT_INVALID_FILE
* FORMAT_WITH_ERRORS
* GET_ERRORS_INVALID_FILE
+ * GET_NAVIGATION_INVALID_FILE
* INVALID_ANALYSIS_ROOT
* INVALID_EXECUTION_CONTEXT
* INVALID_OVERLAY_CHANGE
@@ -1851,6 +1852,7 @@
"FORMAT_INVALID_FILE",
"FORMAT_WITH_ERRORS",
"GET_ERRORS_INVALID_FILE",
+ "GET_NAVIGATION_INVALID_FILE",
"INVALID_ANALYSIS_ROOT",
"INVALID_EXECUTION_CONTEXT",
"INVALID_OVERLAY_CHANGE",
diff --git a/pkg/analysis_server/test/services/refactoring/extract_method_test.dart b/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
index 5e376f3..d33a930 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
@@ -1804,7 +1804,7 @@
var a = res(v1, v2); // marker
}
-num res(int v1, int v2) => v1 + v2 + v1;
+int res(int v1, int v2) => v1 + v2 + v1;
''');
}
diff --git a/pkg/analysis_server/tool/spec/api.dart b/pkg/analysis_server/tool/spec/api.dart
index 6f47644..a558f17 100644
--- a/pkg/analysis_server/tool/spec/api.dart
+++ b/pkg/analysis_server/tool/spec/api.dart
@@ -176,7 +176,7 @@
}
/**
- * Description of a request method.
+ * Description of a notification method.
*/
class Notification extends ApiNode {
/**
@@ -429,7 +429,7 @@
final bool optional;
/**
- * Value which the field is required to contain, or null if it may vary.
+ * Value that the field is required to contain, or null if it may vary.
*/
final Object value;
diff --git a/pkg/analysis_server/tool/spec/codegen_tools.dart b/pkg/analysis_server/tool/spec/codegen_tools.dart
index 0d7e95f..f388379 100644
--- a/pkg/analysis_server/tool/spec/codegen_tools.dart
+++ b/pkg/analysis_server/tool/spec/codegen_tools.dart
@@ -85,8 +85,8 @@
/**
* Generate a doc comment based on the HTML in [docs].
*
- * If [javadocStyle] is true, then the output is compatable with Javadoc,
- * which understands certain HTML constructs.
+ * When generating java code, the output is compatible with Javadoc, which
+ * understands certain HTML constructs.
*/
void docComment(List<dom.Node> docs) {
if (containsOnlyWhitespace(docs)) {
@@ -251,7 +251,7 @@
/**
* Class representing a single output directory (either generated code or
- * generated HTML). No other content should exisit in the directory.
+ * generated HTML). No other content should exist in the directory.
*/
class GeneratedDirectory extends GeneratedContent {
@@ -261,7 +261,7 @@
final String outputDirPath;
/**
- * Callback function which computes the directory contents.
+ * Callback function that computes the directory contents.
*/
final DirectoryContentsComputer directoryContentsComputer;
diff --git a/pkg/analysis_server/tool/spec/from_html.dart b/pkg/analysis_server/tool/spec/from_html.dart
index 938aacc..72c1ee2 100644
--- a/pkg/analysis_server/tool/spec/from_html.dart
+++ b/pkg/analysis_server/tool/spec/from_html.dart
@@ -303,7 +303,7 @@
if (elementProcessors.containsKey(node.localName)) {
elementProcessors[node.localName](node);
} else if (specialElements.contains(node.localName)) {
- throw new Exception('$context: Unexpected use of <${node.localName}');
+ throw new Exception('$context: Unexpected use of <${node.localName}>');
} else {
recurse(node, context, elementProcessors);
}
diff --git a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
index dff7552..c6debb7 100644
--- a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
+++ b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
@@ -105,6 +105,10 @@
* choosing a region that starts at the beginning of a line and ends at the end of a (possibly
* different) line in the file.
*
+ * If a request is made for a file which does not exist, or which is not currently subject to
+ * analysis (e.g. because it is not associated with any analysis root specified to
+ * analysis.setAnalysisRoots), an error of type GET_NAVIGATION_INVALID_FILE will be generated.
+ *
* @param file The file in which navigation information is being requested.
* @param offset The offset of the region for which navigation information is being requested.
* @param length The length of the region for which navigation information is being requested.
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
index d86609d..8e39aff 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
@@ -47,6 +47,12 @@
public static final String GET_ERRORS_INVALID_FILE = "GET_ERRORS_INVALID_FILE";
/**
+ * An "analysis.getErrors" request specified a FilePath which does not match a file currently
+ * subject to analysis.
+ */
+ public static final String GET_NAVIGATION_INVALID_FILE = "GET_NAVIGATION_INVALID_FILE";
+
+ /**
* A path passed as an argument to a request (such as analysis.reanalyze) is required to be an
* analysis root, but isn't.
*/
diff --git a/pkg/analysis_server/tool/spec/html_tools.dart b/pkg/analysis_server/tool/spec/html_tools.dart
index 419fe63..d46419f 100644
--- a/pkg/analysis_server/tool/spec/html_tools.dart
+++ b/pkg/analysis_server/tool/spec/html_tools.dart
@@ -96,8 +96,8 @@
/**
* Execute [callback], collecting any code that is output using [write],
- * [writeln], [add], or [addAll], and return the result as a list of HTML
- * nodes.
+ * [writeln], [add], [addAll] or [element], and return the result as a list
+ * of HTML nodes.
*/
List<dom.Node> collectHtml(void callback()) {
List<dom.Node> oldHtml = _html;
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index b2e68fc..b88c8ac 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -441,6 +441,13 @@
always choosing a region that starts at the beginning of a line and
ends at the end of a (possibly different) line in the file.
</p>
+ <p>
+ If a request is made for a file which does not exist, or
+ which is not currently subject to analysis (e.g. because it
+ is not associated with any analysis root specified to
+ analysis.setAnalysisRoots), an error of type
+ <tt>GET_NAVIGATION_INVALID_FILE</tt> will be generated.
+ </p>
<params>
<field name="file">
<ref>FilePath</ref>
@@ -3161,6 +3168,14 @@
</p>
</value>
<value>
+ <code>GET_NAVIGATION_INVALID_FILE</code>
+ <p>
+ An "analysis.getErrors" request specified a FilePath
+ which does not match a file currently subject to
+ analysis.
+ </p>
+ </value>
+ <value>
<code>INVALID_ANALYSIS_ROOT</code>
<p>
A path passed as an argument to a request (such as
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 7cbf18f..6e22891 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,16 @@
+## 0.25.2-alpha.1
+
+* `dart:sdk` extension `.sdkext` changed to `_sdkext` (to play nicer with pub).
+
+## 0.25.2-alpha.0
+
+* Initial support for analyzing `dart:sdk` extensions from `.sdkext`.
+
+## 0.25.1
+
+* (Internal) code reorganization to address analysis warnings due to SDK reorg.
+* First steps towards `.packages` support.
+
## 0.25.0
* Commandline interface moved to dedicated `analyzer_cli` package. Files moved:
diff --git a/pkg/analyzer/lib/source/sdk_ext.dart b/pkg/analyzer/lib/source/sdk_ext.dart
new file mode 100644
index 0000000..696e181
--- /dev/null
+++ b/pkg/analyzer/lib/source/sdk_ext.dart
@@ -0,0 +1,176 @@
+// 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 source.sdk_ext;
+
+import 'dart:convert';
+import 'dart:core' hide Resource;
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/generated/java_io.dart' show JavaFile;
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart' show FileBasedSource;
+import 'package:path/path.dart' as pathos;
+
+/// Given a packageMap (see [PackageMapProvider]), check in each package's lib
+/// directory for the existence of a `_sdkext` file. This file must contain a
+/// JSON encoded map. Each key in the map is a `dart:` library name. Each value
+/// is a path (relative to the directory containing `_sdkext`) to a dart script
+/// for the given library. For example:
+/// {
+/// "dart:sky": "../sdk_ext/dart_sky.dart"
+/// }
+///
+/// If a key doesn't begin with `dart:` it is ignored.
+class SdkExtUriResolver extends UriResolver {
+ static const String SDK_EXT_NAME = '_sdkext';
+ static const String DART_COLON_PREFIX = 'dart:';
+
+ final Map<String, String> _urlMappings = <String,String>{};
+
+ /// Construct a [SdkExtUriResolver] from a package map
+ /// (see [PackageMapProvider]).
+ SdkExtUriResolver(Map<String, List<Folder>> packageMap) {
+ if (packageMap == null) {
+ return;
+ }
+ packageMap.forEach(_processPackage);
+ }
+
+ /// Number of sdk extensions.
+ int get length => _urlMappings.length;
+
+ /// Return the path mapping for [libName] or null if there is none.
+ String operator[](String libName) => _urlMappings[libName];
+
+ /// Programmatically add a new SDK extension given a JSON description
+ /// ([sdkExtJSON]) and a lib directory ([libDir]).
+ void addSdkExt(String sdkExtJSON, Folder libDir) {
+ _processSdkExt(sdkExtJSON, libDir);
+ }
+
+ @override
+ Source resolveAbsolute(Uri importUri) {
+ String libraryName = _libraryName(importUri);
+ String partPath = _partPath(importUri);
+ // Lookup library name in mappings.
+ String mapping = _urlMappings[libraryName];
+ if (mapping == null) {
+ // Not found.
+ return null;
+ }
+ // This mapping points to the main entry file of the sdk extension.
+ Uri libraryEntry = new Uri.file(mapping);
+ if (!libraryEntry.isAbsolute) {
+ // We expect an absolute path.
+ return null;
+ }
+
+ if (partPath != null) {
+ return _resolvePart(libraryEntry, partPath, importUri);
+ } else {
+ return _resolveEntry(libraryEntry, importUri);
+ }
+ }
+
+ @override
+ Uri restoreAbsolute(Source source) {
+ String libraryName = _libraryName(source.uri);
+ if (_registeredSdkExtension(libraryName)) {
+ return source.uri;
+ }
+ return null;
+ }
+
+ /// Return the library name of [importUri].
+ String _libraryName(Uri importUri) {
+ var uri = importUri.toString();
+ int index = uri.indexOf('/');
+ if (index >= 0) {
+ return uri.substring(0, index);
+ }
+ return uri;
+ }
+
+ /// Return the part path of [importUri].
+ String _partPath(Uri importUri) {
+ var uri = importUri.toString();
+ int index = uri.indexOf('/');
+ if (index >= 0) {
+ return uri.substring(index + 1);
+ }
+ return null;
+ }
+
+ /// Given a package [name] and a list of folders ([libDirs]),
+ /// add any found sdk extensions.
+ void _processPackage(String name, List<Folder> libDirs) {
+ for (var libDir in libDirs) {
+ var sdkExt = _readDotSdkExt(libDir);
+ if (sdkExt != null) {
+ _processSdkExt(sdkExt, libDir);
+ }
+ }
+ }
+
+ /// Given the JSON for an SDK extension ([sdkExtJSON]) and a folder
+ /// ([libDir]), setup the uri mapping.
+ void _processSdkExt(String sdkExtJSON, Folder libDir) {
+ var sdkExt;
+ try {
+ sdkExt = JSON.decode(sdkExtJSON);
+ } catch (e) {
+ return;
+ }
+ if ((sdkExt == null) || (sdkExt is! Map)) {
+ return;
+ }
+ sdkExt.forEach((k, v) => _processSdkExtension(k, v, libDir));
+ }
+
+ /// Install the mapping from [name] to [libDir]/[file].
+ void _processSdkExtension(String name, String file, Folder libDir) {
+ if (!name.startsWith(DART_COLON_PREFIX)) {
+ // SDK extensions must begin with 'dart:'.
+ return;
+ }
+ var key = name;
+ var value = libDir.canonicalizePath(file);
+ _urlMappings[key] = value;
+ }
+
+ /// Read the contents of [libDir]/[SDK_EXT_NAME] as a string.
+ /// Returns null if the file doesn't exist.
+ String _readDotSdkExt(Folder libDir) {
+ var file = libDir.getChild(SDK_EXT_NAME);
+ try {
+ return file.readAsStringSync();
+ } on FileSystemException {
+ // File can't be read.
+ return null;
+ }
+ }
+
+ /// Returns true if [libraryName] is a registered sdk extension.
+ bool _registeredSdkExtension(String libraryName) {
+ return _urlMappings[libraryName] != null;
+ }
+
+ /// Resolve an import of an sdk extension.
+ Source _resolveEntry(Uri libraryEntry, Uri importUri) {
+ // Library entry.
+ JavaFile javaFile = new JavaFile.fromUri(libraryEntry);
+ return new FileBasedSource(javaFile, importUri);
+ }
+
+ /// Resolve a 'part' statement inside an sdk extension.
+ Source _resolvePart(Uri libraryEntry, String partPath, Uri importUri) {
+ // Library part.
+ var directory = pathos.dirname(libraryEntry.path);
+ var partUri = new Uri.file(pathos.join(directory, partPath));
+ assert(partUri.isAbsolute);
+ JavaFile javaFile = new JavaFile.fromUri(partUri);
+ return new FileBasedSource(javaFile, importUri);
+ }
+}
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index 24344aa..395dc27 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -3593,6 +3593,12 @@
* Return the type of function defined by this executable element.
*/
FunctionType get type;
+
+ /**
+ * Return a list containing all of the type parameters defined for this
+ * executable element.
+ */
+ List<TypeParameterElement> get typeParameters;
}
/**
@@ -3630,6 +3636,12 @@
List<ParameterElement> _parameters = ParameterElement.EMPTY_LIST;
/**
+ * A list containing all of the type parameters defined for this executable
+ * element.
+ */
+ List<TypeParameterElement> _typeParameters = TypeParameterElement.EMPTY_LIST;
+
+ /**
* The return type defined by this executable element.
*/
DartType returnType;
@@ -3746,8 +3758,33 @@
}
@override
+ List<TypeParameterElement> get typeParameters => _typeParameters;
+
+ /**
+ * Set the type parameters defined by this executable element to the given
+ * [typeParameters].
+ */
+ void set typeParameters(List<TypeParameterElement> typeParameters) {
+ for (TypeParameterElement parameter in typeParameters) {
+ (parameter as TypeParameterElementImpl).enclosingElement = this;
+ }
+ this._typeParameters = typeParameters;
+ }
+
+ @override
void appendTo(StringBuffer buffer) {
if (this.kind != ElementKind.GETTER) {
+ int typeParameterCount = _typeParameters.length;
+ if (typeParameterCount > 0) {
+ buffer.write('<');
+ for (int i = 0; i < typeParameterCount; i++) {
+ if (i > 0) {
+ buffer.write(", ");
+ }
+ (_typeParameters[i] as TypeParameterElementImpl).appendTo(buffer);
+ }
+ buffer.write('>');
+ }
buffer.write("(");
String closing = null;
ParameterKind kind = ParameterKind.REQUIRED;
@@ -3903,6 +3940,9 @@
FunctionType get type => substituteFor(baseElement.type);
@override
+ List<TypeParameterElement> get typeParameters => baseElement.typeParameters;
+
+ @override
void visitChildren(ElementVisitor visitor) {
// TODO(brianwilkerson) We need to finish implementing the accessors used
// below so that we can safely invoke them.
@@ -8604,6 +8644,13 @@
*/
List<ParameterElement> get parameters;
+ /**
+ * Return a list containing all of the type parameters defined by this
+ * parameter. A parameter will only define other parameters if it is a
+ * function typed parameter.
+ */
+ List<TypeParameterElement> get typeParameters;
+
@override
FormalParameter computeNode();
}
@@ -8627,6 +8674,13 @@
List<ParameterElement> _parameters = ParameterElement.EMPTY_LIST;
/**
+ * A list containing all of the type parameters defined for this parameter
+ * element. There will only be parameters if this parameter is a function
+ * typed parameter.
+ */
+ List<TypeParameterElement> _typeParameters = TypeParameterElement.EMPTY_LIST;
+
+ /**
* The kind of this parameter.
*/
ParameterKind parameterKind;
@@ -8697,6 +8751,20 @@
}
@override
+ List<TypeParameterElement> get typeParameters => _typeParameters;
+
+ /**
+ * Set the type parameters defined by this parameter element to the given
+ * [typeParameters].
+ */
+ void set typeParameters(List<TypeParameterElement> typeParameters) {
+ for (TypeParameterElement parameter in typeParameters) {
+ (parameter as TypeParameterElementImpl).enclosingElement = this;
+ }
+ this._typeParameters = typeParameters;
+ }
+
+ @override
SourceRange get visibleRange {
if (_visibleRangeLength < 0) {
return null;
@@ -8852,6 +8920,9 @@
}
@override
+ List<TypeParameterElement> get typeParameters => baseElement.typeParameters;
+
+ @override
SourceRange get visibleRange => baseElement.visibleRange;
@override
diff --git a/pkg/analyzer/lib/src/generated/element_handle.dart b/pkg/analyzer/lib/src/generated/element_handle.dart
index 1cba143..e5921d6 100644
--- a/pkg/analyzer/lib/src/generated/element_handle.dart
+++ b/pkg/analyzer/lib/src/generated/element_handle.dart
@@ -549,6 +549,9 @@
@override
FunctionType get type => actualElement.type;
+
+ @override
+ List<TypeParameterElement> get typeParameters => actualElement.typeParameters;
}
/**
@@ -919,6 +922,9 @@
List<ParameterElement> get parameters => actualElement.parameters;
@override
+ List<TypeParameterElement> get typeParameters => actualElement.typeParameters;
+
+ @override
SourceRange get visibleRange => actualElement.visibleRange;
}
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 33f470f..c4bc15a 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -10,7 +10,6 @@
import 'package:analyzer/src/context/cache.dart'
show CacheEntry, TargetedResult;
import 'package:analyzer/src/generated/constant.dart';
-import 'package:analyzer/src/services/lint.dart';
import 'package:analyzer/src/task/dart.dart'
show
HINTS,
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index c01e769..49fc6c7 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -2672,7 +2672,9 @@
//
ElementHolder holder = new ElementHolder();
_visitChildren(holder, node);
- (node.element as ParameterElementImpl).parameters = holder.parameters;
+ ParameterElementImpl element = node.element;
+ element.parameters = holder.parameters;
+ element.typeParameters = holder.typeParameters;
holder.validate();
return null;
}
@@ -2702,6 +2704,7 @@
element.labels = holder.labels;
element.localVariables = holder.localVariables;
element.parameters = holder.parameters;
+ element.typeParameters = holder.typeParameters;
if (body.isAsynchronous) {
element.asynchronous = true;
}
@@ -2809,6 +2812,7 @@
element.labels = holder.labels;
element.localVariables = holder.localVariables;
element.parameters = holder.parameters;
+ element.typeParameters = holder.typeParameters;
if (body.isAsynchronous) {
element.asynchronous = true;
}
@@ -2871,7 +2875,9 @@
//
ElementHolder holder = new ElementHolder();
_visitChildren(holder, node);
- (node.element as ParameterElementImpl).parameters = holder.parameters;
+ ParameterElementImpl element = node.element;
+ element.parameters = holder.parameters;
+ element.typeParameters = holder.typeParameters;
holder.validate();
return null;
}
@@ -2921,6 +2927,7 @@
element.localVariables = holder.localVariables;
element.parameters = holder.parameters;
element.static = isStatic;
+ element.typeParameters = holder.typeParameters;
if (body.isAsynchronous) {
element.asynchronous = true;
}
@@ -4295,28 +4302,35 @@
}
/**
- * Instances of the class `FunctionScope` implement the scope defined by a function.
+ * The scope defined by a function.
*/
class FunctionScope extends EnclosedScope {
+ /**
+ * The element representing the function that defines this scope.
+ */
final ExecutableElement _functionElement;
+ /**
+ * A flag indicating whether the parameters have already been defined, used to
+ * prevent the parameters from being defined multiple times.
+ */
bool _parametersDefined = false;
/**
- * Initialize a newly created scope enclosed within another scope.
- *
- * @param enclosingScope the scope in which this scope is lexically enclosed
- * @param functionElement the element representing the type represented by this scope
+ * Initialize a newly created scope enclosed within the [enclosingScope] that
+ * represents the given [_functionElement].
*/
FunctionScope(Scope enclosingScope, this._functionElement)
- : super(new EnclosedScope(enclosingScope)) {
+ : super(new EnclosedScope(new EnclosedScope(enclosingScope))) {
if (_functionElement == null) {
throw new IllegalArgumentException("function element cannot be null");
}
+ _defineTypeParameters();
}
/**
- * Define the parameters for the given function in the scope that encloses this function.
+ * Define the parameters for the given function in the scope that encloses
+ * this function.
*/
void defineParameters() {
if (_parametersDefined) {
@@ -4330,11 +4344,21 @@
}
}
}
+
+ /**
+ * Define the type parameters for the function.
+ */
+ void _defineTypeParameters() {
+ Scope typeParameterScope = enclosingScope.enclosingScope;
+ for (TypeParameterElement typeParameter
+ in _functionElement.typeParameters) {
+ typeParameterScope.define(typeParameter);
+ }
+ }
}
/**
- * Instances of the class `FunctionTypeScope` implement the scope defined by a function type
- * alias.
+ * The scope defined by a function type alias.
*/
class FunctionTypeScope extends EnclosedScope {
final FunctionTypeAliasElement _typeElement;
@@ -4342,10 +4366,8 @@
bool _parametersDefined = false;
/**
- * Initialize a newly created scope enclosed within another scope.
- *
- * @param enclosingScope the scope in which this scope is lexically enclosed
- * @param typeElement the element representing the type alias represented by this scope
+ * Initialize a newly created scope enclosed within the [enclosingScope] that
+ * represents the given [_typeElement].
*/
FunctionTypeScope(Scope enclosingScope, this._typeElement)
: super(new EnclosedScope(enclosingScope)) {
@@ -4354,8 +4376,6 @@
/**
* Define the parameters for the function type alias.
- *
- * @param typeElement the element representing the type represented by this scope
*/
void defineParameters() {
if (_parametersDefined) {
@@ -4369,8 +4389,6 @@
/**
* Define the type parameters for the function type alias.
- *
- * @param typeElement the element representing the type represented by this scope
*/
void _defineTypeParameters() {
Scope typeParameterScope = enclosingScope;
@@ -12080,6 +12098,29 @@
}
@override
+ Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
+ Scope outerScope = nameScope;
+ try {
+ ParameterElement parameterElement = node.element;
+ if (parameterElement == null) {
+ AnalysisEngine.instance.logger.logInformation(
+ "Missing element for function typed formal parameter ${node.identifier.name} in ${definingLibrary.source.fullName}",
+ new CaughtException(new AnalysisException(), null));
+ } else {
+ nameScope = new EnclosedScope(nameScope);
+ for (TypeParameterElement typeParameter
+ in parameterElement.typeParameters) {
+ nameScope.define(typeParameter);
+ }
+ }
+ super.visitFunctionTypedFormalParameter(node);
+ } finally {
+ nameScope = outerScope;
+ }
+ return null;
+ }
+
+ @override
Object visitIfStatement(IfStatement node) {
safelyVisit(node.condition);
visitStatementInScope(node.thenStatement);
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 75c175a..5b96dbd 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -818,10 +818,11 @@
if (_packages != null && containedUri.scheme == 'package') {
Uri packageUri =
_packages.resolve(containedUri, notFound: (Uri packageUri) => null);
- //TODO(pquitslund): package_config needs to be updated to set schemes for file URIs.
+ // Ensure scheme is set.
if (packageUri != null && packageUri.scheme == '') {
- containedUri = packageUri.replace(scheme: 'file');
+ packageUri = packageUri.replace(scheme: 'file');
}
+ containedUri = packageUri;
}
for (UriResolver resolver in _resolvers) {
Source result = resolver.resolveAbsolute(containedUri);
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 20f3957..096c14b 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -253,12 +253,14 @@
}
ExecutableElement staticMethodElement = node.staticElement;
DartType staticType = _computeStaticReturnType(staticMethodElement);
- staticType = _refineBinaryExpressionType(node, staticType);
+ staticType = _refineBinaryExpressionType(node, staticType, _getStaticType);
_recordStaticType(node, staticType);
MethodElement propagatedMethodElement = node.propagatedElement;
if (!identical(propagatedMethodElement, staticMethodElement)) {
DartType propagatedType =
_computeStaticReturnType(propagatedMethodElement);
+ propagatedType =
+ _refineBinaryExpressionType(node, propagatedType, _getBestType);
_resolver.recordPropagatedTypeIfBetter(node, propagatedType);
}
return null;
@@ -1381,6 +1383,13 @@
}
/**
+ * Return the best type of the given [expression].
+ */
+ DartType _getBestType(Expression expression) {
+ return expression.bestType;
+ }
+
+ /**
* If the given element name can be mapped to the name of a class defined within the given
* library, return the type specified by the argument.
*
@@ -1507,10 +1516,7 @@
}
/**
- * Return the static type of the given expression.
- *
- * @param expression the expression whose type is to be returned
- * @return the static type of the given expression
+ * Return the static type of the given [expression].
*/
DartType _getStaticType(Expression expression) {
DartType type = expression.staticType;
@@ -1697,15 +1703,15 @@
}
/**
- * Attempts to make a better guess for the static type of the given binary expression.
- *
- * @param node the binary expression to analyze
- * @param staticType the static type of the expression as resolved
- * @return the better type guess, or the same static type as given
+ * Attempts to make a better guess for the type of the given binary
+ * [expression], given that resolution has so far produced the [currentType].
+ * The [typeAccessor] is used to access the corresponding type of the left
+ * and right operands.
*/
DartType _refineBinaryExpressionType(
- BinaryExpression node, DartType staticType) {
- sc.TokenType operator = node.operator.type;
+ BinaryExpression expression, DartType currentType,
+ [DartType typeAccessor(Expression node)]) {
+ sc.TokenType operator = expression.operator.type;
// bool
if (operator == sc.TokenType.AMPERSAND_AMPERSAND ||
operator == sc.TokenType.BAR_BAR ||
@@ -1714,14 +1720,14 @@
return _typeProvider.boolType;
}
DartType intType = _typeProvider.intType;
- if (_getStaticType(node.leftOperand) == intType) {
+ if (typeAccessor(expression.leftOperand) == intType) {
// int op double
if (operator == sc.TokenType.MINUS ||
operator == sc.TokenType.PERCENT ||
operator == sc.TokenType.PLUS ||
operator == sc.TokenType.STAR) {
DartType doubleType = _typeProvider.doubleType;
- if (_getStaticType(node.rightOperand) == doubleType) {
+ if (typeAccessor(expression.rightOperand) == doubleType) {
return doubleType;
}
}
@@ -1731,13 +1737,13 @@
operator == sc.TokenType.PLUS ||
operator == sc.TokenType.STAR ||
operator == sc.TokenType.TILDE_SLASH) {
- if (_getStaticType(node.rightOperand) == intType) {
- staticType = intType;
+ if (typeAccessor(expression.rightOperand) == intType) {
+ return intType;
}
}
}
// default
- return staticType;
+ return currentType;
}
/**
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 961627c..99ad62c 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 0.25.1
+version: 0.25.2-alpha.1
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 0a1b03a..1b13295 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -5391,6 +5391,7 @@
expect(declaration.functionExpression.element, same(function));
expect(function.isExternal, isTrue);
expect(function.isSynthetic, isFalse);
+ expect(function.typeParameters, hasLength(0));
}
void test_visitFunctionDeclaration_getter() {
@@ -5412,6 +5413,7 @@
expect(accessor.isExternal, isFalse);
expect(accessor.isSetter, isFalse);
expect(accessor.isSynthetic, isFalse);
+ expect(accessor.typeParameters, hasLength(0));
PropertyInducingElement variable = accessor.variable;
EngineTestCase.assertInstanceOf((obj) => obj is TopLevelVariableElement,
TopLevelVariableElement, variable);
@@ -5435,6 +5437,7 @@
expect(declaration.functionExpression.element, same(function));
expect(function.isExternal, isFalse);
expect(function.isSynthetic, isFalse);
+ expect(function.typeParameters, hasLength(0));
}
void test_visitFunctionDeclaration_setter() {
@@ -5456,12 +5459,40 @@
expect(accessor.isExternal, isFalse);
expect(accessor.isSetter, isTrue);
expect(accessor.isSynthetic, isFalse);
+ expect(accessor.typeParameters, hasLength(0));
PropertyInducingElement variable = accessor.variable;
EngineTestCase.assertInstanceOf((obj) => obj is TopLevelVariableElement,
TopLevelVariableElement, variable);
expect(variable.isSynthetic, isTrue);
}
+ void test_visitFunctionDeclaration_typeParameters() {
+ ElementHolder holder = new ElementHolder();
+ ElementBuilder builder = new ElementBuilder(holder);
+ String functionName = 'f';
+ String typeParameterName = 'E';
+ FunctionExpression expression = AstFactory.functionExpression3(
+ AstFactory.typeParameterList([typeParameterName]),
+ AstFactory.formalParameterList(), AstFactory.blockFunctionBody2());
+ FunctionDeclaration declaration =
+ AstFactory.functionDeclaration(null, null, functionName, expression);
+ declaration.accept(builder);
+ List<FunctionElement> functions = holder.functions;
+ expect(functions, hasLength(1));
+ FunctionElement function = functions[0];
+ expect(function, isNotNull);
+ expect(function.name, functionName);
+ expect(function.isExternal, isFalse);
+ expect(function.isSynthetic, isFalse);
+ expect(declaration.element, same(function));
+ expect(expression.element, same(function));
+ List<TypeParameterElement> typeParameters = function.typeParameters;
+ expect(typeParameters, hasLength(1));
+ TypeParameterElement typeParameter = typeParameters[0];
+ expect(typeParameter, isNotNull);
+ expect(typeParameter.name, typeParameterName);
+ }
+
void test_visitFunctionExpression() {
ElementHolder holder = new ElementHolder();
ElementBuilder builder = new ElementBuilder(holder);
@@ -5474,6 +5505,7 @@
expect(function, isNotNull);
expect(expression.element, same(function));
expect(function.isSynthetic, isFalse);
+ expect(function.typeParameters, hasLength(0));
}
void test_visitFunctionTypeAlias() {
@@ -5515,11 +5547,34 @@
expect(parameter.isFinal, isFalse);
expect(parameter.isSynthetic, isFalse);
expect(parameter.parameterKind, ParameterKind.REQUIRED);
- {
- SourceRange visibleRange = parameter.visibleRange;
- expect(100, visibleRange.offset);
- expect(110, visibleRange.end);
- }
+ SourceRange visibleRange = parameter.visibleRange;
+ expect(100, visibleRange.offset);
+ expect(110, visibleRange.end);
+ }
+
+ void test_visitFunctionTypedFormalParameter_withTypeParameters() {
+ ElementHolder holder = new ElementHolder();
+ ElementBuilder builder = new ElementBuilder(holder);
+ String parameterName = "p";
+ FunctionTypedFormalParameter formalParameter =
+ AstFactory.functionTypedFormalParameter(null, parameterName);
+ formalParameter.typeParameters = AstFactory.typeParameterList(['F']);
+ _useParameterInMethod(formalParameter, 100, 110);
+ formalParameter.accept(builder);
+ List<ParameterElement> parameters = holder.parameters;
+ expect(parameters, hasLength(1));
+ ParameterElement parameter = parameters[0];
+ expect(parameter, isNotNull);
+ expect(parameter.name, parameterName);
+ expect(parameter.initializer, isNull);
+ expect(parameter.isConst, isFalse);
+ expect(parameter.isFinal, isFalse);
+ expect(parameter.isSynthetic, isFalse);
+ expect(parameter.parameterKind, ParameterKind.REQUIRED);
+ expect(parameter.typeParameters, hasLength(1));
+ SourceRange visibleRange = parameter.visibleRange;
+ expect(100, visibleRange.offset);
+ expect(110, visibleRange.end);
}
void test_visitLabeledStatement() {
@@ -5554,6 +5609,7 @@
expect(method.labels, hasLength(0));
expect(method.localVariables, hasLength(0));
expect(method.parameters, hasLength(0));
+ expect(method.typeParameters, hasLength(0));
expect(method.isAbstract, isTrue);
expect(method.isExternal, isFalse);
expect(method.isStatic, isFalse);
@@ -5579,6 +5635,7 @@
expect(method.labels, hasLength(0));
expect(method.localVariables, hasLength(0));
expect(method.parameters, hasLength(0));
+ expect(method.typeParameters, hasLength(0));
expect(method.isAbstract, isFalse);
expect(method.isExternal, isTrue);
expect(method.isStatic, isFalse);
@@ -5691,6 +5748,7 @@
expect(method.labels, hasLength(0));
expect(method.localVariables, hasLength(0));
expect(method.parameters, hasLength(0));
+ expect(method.typeParameters, hasLength(0));
expect(method.isAbstract, isFalse);
expect(method.isExternal, isFalse);
expect(method.isStatic, isFalse);
@@ -5716,6 +5774,7 @@
expect(method.labels, hasLength(0));
expect(method.localVariables, hasLength(0));
expect(method.parameters, hasLength(1));
+ expect(method.typeParameters, hasLength(0));
expect(method.isAbstract, isFalse);
expect(method.isExternal, isFalse);
expect(method.isStatic, isFalse);
@@ -5831,12 +5890,38 @@
expect(method.labels, hasLength(0));
expect(method.localVariables, hasLength(0));
expect(method.parameters, hasLength(0));
+ expect(method.typeParameters, hasLength(0));
expect(method.isAbstract, isFalse);
expect(method.isExternal, isFalse);
expect(method.isStatic, isTrue);
expect(method.isSynthetic, isFalse);
}
+ void test_visitMethodDeclaration_typeParameters() {
+ ElementHolder holder = new ElementHolder();
+ ElementBuilder builder = new ElementBuilder(holder);
+ String methodName = "m";
+ MethodDeclaration methodDeclaration = AstFactory.methodDeclaration2(null,
+ null, null, null, AstFactory.identifier3(methodName),
+ AstFactory.formalParameterList(), AstFactory.blockFunctionBody2());
+ methodDeclaration.typeParameters = AstFactory.typeParameterList(['E']);
+ methodDeclaration.accept(builder);
+ List<MethodElement> methods = holder.methods;
+ expect(methods, hasLength(1));
+ MethodElement method = methods[0];
+ expect(method, isNotNull);
+ expect(method.name, methodName);
+ expect(method.functions, hasLength(0));
+ expect(method.labels, hasLength(0));
+ expect(method.localVariables, hasLength(0));
+ expect(method.parameters, hasLength(0));
+ expect(method.typeParameters, hasLength(1));
+ expect(method.isAbstract, isFalse);
+ expect(method.isExternal, isFalse);
+ expect(method.isStatic, isFalse);
+ expect(method.isSynthetic, isFalse);
+ }
+
void test_visitMethodDeclaration_withMembers() {
ElementHolder holder = new ElementHolder();
ElementBuilder builder = new ElementBuilder(holder);
@@ -5863,6 +5948,7 @@
MethodElement method = methods[0];
expect(method, isNotNull);
expect(method.name, methodName);
+ expect(method.typeParameters, hasLength(0));
expect(method.isAbstract, isFalse);
expect(method.isExternal, isFalse);
expect(method.isStatic, isFalse);
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index e07053d..1e17493 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -10111,6 +10111,17 @@
_listener.assertNoErrors();
}
+ void test_visitBinaryExpression_minusID_propagated() {
+ // a - b
+ BinaryExpression node = AstFactory.binaryExpression(
+ _propagatedVariable(_typeProvider.intType, 'a'), TokenType.MINUS,
+ _propagatedVariable(_typeProvider.doubleType, 'b'));
+ node.propagatedElement = getMethod(_typeProvider.numType, "+");
+ _analyze(node);
+ expect(node.propagatedType, same(_typeProvider.doubleType));
+ _listener.assertNoErrors();
+ }
+
void test_visitBinaryExpression_notEquals() {
// 2 != 3
Expression node = AstFactory.binaryExpression(
@@ -10137,6 +10148,17 @@
_listener.assertNoErrors();
}
+ void test_visitBinaryExpression_plusII_propagated() {
+ // a + b
+ BinaryExpression node = AstFactory.binaryExpression(
+ _propagatedVariable(_typeProvider.intType, 'a'), TokenType.PLUS,
+ _propagatedVariable(_typeProvider.intType, 'b'));
+ node.propagatedElement = getMethod(_typeProvider.numType, "+");
+ _analyze(node);
+ expect(node.propagatedType, same(_typeProvider.intType));
+ _listener.assertNoErrors();
+ }
+
void test_visitBinaryExpression_slash() {
// 2 / 2
BinaryExpression node = AstFactory.binaryExpression(
@@ -11104,6 +11126,25 @@
StaticTypeAnalyzer.flattenFutures(_typeProvider, type);
/**
+ * Return a simple identifier that has been resolved to a variable element with the given type.
+ *
+ * @param type the type of the variable being represented
+ * @param variableName the name of the variable
+ * @return a simple identifier that has been resolved to a variable element with the given type
+ */
+ SimpleIdentifier _propagatedVariable(
+ InterfaceType type, String variableName) {
+ SimpleIdentifier identifier = AstFactory.identifier3(variableName);
+ VariableElementImpl element =
+ ElementFactory.localVariableElement(identifier);
+ element.type = type;
+ identifier.staticType = _typeProvider.dynamicType;
+ identifier.propagatedElement = element;
+ identifier.propagatedType = type;
+ return identifier;
+ }
+
+ /**
* Return an integer literal that has been resolved to the correct type.
*
* @param value the value of the literal
@@ -13376,26 +13417,11 @@
_listener.assertNoErrors();
}
- void fail_visitFunctionDeclaration() {
- fail("Not yet tested");
- _listener.assertNoErrors();
- }
-
void fail_visitFunctionTypeAlias() {
fail("Not yet tested");
_listener.assertNoErrors();
}
- void fail_visitFunctionTypedFormalParameter() {
- fail("Not yet tested");
- _listener.assertNoErrors();
- }
-
- void fail_visitMethodDeclaration() {
- fail("Not yet tested");
- _listener.assertNoErrors();
- }
-
void fail_visitVariableDeclaration() {
fail("Not yet tested");
ClassElement type = ElementFactory.classElement2("A");
@@ -13698,6 +13724,148 @@
_listener.assertNoErrors();
}
+ void test_visitFunctionDeclaration() {
+ // R f(P p) {}
+ // class R {}
+ // class P {}
+ ClassElement elementR = ElementFactory.classElement2('R');
+ ClassElement elementP = ElementFactory.classElement2('P');
+ FunctionElement elementF = ElementFactory.functionElement('f');
+ FunctionDeclaration declaration = AstFactory.functionDeclaration(
+ AstFactory.typeName4('R'), null, 'f', AstFactory.functionExpression2(
+ AstFactory.formalParameterList([
+ AstFactory.simpleFormalParameter4(AstFactory.typeName4('P'), 'p')
+ ]), null));
+ declaration.name.staticElement = elementF;
+ _resolveNode(declaration, [elementR, elementP]);
+ expect(declaration.returnType.type, elementR.type);
+ SimpleFormalParameter parameter =
+ declaration.functionExpression.parameters.parameters[0];
+ expect(parameter.type.type, elementP.type);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionDeclaration_typeParameter() {
+ // E f<E>(E e) {}
+ TypeParameterElement elementE = ElementFactory.typeParameterElement('E');
+ FunctionElementImpl elementF = ElementFactory.functionElement('f');
+ elementF.typeParameters = <TypeParameterElement>[elementE];
+ FunctionDeclaration declaration = AstFactory.functionDeclaration(
+ AstFactory.typeName4('E'), null, 'f', AstFactory.functionExpression2(
+ AstFactory.formalParameterList([
+ AstFactory.simpleFormalParameter4(AstFactory.typeName4('E'), 'e')
+ ]), null));
+ declaration.name.staticElement = elementF;
+ _resolveNode(declaration, []);
+ expect(declaration.returnType.type, elementE.type);
+ SimpleFormalParameter parameter =
+ declaration.functionExpression.parameters.parameters[0];
+ expect(parameter.type.type, elementE.type);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionTypedFormalParameter() {
+ // R f(R g(P p)) {}
+ // class R {}
+ // class P {}
+ ClassElement elementR = ElementFactory.classElement2('R');
+ ClassElement elementP = ElementFactory.classElement2('P');
+ FunctionElement elementF = ElementFactory.functionElement('f');
+ ParameterElementImpl requiredParameter =
+ ElementFactory.requiredParameter('p');
+ FunctionTypedFormalParameter parameterDeclaration = AstFactory
+ .functionTypedFormalParameter(AstFactory.typeName4('R'), 'g', [
+ AstFactory.simpleFormalParameter4(AstFactory.typeName4('P'), 'p')
+ ]);
+ parameterDeclaration.identifier.staticElement = requiredParameter;
+ FunctionDeclaration declaration = AstFactory.functionDeclaration(
+ AstFactory.typeName4('R'), null, 'f', AstFactory.functionExpression2(
+ AstFactory.formalParameterList([parameterDeclaration]), null));
+ declaration.name.staticElement = elementF;
+ _resolveNode(declaration, [elementR, elementP]);
+ expect(declaration.returnType.type, elementR.type);
+ FunctionTypedFormalParameter parameter =
+ declaration.functionExpression.parameters.parameters[0];
+ expect(parameter.returnType.type, elementR.type);
+ SimpleFormalParameter innerParameter = parameter.parameters.parameters[0];
+ expect(innerParameter.type.type, elementP.type);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionTypedFormalParameter_typeParameter() {
+ // R f(R g<E>(E e)) {}
+ // class R {}
+ ClassElement elementR = ElementFactory.classElement2('R');
+ TypeParameterElement elementE = ElementFactory.typeParameterElement('E');
+ FunctionElement elementF = ElementFactory.functionElement('f');
+ ParameterElementImpl requiredParameter =
+ ElementFactory.requiredParameter('g');
+ requiredParameter.typeParameters = <TypeParameterElement>[elementE];
+ FunctionTypedFormalParameter parameterDeclaration = AstFactory
+ .functionTypedFormalParameter(AstFactory.typeName4('R'), 'g', [
+ AstFactory.simpleFormalParameter4(AstFactory.typeName4('E'), 'e')
+ ]);
+ parameterDeclaration.identifier.staticElement = requiredParameter;
+ FunctionDeclaration declaration = AstFactory.functionDeclaration(
+ AstFactory.typeName4('R'), null, 'f', AstFactory.functionExpression2(
+ AstFactory.formalParameterList([parameterDeclaration]), null));
+ declaration.name.staticElement = elementF;
+ _resolveNode(declaration, [elementR]);
+ expect(declaration.returnType.type, elementR.type);
+ FunctionTypedFormalParameter parameter =
+ declaration.functionExpression.parameters.parameters[0];
+ expect(parameter.returnType.type, elementR.type);
+ SimpleFormalParameter innerParameter = parameter.parameters.parameters[0];
+ expect(innerParameter.type.type, elementE.type);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitMethodDeclaration() {
+ // class A {
+ // R m(P p) {}
+ // }
+ // class R {}
+ // class P {}
+ ClassElementImpl elementA = ElementFactory.classElement2('A');
+ ClassElement elementR = ElementFactory.classElement2('R');
+ ClassElement elementP = ElementFactory.classElement2('P');
+ MethodElement elementM = ElementFactory.methodElement('m', null);
+ elementA.methods = <MethodElement>[elementM];
+ MethodDeclaration declaration = AstFactory.methodDeclaration(null,
+ AstFactory.typeName4('R'), null, null, AstFactory.identifier3('m'),
+ AstFactory.formalParameterList([
+ AstFactory.simpleFormalParameter4(AstFactory.typeName4('P'), 'p')
+ ]));
+ declaration.name.staticElement = elementM;
+ _resolveNode(declaration, [elementA, elementR, elementP]);
+ expect(declaration.returnType.type, elementR.type);
+ SimpleFormalParameter parameter = declaration.parameters.parameters[0];
+ expect(parameter.type.type, elementP.type);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitMethodDeclaration_typeParameter() {
+ // class A {
+ // E m<E>(E e) {}
+ // }
+ ClassElementImpl elementA = ElementFactory.classElement2('A');
+ TypeParameterElement elementE = ElementFactory.typeParameterElement('E');
+ MethodElementImpl elementM = ElementFactory.methodElement('m', null);
+ elementM.typeParameters = <TypeParameterElement>[elementE];
+ elementA.methods = <MethodElement>[elementM];
+ MethodDeclaration declaration = AstFactory.methodDeclaration(null,
+ AstFactory.typeName4('E'), null, null, AstFactory.identifier3('m'),
+ AstFactory.formalParameterList([
+ AstFactory.simpleFormalParameter4(AstFactory.typeName4('E'), 'e')
+ ]));
+ declaration.name.staticElement = elementM;
+ _resolveNode(declaration, [elementA]);
+ expect(declaration.returnType.type, elementE.type);
+ SimpleFormalParameter parameter = declaration.parameters.parameters[0];
+ expect(parameter.type.type, elementE.type);
+ _listener.assertNoErrors();
+ }
+
void test_visitSimpleFormalParameter_noType() {
// p
FormalParameter node = AstFactory.simpleFormalParameter3("p");
diff --git a/pkg/analyzer/test/generated/source_factory_test.dart b/pkg/analyzer/test/generated/source_factory_test.dart
index e510949..7ff5572 100644
--- a/pkg/analyzer/test/generated/source_factory_test.dart
+++ b/pkg/analyzer/test/generated/source_factory_test.dart
@@ -77,6 +77,15 @@
group('resolveUri', () {
test('URI in mapping', () {
String uri = resolvePackageUri(config: '''
+unittest:file:///home/somebody/.pub/cache/unittest-0.9.9/lib/
+async:file:///home/somebody/.pub/cache/async-1.1.0/lib/
+quiver:file:///home/somebody/.pub/cache/quiver-1.2.1/lib
+''', uri: 'package:unittest/unittest.dart');
+ expect(uri, equals(
+ '/home/somebody/.pub/cache/unittest-0.9.9/lib/unittest.dart'));
+ });
+ test('URI in mapping (no scheme)', () {
+ String uri = resolvePackageUri(config: '''
unittest:/home/somebody/.pub/cache/unittest-0.9.9/lib/
async:/home/somebody/.pub/cache/async-1.1.0/lib/
quiver:/home/somebody/.pub/cache/quiver-1.2.1/lib
diff --git a/pkg/analyzer/test/source/sdk_ext_test.dart b/pkg/analyzer/test/source/sdk_ext_test.dart
new file mode 100644
index 0000000..288fe37
--- /dev/null
+++ b/pkg/analyzer/test/source/sdk_ext_test.dart
@@ -0,0 +1,96 @@
+// 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 test.source.sdk_ext;
+
+import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer/source/sdk_ext.dart';
+import 'package:unittest/unittest.dart';
+
+main() {
+ groupSep = ' | ';
+ group('SdkExtUriResolverTest', () {
+ setUp(() {
+ buildResourceProvider();
+ });
+ tearDown(() {
+ clearResourceProvider();
+ });
+ test('test_NullPackageMap', () {
+ var resolver = new SdkExtUriResolver(null);
+ expect(resolver.length, equals(0));
+ });
+ test('test_NoSdkExtPackageMap', () {
+ var resolver = new SdkExtUriResolver({
+ 'fox': [resourceProvider.getResource('/empty')]
+ });
+ expect(resolver.length, equals(0));
+ });
+ test('test_SdkExtPackageMap', () {
+ var resolver = new SdkExtUriResolver({
+ 'fox': [resourceProvider.getResource('/tmp')]
+ });
+ // We have four mappings.
+ expect(resolver.length, equals(4));
+ // Check that they map to the correct paths.
+ expect(resolver['dart:fox'], equals("/tmp/slippy.dart"));
+ expect(resolver['dart:bear'], equals("/tmp/grizzly.dart"));
+ expect(resolver['dart:relative'], equals("/relative.dart"));
+ expect(resolver['dart:deep'], equals("/tmp/deep/directory/file.dart"));
+ });
+ test('test_BadJSON', () {
+ var resolver = new SdkExtUriResolver(null);
+ resolver.addSdkExt(r'''{{{,{{}}},}}''', null);
+ expect(resolver.length, equals(0));
+ });
+ test('test_restoreAbsolute', () {
+ var resolver = new SdkExtUriResolver({
+ 'fox': [resourceProvider.getResource('/tmp')]
+ });
+ var source = resolver.resolveAbsolute(Uri.parse('dart:fox'));
+ expect(source, isNotNull);
+ // Restore source's uri.
+ var restoreUri = resolver.restoreAbsolute(source);
+ expect(restoreUri, isNotNull);
+ // Verify that it is 'dart:fox'.
+ expect(restoreUri.toString(), equals('dart:fox'));
+ expect(restoreUri.scheme, equals('dart'));
+ expect(restoreUri.path, equals('fox'));
+ });
+ test('test_resolvePart', () {
+ var resolver = new SdkExtUriResolver({
+ 'fox': [resourceProvider.getResource('/tmp')]
+ });
+ var source = resolver.resolveAbsolute(Uri.parse('dart:fox/foo.dart'));
+ expect(source, isNotNull);
+ // Restore source's uri.
+ var restoreUri = resolver.restoreAbsolute(source);
+ expect(restoreUri, isNotNull);
+ // Verify that it is 'dart:fox/foo.dart'.
+ expect(restoreUri.toString(), equals('dart:fox/foo.dart'));
+ expect(restoreUri.scheme, equals('dart'));
+ expect(restoreUri.path, equals('fox/foo.dart'));
+ });
+ });
+}
+
+MemoryResourceProvider resourceProvider;
+
+buildResourceProvider() {
+ resourceProvider = new MemoryResourceProvider();
+ resourceProvider.newFolder('/empty');
+ resourceProvider.newFolder('/tmp');
+ resourceProvider.newFile('/tmp/_sdkext', r'''
+ {
+ "dart:fox": "slippy.dart",
+ "dart:bear": "grizzly.dart",
+ "dart:relative": "../relative.dart",
+ "dart:deep": "deep/directory/file.dart",
+ "fart:loudly": "nomatter.dart"
+ }''');
+}
+
+clearResourceProvider() {
+ resourceProvider = null;
+}
diff --git a/pkg/analyzer/test/source/test_all.dart b/pkg/analyzer/test/source/test_all.dart
index d2de433..b8c09bf 100644
--- a/pkg/analyzer/test/source/test_all.dart
+++ b/pkg/analyzer/test/source/test_all.dart
@@ -8,6 +8,7 @@
import 'package_map_provider_test.dart' as package_map_provider_test;
import 'package_map_resolver_test.dart' as package_map_resolver_test;
+import 'sdk_ext_test.dart' as sdk_ext_test;
/// Utility for manually running all tests.
main() {
@@ -15,5 +16,6 @@
group('source', () {
package_map_provider_test.main();
package_map_resolver_test.main();
+ sdk_ext_test.main();
});
}
diff --git a/pkg/analyzer/test/src/task/html_work_manager_test.dart b/pkg/analyzer/test/src/task/html_work_manager_test.dart
index 94015ae..ad1027c 100644
--- a/pkg/analyzer/test/src/task/html_work_manager_test.dart
+++ b/pkg/analyzer/test/src/task/html_work_manager_test.dart
@@ -16,7 +16,6 @@
import 'package:analyzer/src/generated/error.dart'
show AnalysisError, HtmlErrorCode;
import 'package:analyzer/src/generated/java_engine.dart' show CaughtException;
-import 'package:analyzer/src/generated/scanner.dart' show ScannerErrorCode;
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/task/driver.dart';
import 'package:analyzer/src/task/html.dart';
diff --git a/pkg/analyzer/tool/task_dependency_graph.dart b/pkg/analyzer/tool/task_dependency_graph.dart
new file mode 100644
index 0000000..79e6d50
--- /dev/null
+++ b/pkg/analyzer/tool/task_dependency_graph.dart
@@ -0,0 +1,151 @@
+// 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.
+
+/**
+ * This file contains code to output a description of tasks and their
+ * dependencies in ".dot" format. Prior to running, the user should run "pub
+ * get" in the analyzer directory to ensure that a "packages" folder exists.
+ *
+ * The ".dot" file is output to standard out. To convert it to a pdf, store it
+ * in a file (e.g. "tasks.dot"), and post-process it with
+ * "dot tasks.dart -Tpdf -O".
+ *
+ * TODO(paulberry):
+ * - Add general.dart and html.dart for completeness.
+ * - Use Graphviz's "record" feature to produce more compact output
+ * (http://www.graphviz.org/content/node-shapes#record)
+ * - Produce a warning if a result descriptor is found which isn't the output
+ * of exactly one task.
+ * - Convert this tool to use package_config to find the package map.
+ */
+library task_dependency_graph;
+
+import 'dart:io' hide File;
+
+import 'package:analyzer/analyzer.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/java_io.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/sdk_io.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:path/path.dart' as path;
+
+main() {
+ new Driver().run();
+}
+
+typedef void ResultDescriptorFinderCallback(PropertyAccessorElement element);
+
+class Driver {
+ PhysicalResourceProvider resourceProvider;
+ AnalysisContext context;
+ InterfaceType resultDescriptorType;
+ String rootDir;
+
+ void findResultDescriptors(
+ AstNode node, void callback(String descriptorName)) {
+ Set<PropertyAccessorElement> resultDescriptors =
+ new Set<PropertyAccessorElement>();
+ node.accept(new ResultDescriptorFinder(
+ resultDescriptorType, resultDescriptors.add));
+ for (PropertyAccessorElement resultDescriptor in resultDescriptors) {
+ callback(resultDescriptor.name);
+ }
+ }
+
+ /**
+ * Find the root directory of the analyzer package by proceeding
+ * upward to the 'tool' dir, and then going up one more directory.
+ */
+ String findRoot(String pathname) {
+ while (path.basename(pathname) != 'tool') {
+ String parent = path.dirname(pathname);
+ if (parent.length >= pathname.length) {
+ throw new Exception("Can't find root directory");
+ }
+ pathname = parent;
+ }
+ return path.dirname(pathname);
+ }
+
+ CompilationUnit getUnit(Source source) =>
+ context.resolveCompilationUnit2(source, source);
+
+ void run() {
+ rootDir = findRoot(Platform.script.toFilePath(windows: Platform.isWindows));
+ resourceProvider = PhysicalResourceProvider.INSTANCE;
+ DartSdk sdk = DirectoryBasedDartSdk.defaultSdk;
+ context = AnalysisEngine.instance.createAnalysisContext();
+ JavaFile packagesDir = new JavaFile(path.join(rootDir, 'packages'));
+ List<UriResolver> uriResolvers = [
+ new FileUriResolver(),
+ new DartUriResolver(sdk),
+ new PackageUriResolver(<JavaFile>[packagesDir])
+ ];
+ context.sourceFactory = new SourceFactory(uriResolvers);
+ Source taskSource =
+ setupSource(path.join('lib', 'src', 'task', 'dart.dart'));
+ Source modelSource = setupSource(path.join('lib', 'task', 'model.dart'));
+ CompilationUnitElement modelElement = getUnit(modelSource).element;
+ InterfaceType analysisTaskType = modelElement.getType('AnalysisTask').type;
+ DartType dynamicType = context.typeProvider.dynamicType;
+ resultDescriptorType = modelElement.getType('ResultDescriptor').type
+ .substitute4([dynamicType]);
+ CompilationUnit taskUnit = getUnit(taskSource);
+ CompilationUnitElement taskUnitElement = taskUnit.element;
+ print('digraph G {');
+ Set<String> results = new Set<String>();
+ for (ClassElement cls in taskUnitElement.types) {
+ if (!cls.isAbstract && cls.type.isSubtypeOf(analysisTaskType)) {
+ String task = cls.name;
+ // TODO(paulberry): node is deprecated. What am I supposed to do
+ // instead?
+ findResultDescriptors(cls.getMethod('buildInputs').node,
+ (String input) {
+ results.add(input);
+ print(' $input -> $task');
+ });
+ findResultDescriptors(cls.getField('DESCRIPTOR').node, (String output) {
+ results.add(output);
+ print(' $task -> $output');
+ });
+ }
+ }
+ for (String result in results) {
+ print(' $result [shape=box]');
+ }
+ print('}');
+ }
+
+ Source setupSource(String filename) {
+ String filePath = path.join(rootDir, filename);
+ File file = resourceProvider.getResource(filePath);
+ Source source = file.createSource();
+ ChangeSet changeSet = new ChangeSet();
+ changeSet.addedSource(source);
+ context.applyChanges(changeSet);
+ return source;
+ }
+}
+
+class ResultDescriptorFinder extends GeneralizingAstVisitor {
+ final InterfaceType resultDescriptorType;
+ final ResultDescriptorFinderCallback callback;
+
+ ResultDescriptorFinder(this.resultDescriptorType, this.callback);
+
+ @override
+ visitIdentifier(Identifier node) {
+ Element element = node.staticElement;
+ if (element is PropertyAccessorElement &&
+ element.isGetter &&
+ element.returnType.isSubtypeOf(resultDescriptorType)) {
+ callback(element);
+ }
+ }
+}
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart
index 9fd865a..c65cbc5 100644
--- a/pkg/compiler/lib/src/apiimpl.dart
+++ b/pkg/compiler/lib/src/apiimpl.dart
@@ -104,9 +104,7 @@
hasOption(options, '--generate-code-with-compile-time-errors'),
testMode: hasOption(options, '--test-mode'),
allowNativeExtensions:
- hasOption(options, '--allow-native-extensions'),
- enableNullAwareOperators:
- hasOption(options, '--enable-null-aware-operators')) {
+ hasOption(options, '--allow-native-extensions')) {
tasks.addAll([
userHandlerTask = new leg.GenericTask('Diagnostic handler', this),
userProviderTask = new leg.GenericTask('Input provider', this),
@@ -369,46 +367,52 @@
});
}
- Future setupPackages(Uri uri) async {
+ Future setupPackages(Uri uri) {
if (packageRoot != null) {
// Use "non-file" packages because the file version requires a [Directory]
// and we can't depend on 'dart:io' classes.
packages = new NonFilePackagesDirectoryPackages(packageRoot);
} else if (packageConfig != null) {
- var packageConfigContents = await provider(packageConfig);
- if (packageConfigContents is String) {
- packageConfigContents = UTF8.encode(packageConfigContents);
- }
- packages =
- new MapPackages(pkgs.parse(packageConfigContents, packageConfig));
+ return provider(packageConfig).then((packageConfigContents) {
+ if (packageConfigContents is String) {
+ packageConfigContents = UTF8.encode(packageConfigContents);
+ }
+ packages =
+ new MapPackages(pkgs.parse(packageConfigContents, packageConfig));
+ });
} else {
if (packagesDiscoveryProvider == null) {
packages = Packages.noPackages;
} else {
- packages = await callUserPackagesDiscovery(uri);
+ return callUserPackagesDiscovery(uri).then((p) {
+ packages = p;
+ });
}
}
+ return new Future.value();
}
- Future<bool> run(Uri uri) async {
+ Future<bool> run(Uri uri) {
log('Allowed library categories: $allowedLibraryCategories');
- await setupPackages(uri);
- assert(packages != null);
+ return setupPackages(uri).then((_) {
+ assert(packages != null);
- bool success = await super.run(uri);
- int cumulated = 0;
- for (final task in tasks) {
- int elapsed = task.timing;
- if (elapsed != 0) {
- cumulated += elapsed;
- log('${task.name} took ${elapsed}msec');
- }
- }
- int total = totalCompileTime.elapsedMilliseconds;
- log('Total compile-time ${total}msec;'
- ' unaccounted ${total - cumulated}msec');
- return success;
+ return super.run(uri).then((bool success) {
+ int cumulated = 0;
+ for (final task in tasks) {
+ int elapsed = task.timing;
+ if (elapsed != 0) {
+ cumulated += elapsed;
+ log('${task.name} took ${elapsed}msec');
+ }
+ }
+ int total = totalCompileTime.elapsedMilliseconds;
+ log('Total compile-time ${total}msec;'
+ ' unaccounted ${total - cumulated}msec');
+ return success;
+ });
+ });
}
void reportDiagnostic(leg.Spannable node,
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 8360a5d..0cc5a67 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -791,10 +791,6 @@
/// If `true` native extension syntax is supported by the frontend.
final bool allowNativeExtensions;
- /// Temporary flag to enable `?.`, `??`, and `??=` until it becomes part of
- /// the spec.
- final bool enableNullAwareOperators;
-
/// Output provider from user of Compiler API.
api.CompilerOutputProvider userOutputProvider;
@@ -1063,7 +1059,6 @@
bool hasIncrementalSupport: false,
this.enableExperimentalMirrors: false,
this.allowNativeExtensions: false,
- this.enableNullAwareOperators: false,
this.generateCodeWithCompileTimeErrors: false,
this.testMode: false,
api.CompilerOutputProvider outputProvider,
diff --git a/pkg/compiler/lib/src/cps_ir/cps_fragment.dart b/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
new file mode 100644
index 0000000..6eda707
--- /dev/null
+++ b/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
@@ -0,0 +1,292 @@
+// 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 cps_ir.cps_fragment;
+
+import 'cps_ir_nodes.dart';
+import '../constants/values.dart';
+import '../universe/universe.dart' show Selector;
+import '../types/types.dart' show TypeMask;
+import '../io/source_information.dart';
+import '../elements/elements.dart';
+
+/// Builds a CPS fragment that can be plugged into another CPS term.
+///
+/// A CPS fragment contains a CPS term, possibly with a "hole" in it denoting
+/// where to insert new IR nodes. We say a fragment is "open" if it has such
+/// a hole. Otherwise, the fragment is "closed" and cannot be extended further.
+///
+/// This class is designed for building non-trivial CPS terms in a readable and
+/// non-error prone manner. It is not designed to manipulate existing IR nodes,
+/// nor is it intended to shield the user from every complexity in the IR.
+///
+/// EXAMPLES:
+///
+/// Call `cont` with `obj.field + 1` as argument:
+///
+/// CpsFragment cps = new CpsFragment();
+/// var fieldValue = cps.letPrim(new GetField(obj, field));
+/// var plusOne = cps.applyBuiltin(BuiltinOperator.NumAdd,
+/// [fieldValue, cps.makeOne()]);
+/// cps.invokeContinuation(cont, [plusOne]);
+///
+/// If `condition` is true then invoke `cont1`, else `cont2`.
+///
+/// cps.ifTrue(condition).invokeContinuation(cont1, []);
+/// cps.invokeContinuation(cont2, []);
+///
+/// If `condition` is true then invoke `cont` with a bound primitive:
+///
+/// CpsFragment branch = cps.ifTrue(condition);
+/// branch.invokeContinuation(cont, [branch.letPrim(arg)]);
+///
+/// Loop and call a method until it returns false:
+///
+/// Continuation loop = cps.beginLoop();
+/// var result = cps.invokeMethod(receiver, selector, ...);
+/// cps.ifFalse(result).invokeContinuation(exit, []);
+/// cps.continueLoop(loop);
+///
+class CpsFragment {
+ /// The root of the IR built using this fragment.
+ Expression root;
+
+ /// Node whose body is the hole in this CPS fragment. May be null.
+ InteriorNode context;
+
+ /// Source information to attach to every IR node created in the fragment.
+ SourceInformation sourceInformation;
+
+ CpsFragment([this.sourceInformation, this.context]);
+
+ bool get isOpen => root == null || context != null;
+ bool get isClosed => !isOpen;
+ bool get isEmpty => root == null;
+
+ /// Asserts that the fragment is non-empty and closed and returns the IR that
+ /// was built.
+ Expression get result {
+ assert(!isEmpty);
+ assert(isClosed);
+ return root;
+ }
+
+ /// Put the given expression into the fragment's hole.
+ ///
+ /// Afterwards the fragment is closed and cannot be extended until a new
+ /// [context] is set.
+ void put(Expression node) {
+ assert(root == null || context != null); // We must put the node somewhere.
+ if (root == null) {
+ root = node;
+ }
+ if (context != null) {
+ context.body = node;
+ }
+ context = null;
+ }
+
+ /// Bind a primitive. Returns the same primitive for convenience.
+ Primitive letPrim(Primitive prim) {
+ assert(prim != null);
+ LetPrim let = new LetPrim(prim);
+ put(let);
+ context = let;
+ return prim;
+ }
+
+ /// Bind a constant value.
+ Primitive makeConstant(ConstantValue constant) {
+ return letPrim(new Constant(constant));
+ }
+
+ Primitive makeZero() => makeConstant(new IntConstantValue(0));
+ Primitive makeOne() => makeConstant(new IntConstantValue(1));
+ Primitive makeNull() => makeConstant(new NullConstantValue());
+ Primitive makeTrue() => makeConstant(new TrueConstantValue());
+ Primitive makeFalse() => makeConstant(new FalseConstantValue());
+
+ /// Invoke a built-in operator.
+ Primitive applyBuiltin(BuiltinOperator op, List<Primitive> args) {
+ return letPrim(new ApplyBuiltinOperator(op, args));
+ }
+
+ /// Inserts an invocation. binds its continuation, and returns the
+ /// continuation parameter (i.e. the return value of the invocation).
+ ///
+ /// The continuation body becomes the new hole.
+ Parameter invokeMethod(Primitive receiver,
+ Selector selector,
+ TypeMask mask,
+ List<Primitive> arguments) {
+ Continuation cont = new Continuation(<Parameter>[new Parameter(null)]);
+ InvokeMethod invoke =
+ new InvokeMethod(receiver, selector, mask, arguments, cont,
+ sourceInformation);
+ put(new LetCont(cont, invoke));
+ context = cont;
+ return cont.parameters.single;
+ }
+
+ /// Inserts an invocation. binds its continuation, and returns the
+ /// continuation parameter (i.e. the return value of the invocation).
+ ///
+ /// The continuation body becomes the new hole.
+ Parameter invokeStatic(FunctionElement target, List<Primitive> arguments) {
+ Continuation cont = new Continuation(<Parameter>[new Parameter(null)]);
+ InvokeStatic invoke =
+ new InvokeStatic(target, new Selector.fromElement(target), arguments,
+ cont, sourceInformation);
+ put(new LetCont(cont, invoke));
+ context = cont;
+ return cont.parameters.single;
+ }
+
+ /// Inserts an invocation to a static function that throws an error.
+ ///
+ /// This closes the fragment; no more nodes may be added.
+ void invokeStaticThrower(FunctionElement target, List<Primitive> arguments) {
+ invokeStatic(target, arguments);
+ put(new Unreachable());
+ }
+
+ /// Invoke a non-recursive continuation.
+ ///
+ /// This closes the fragment; no more nodes may be inserted.
+ void invokeContinuation(Continuation cont, [List<Primitive> arguments]) {
+ if (arguments == null) arguments = <Primitive>[];
+ put(new InvokeContinuation(cont, arguments));
+ }
+
+ /// Build a loop with the given loop variables and initial values.
+ /// Call [continueLoop] with the returned continuation to iterate the loop.
+ ///
+ /// The loop body becomes the new hole.
+ Continuation beginLoop([List<Parameter> loopVars,
+ List<Primitive> initialValues]) {
+ if (initialValues == null) {
+ assert(loopVars == null);
+ loopVars = <Parameter>[];
+ initialValues = <Primitive>[];
+ }
+ Continuation cont = new Continuation(loopVars);
+ put(new LetCont(cont, new InvokeContinuation(cont, initialValues)));
+ context = cont;
+ return cont;
+ }
+
+ /// Continue a loop started by [beginLoop].
+ ///
+ /// This closes the fragment; no more nodes may be inserted.
+ void continueLoop(Continuation cont, [List<Primitive> updatedLoopVariables]) {
+ put(new InvokeContinuation(cont, updatedLoopVariables, isRecursive: true));
+ }
+
+ /// Branch on [condition].
+ ///
+ /// Returns a new fragment for the 'then' branch.
+ ///
+ /// The 'else' branch becomes the new hole.
+ CpsFragment ifTrue(Primitive condition) {
+ Continuation trueCont = new Continuation(<Parameter>[]);
+ Continuation falseCont = new Continuation(<Parameter>[]);
+ put(new LetCont.two(trueCont, falseCont,
+ new Branch(new IsTrue(condition), trueCont, falseCont)));
+ context = falseCont;
+ return new CpsFragment(sourceInformation, trueCont);
+ }
+
+ /// Branch on [condition].
+ ///
+ /// Returns a new fragment for the 'else' branch.
+ ///
+ /// The 'then' branch becomes the new hole.
+ CpsFragment ifFalse(Primitive condition) {
+ Continuation trueCont = new Continuation(<Parameter>[]);
+ Continuation falseCont = new Continuation(<Parameter>[]);
+ put(new LetCont.two(trueCont, falseCont,
+ new Branch(new IsTrue(condition), trueCont, falseCont)));
+ context = trueCont;
+ return new CpsFragment(sourceInformation, falseCont);
+ }
+
+ /// Create a new empty continuation and bind it here.
+ ///
+ /// Convenient for making a join point where multiple branches
+ /// meet later.
+ ///
+ /// The LetCont body becomes the new hole.
+ ///
+ /// Example use:
+ ///
+ /// Continuation fail = cps.letCont();
+ ///
+ /// // Fail if something
+ /// cps.ifTrue(<condition>)
+ /// ..invokeMethod(<method>)
+ /// ..invokeContinuation(fail);
+ ///
+ /// // Fail if something else
+ /// cps.ifTrue(<anotherCondition>)
+ /// ..invokeMethod(<anotherMethod>)
+ /// ..invokeContinuation(fail);
+ ///
+ /// // Build the fail branch
+ /// cps.insideContinuation(fail)
+ /// ..invokeStaticThrower(...);
+ ///
+ /// // Go to the happy branch
+ /// cps.invokeContinuation(cont..)
+ ///
+ Continuation letCont([List<Parameter> parameters]) {
+ if (parameters == null) parameters = <Parameter>[];
+ Continuation cont = new Continuation(parameters);
+ LetCont let = new LetCont(cont, null);
+ put(let);
+ context = let;
+ return cont;
+ }
+
+ /// Returns a fragment whose context is the body of the given continuation.
+ ///
+ /// Does not change the state of this CPS fragment.
+ ///
+ /// Useful for building the body of a continuation created using [letCont].
+ CpsFragment insideContinuation(Continuation cont) {
+ return new CpsFragment(sourceInformation, cont);
+ }
+
+ /// Puts the given fragment into this one.
+ ///
+ /// If [other] was an open fragment, its hole becomes the new hole
+ /// in this fragment.
+ ///
+ /// [other] is reset to an empty fragment after this.
+ void append(CpsFragment other) {
+ if (other.root == null) return;
+ put(other.root);
+ context = other.context;
+ other.context = null;
+ other.root = null;
+ }
+
+ /// Reads the value of the given mutable variable.
+ Primitive getMutable(MutableVariable variable) {
+ return letPrim(new GetMutableVariable(variable));
+ }
+
+ /// Sets the value of the given mutable variable.
+ void setMutable(MutableVariable variable, Primitive value) {
+ SetMutableVariable setter = new SetMutableVariable(variable, value);
+ put(setter);
+ context = setter;
+ }
+
+ /// Declare a new mutable variable.
+ void letMutable(MutableVariable variable, Primitive initialValue) {
+ LetMutable let = new LetMutable(variable, initialValue);
+ put(let);
+ context = let;
+ }
+}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
index 6c324d8..cca5f7b 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
@@ -624,12 +624,13 @@
ir.Primitive _buildInvokeSuper(Element target,
Selector selector,
- List<ir.Primitive> arguments) {
+ List<ir.Primitive> arguments,
+ SourceInformation sourceInformation) {
assert(target.isInstanceMember);
assert(isOpen);
return _continueWithExpression(
(k) => new ir.InvokeMethodDirectly(
- buildThis(), target, selector, arguments, k));
+ buildThis(), target, selector, arguments, k, sourceInformation));
}
ir.Primitive _buildInvokeDynamic(ir.Primitive receiver,
@@ -655,9 +656,11 @@
/// Create a [ir.Constant] from [value] and add it to the CPS term.
- ir.Constant buildConstant(ConstantValue value) {
+ ir.Constant buildConstant(ConstantValue value,
+ {SourceInformation sourceInformation}) {
assert(isOpen);
- return addPrimitive(new ir.Constant(value));
+ return addPrimitive(
+ new ir.Constant(value, sourceInformation: sourceInformation));
}
/// Create an integer constant and add it to the CPS term.
@@ -793,63 +796,74 @@
/// Create a invocation of the [method] on the super class where the call
/// structure is defined [callStructure] and the argument values are defined
/// by [arguments].
- ir.Primitive buildSuperMethodInvocation(MethodElement method,
- CallStructure callStructure,
- List<ir.Primitive> arguments) {
+ ir.Primitive buildSuperMethodInvocation(
+ MethodElement method,
+ CallStructure callStructure,
+ List<ir.Primitive> arguments,
+ {SourceInformation sourceInformation}) {
// TODO(johnniwinther): This shouldn't be necessary.
SelectorKind kind = Elements.isOperatorName(method.name)
? SelectorKind.OPERATOR : SelectorKind.CALL;
Selector selector =
new Selector(kind, method.memberName, callStructure);
- return _buildInvokeSuper(method, selector, arguments);
+ return _buildInvokeSuper(method, selector, arguments, sourceInformation);
}
/// Create a read access of the [method] on the super class, i.e. a
/// closurization of [method].
- ir.Primitive buildSuperMethodGet(MethodElement method) {
+ ir.Primitive buildSuperMethodGet(MethodElement method,
+ {SourceInformation sourceInformation}) {
// TODO(johnniwinther): This should have its own ir node.
return _buildInvokeSuper(
method,
new Selector.getter(method.name, method.library),
- const <ir.Primitive>[]);
+ const <ir.Primitive>[],
+ sourceInformation);
}
/// Create a getter invocation of the [getter] on the super class.
- ir.Primitive buildSuperGetterGet(MethodElement getter) {
+ ir.Primitive buildSuperGetterGet(MethodElement getter,
+ SourceInformation sourceInformation) {
// TODO(johnniwinther): This should have its own ir node.
return _buildInvokeSuper(
getter,
new Selector.getter(getter.name, getter.library),
- const <ir.Primitive>[]);
+ const <ir.Primitive>[],
+ sourceInformation);
}
/// Create an setter invocation of the [setter] on the super class with
/// [value].
ir.Primitive buildSuperSetterSet(MethodElement setter,
- ir.Primitive value) {
+ ir.Primitive value,
+ {SourceInformation sourceInformation}) {
// TODO(johnniwinther): This should have its own ir node.
_buildInvokeSuper(
setter,
new Selector.setter(setter.name, setter.library),
- <ir.Primitive>[value]);
+ <ir.Primitive>[value],
+ sourceInformation);
return value;
}
/// Create an invocation of the index [method] on the super class with
/// the provided [index].
ir.Primitive buildSuperIndex(MethodElement method,
- ir.Primitive index) {
+ ir.Primitive index,
+ {SourceInformation sourceInformation}) {
return _buildInvokeSuper(
- method, new Selector.index(), <ir.Primitive>[index]);
+ method, new Selector.index(), <ir.Primitive>[index],
+ sourceInformation);
}
/// Create an invocation of the index set [method] on the super class with
/// the provided [index] and [value].
ir.Primitive buildSuperIndexSet(MethodElement method,
ir.Primitive index,
- ir.Primitive value) {
+ ir.Primitive value,
+ {SourceInformation sourceInformation}) {
_buildInvokeSuper(method, new Selector.indexSet(),
- <ir.Primitive>[index, value]);
+ <ir.Primitive>[index, value], sourceInformation);
return value;
}
@@ -859,8 +873,11 @@
ir.Primitive buildDynamicInvocation(ir.Primitive receiver,
Selector selector,
TypeMask mask,
- List<ir.Primitive> arguments) {
- return _buildInvokeDynamic(receiver, selector, mask, arguments);
+ List<ir.Primitive> arguments,
+ {SourceInformation sourceInformation}) {
+ return _buildInvokeDynamic(
+ receiver, selector, mask, arguments,
+ sourceInformation: sourceInformation);
}
/// Create a dynamic getter invocation on [receiver] where the getter name is
@@ -925,11 +942,14 @@
/// Create an invocation of the the [local] variable or parameter where
/// argument structure is defined by [callStructure] and the argument values
/// are defined by [arguments].
- ir.Primitive buildLocalVariableInvocation(LocalVariableElement local,
- CallStructure callStructure,
- List<ir.Primitive> arguments) {
+ ir.Primitive buildLocalVariableInvocation(
+ LocalVariableElement local,
+ CallStructure callStructure,
+ List<ir.Primitive> arguments,
+ {SourceInformation callSourceInformation}) {
return buildCallInvocation(
- buildLocalVariableGet(local), callStructure, arguments);
+ buildLocalVariableGet(local), callStructure, arguments,
+ sourceInformation: callSourceInformation);
}
/// Create an invocation of the local [function] where argument structure is
@@ -938,10 +958,12 @@
ir.Primitive buildLocalFunctionInvocation(
LocalFunctionElement function,
CallStructure callStructure,
- List<ir.Primitive> arguments) {
+ List<ir.Primitive> arguments,
+ SourceInformation sourceInformation) {
// TODO(johnniwinther): Maybe this should have its own ir node.
return buildCallInvocation(
- buildLocalFunctionGet(function), callStructure, arguments);
+ buildLocalFunctionGet(function), callStructure, arguments,
+ sourceInformation: sourceInformation);
}
/// Create a static invocation of [function] where argument structure is
@@ -974,7 +996,7 @@
/// Create a getter invocation of the static [getter].
ir.Primitive buildStaticGetterGet(MethodElement getter,
- {SourceInformation sourceInformation}) {
+ SourceInformation sourceInformation) {
Selector selector = new Selector.getter(getter.name, getter.library);
return _buildInvokeStatic(
getter, selector, const <ir.Primitive>[], sourceInformation);
@@ -1958,7 +1980,7 @@
IrBuilder builder = makeDelimitedBuilder(newReturn.environment);
ir.Primitive value = builder.environment.discard(1);
buildFinallyBlock(builder);
- if (builder.isOpen) builder.buildReturn(value);
+ if (builder.isOpen) builder.buildReturn(value: value);
newReturn.continuation.body = builder._root;
exits.add(newReturn.continuation);
}
@@ -1973,7 +1995,7 @@
/// Create a return statement `return value;` or `return;` if [value] is
/// null.
- void buildReturn([ir.Primitive value]) {
+ void buildReturn({ir.Primitive value, SourceInformation sourceInformation}) {
// Build(Return(e), C) = C'[InvokeContinuation(return, x)]
// where (C', x) = Build(e, C)
//
@@ -1983,7 +2005,8 @@
value = buildNullConstant();
}
if (state.returnCollector == null) {
- add(new ir.InvokeContinuation(state.returnContinuation, [value]));
+ add(new ir.InvokeContinuation(state.returnContinuation, [value],
+ sourceInformation: sourceInformation));
_current = null;
} else {
// Inside the try block of try/finally, all returns go to a join-point
@@ -2305,12 +2328,15 @@
/// Add [functionElement] to the environment with provided [definition].
void declareLocalFunction(LocalFunctionElement functionElement,
- ClosureClassElement classElement) {
- ir.Primitive closure = buildFunctionExpression(classElement);
+ ClosureClassElement classElement,
+ SourceInformation sourceInformation) {
+ ir.Primitive closure =
+ buildFunctionExpression(classElement, sourceInformation);
declareLocalVariable(functionElement, initialValue: closure);
}
- ir.Primitive buildFunctionExpression(ClosureClassElement classElement) {
+ ir.Primitive buildFunctionExpression(ClosureClassElement classElement,
+ SourceInformation sourceInformation) {
List<ir.Primitive> arguments = <ir.Primitive>[];
for (ClosureFieldElement field in classElement.closureFields) {
// Captured 'this' is not available as a local in the current environment,
@@ -2320,8 +2346,8 @@
: environment.lookup(field.local);
arguments.add(value);
}
- return addPrimitive(
- new ir.CreateInstance(classElement, arguments, const <ir.Primitive>[]));
+ return addPrimitive(new ir.CreateInstance(
+ classElement, arguments, const <ir.Primitive>[], sourceInformation));
}
/// Create a read access of [local] variable or parameter.
@@ -2430,13 +2456,14 @@
ir.Primitive buildInvokeDirectly(FunctionElement target,
ir.Primitive receiver,
- List<ir.Primitive> arguments) {
+ List<ir.Primitive> arguments,
+ {SourceInformation sourceInformation}) {
assert(isOpen);
Selector selector =
new Selector.call(target.name, target.library, arguments.length);
return _continueWithExpression(
(k) => new ir.InvokeMethodDirectly(
- receiver, target, selector, arguments, k));
+ receiver, target, selector, arguments, k, sourceInformation));
}
/// Loads parameters to a constructor body into the environment.
@@ -2459,10 +2486,12 @@
/// Create a constructor invocation of [element] on [type] where the
/// constructor name and argument structure are defined by [callStructure] and
/// the argument values are defined by [arguments].
- ir.Primitive buildConstructorInvocation(ConstructorElement element,
- CallStructure callStructure,
- DartType type,
- List<ir.Primitive> arguments) {
+ ir.Primitive buildConstructorInvocation(
+ ConstructorElement element,
+ CallStructure callStructure,
+ DartType type,
+ List<ir.Primitive> arguments,
+ SourceInformation sourceInformation) {
assert(isOpen);
Selector selector =
new Selector(SelectorKind.CALL, element.memberName, callStructure);
@@ -2479,8 +2508,8 @@
..addAll(typeArguments);
}
return _continueWithExpression(
- (k) => new ir.InvokeConstructor(type, element, selector,
- arguments, k));
+ (k) => new ir.InvokeConstructor(
+ type, element, selector, arguments, k, sourceInformation));
}
ir.Primitive buildTypeExpression(DartType type) {
@@ -2508,7 +2537,8 @@
/// if we are currently building a constructor field initializer, from the
/// corresponding type argument (field initializers are evaluated before the
/// receiver object is created).
- ir.Primitive buildTypeVariableAccess(TypeVariableType variable) {
+ ir.Primitive buildTypeVariableAccess(TypeVariableType variable,
+ {SourceInformation sourceInformation}) {
// If the local exists in the environment, use that.
// This is put here when we are inside a constructor or field initializer,
// (or possibly a closure inside one of these).
@@ -2520,7 +2550,8 @@
// If the type variable is not in a local, read its value from the
// receiver object.
ir.Primitive target = buildThis();
- return addPrimitive(new ir.ReadTypeVariable(variable, target));
+ return addPrimitive(
+ new ir.ReadTypeVariable(variable, target, sourceInformation));
}
/// Make the given type variable accessible through the local environment
@@ -2532,9 +2563,12 @@
}
/// Reifies the value of [variable] on the current receiver object.
- ir.Primitive buildReifyTypeVariable(TypeVariableType variable) {
- ir.Primitive typeArgument = buildTypeVariableAccess(variable);
- return addPrimitive(new ir.ReifyRuntimeType(typeArgument));
+ ir.Primitive buildReifyTypeVariable(TypeVariableType variable,
+ SourceInformation sourceInformation) {
+ ir.Primitive typeArgument =
+ buildTypeVariableAccess(variable, sourceInformation: sourceInformation);
+ return addPrimitive(
+ new ir.ReifyRuntimeType(typeArgument, sourceInformation));
}
ir.Primitive buildInvocationMirror(Selector selector,
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 8b81f39..2c4fa8e 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
@@ -252,6 +252,45 @@
return null;
}
+ /// Construct a method that executes the forwarding call to the target
+ /// constructor. This is only required, if the forwarding factory
+ /// constructor can potentially be the target of a reflective call, because
+ /// the builder shortcuts calls to redirecting factories at the call site
+ /// (see [JsIrBuilderVisitor.handleConstructorInvoke]).
+ visitRedirectingFactoryBody(ast.RedirectingFactoryBody node) {
+ ConstructorElement targetConstructor =
+ elements.getRedirectingTargetConstructor(node).implementation;
+ ConstructorElement redirectingConstructor =
+ irBuilder.state.currentElement.implementation;
+ List<ir.Primitive> arguments = <ir.Primitive>[];
+ FunctionSignature redirectingSignature =
+ redirectingConstructor.functionSignature;
+ List<String> namedParameters = <String>[];
+ redirectingSignature.forEachParameter((ParameterElement parameter) {
+ arguments.add(irBuilder.environment.lookup(parameter));
+ if (parameter.isNamed) {
+ namedParameters.add(parameter.name);
+ }
+ });
+ ClassElement cls = redirectingConstructor.enclosingClass;
+ InterfaceType targetType =
+ redirectingConstructor.computeEffectiveTargetType(cls.thisType);
+ CallStructure callStructure = new CallStructure(
+ redirectingSignature.parameterCount,
+ namedParameters);
+ arguments = normalizeStaticArguments(callStructure, targetConstructor,
+ arguments);
+ ir.Primitive instance = irBuilder.buildConstructorInvocation(
+ targetConstructor,
+ callStructure,
+ targetType,
+ arguments,
+ sourceInformationBuilder.buildNew(node));
+ irBuilder.buildReturn(
+ value: instance,
+ sourceInformation: sourceInformationBuilder.buildReturn(node));
+ }
+
visitFor(ast.For node) {
List<LocalElement> loopVariables = <LocalElement>[];
if (node.initializer is ast.VariableDefinitions) {
@@ -363,7 +402,9 @@
ir.Primitive visitReturn(ast.Return node) {
assert(irBuilder.isOpen);
assert(invariant(node, node.beginToken.value != 'native'));
- irBuilder.buildReturn(build(node.expression));
+ irBuilder.buildReturn(
+ value: build(node.expression),
+ sourceInformation: sourceInformationBuilder.buildReturn(node));
return null;
}
@@ -497,9 +538,11 @@
return irBuilder.state.constants.getConstantValueForVariable(element);
}
- ir.Primitive buildConstantExpression(ConstantExpression expression) {
+ ir.Primitive buildConstantExpression(ConstantExpression expression,
+ SourceInformation sourceInformation) {
return irBuilder.buildConstant(
- irBuilder.state.constants.getConstantValue(expression));
+ irBuilder.state.constants.getConstantValue(expression),
+ sourceInformation: sourceInformation);
}
ir.Primitive visitLiteralList(ast.LiteralList node) {
@@ -563,7 +606,7 @@
} else {
// The call to assert and its argument expression must be ignored
// in production mode.
- // Assertions can only occur in expression statements, so no value needs
+ // Assertions can onl)y occur in expression statements, so no value needs
// to be returned.
return null;
}
@@ -577,13 +620,15 @@
@override
ir.Primitive visitExpressionInvoke(ast.Send node,
ast.Node expression,
- ast.NodeList arguments,
+ ast.NodeList argumentsNode,
Selector selector, _) {
ir.Primitive receiver = visit(expression);
List<ir.Primitive> arguments = node.arguments.mapToList(visit);
arguments = normalizeDynamicArguments(selector.callStructure, arguments);
return irBuilder.buildCallInvocation(
- receiver, selector.callStructure, arguments);
+ receiver, selector.callStructure, arguments,
+ sourceInformation:
+ sourceInformationBuilder.buildCall(node, argumentsNode));
}
/// Returns `true` if [node] is a super call.
@@ -596,7 +641,8 @@
ir.Primitive handleConstantGet(
ast.Node node,
ConstantExpression constant, _) {
- return buildConstantExpression(constant);
+ return buildConstantExpression(constant,
+ sourceInformationBuilder.buildGet(node));
}
/// If [node] is null, returns this.
@@ -635,7 +681,8 @@
ast.Send node,
ConstantExpression constant,
_) {
- return buildConstantExpression(constant);
+ return buildConstantExpression(constant,
+ sourceInformationBuilder.buildGet(node));
}
@override
@@ -644,7 +691,8 @@
LocalVariableElement element,
_) {
return element.isConst
- ? irBuilder.buildConstant(getConstantForVariable(element))
+ ? irBuilder.buildConstant(getConstantForVariable(element),
+ sourceInformation: sourceInformationBuilder.buildGet(node))
: irBuilder.buildLocalVariableGet(element);
}
@@ -681,7 +729,8 @@
ast.Send node,
FunctionElement getter,
_) {
- return irBuilder.buildStaticGetterGet(getter);
+ return irBuilder.buildStaticGetterGet(
+ getter, sourceInformationBuilder.buildGet(node));
}
@override
@@ -697,7 +746,8 @@
ast.Send node,
FunctionElement getter,
_) {
- return irBuilder.buildSuperGetterGet(getter);
+ return irBuilder.buildSuperGetterGet(
+ getter, sourceInformationBuilder.buildGet(node));
}
@override
@@ -727,14 +777,17 @@
return irBuilder.buildThis();
}
- ir.Primitive translateTypeVariableTypeLiteral(TypeVariableElement element) {
- return irBuilder.buildReifyTypeVariable(element.type);
+ ir.Primitive translateTypeVariableTypeLiteral(
+ TypeVariableElement element,
+ SourceInformation sourceInformation) {
+ return irBuilder.buildReifyTypeVariable(element.type, sourceInformation);
}
@override
ir.Primitive visitTypeVariableTypeLiteralGet(ast.Send node,
TypeVariableElement element, _) {
- return translateTypeVariableTypeLiteral(element);
+ return translateTypeVariableTypeLiteral(element,
+ sourceInformationBuilder.buildGet(node));
}
ir.Primitive translateLogicalOperator(ast.Expression left,
@@ -806,7 +859,9 @@
List<ir.Primitive> arguments = <ir.Primitive>[visit(right)];
arguments = normalizeDynamicArguments(selector.callStructure, arguments);
return irBuilder.buildDynamicInvocation(
- receiver, selector, elements.getTypeMask(node), arguments);
+ receiver, selector, elements.getTypeMask(node), arguments,
+ sourceInformation:
+ sourceInformationBuilder.buildCall(node, node.selector));
}
@override
@@ -943,10 +998,12 @@
ir.Primitive translateCallInvoke(ir.Primitive target,
ast.NodeList arguments,
- CallStructure callStructure) {
+ CallStructure callStructure,
+ SourceInformation sourceInformation) {
return irBuilder.buildCallInvocation(target, callStructure,
- translateDynamicArguments(arguments, callStructure));
+ translateDynamicArguments(arguments, callStructure),
+ sourceInformation: sourceInformation);
}
@override
@@ -956,8 +1013,10 @@
ast.NodeList arguments,
CallStructure callStructure,
_) {
- ir.Primitive target = buildConstantExpression(constant);
- return translateCallInvoke(target, arguments, callStructure);
+ ir.Primitive target = buildConstantExpression(constant,
+ sourceInformationBuilder.buildGet(node));
+ return translateCallInvoke(target, arguments, callStructure,
+ sourceInformationBuilder.buildCall(node, arguments));
}
@override
@@ -969,7 +1028,9 @@
_) {
return irBuilder.buildDynamicInvocation(
translateReceiver(receiver), selector, elements.getTypeMask(node),
- translateDynamicArguments(arguments, selector.callStructure));
+ translateDynamicArguments(arguments, selector.callStructure),
+ sourceInformation:
+ sourceInformationBuilder.buildCall(node, node.selector));
}
@override
@@ -994,7 +1055,9 @@
CallStructure callStructure,
_) {
return irBuilder.buildLocalVariableInvocation(element, callStructure,
- translateDynamicArguments(arguments, callStructure));
+ translateDynamicArguments(arguments, callStructure),
+ callSourceInformation:
+ sourceInformationBuilder.buildCall(node, arguments));
}
@override
@@ -1005,7 +1068,8 @@
CallStructure callStructure,
_) {
return irBuilder.buildLocalFunctionInvocation(function, callStructure,
- translateDynamicArguments(arguments, callStructure));
+ translateDynamicArguments(arguments, callStructure),
+ sourceInformationBuilder.buildCall(node, arguments));
}
@override
@@ -1024,7 +1088,9 @@
ir.Primitive target = buildStaticFieldGet(field, src);
return irBuilder.buildCallInvocation(target,
callStructure,
- translateDynamicArguments(arguments, callStructure));
+ translateDynamicArguments(arguments, callStructure),
+ sourceInformation:
+ sourceInformationBuilder.buildCall(node, arguments));
}
@override
@@ -1056,10 +1122,13 @@
if (compiler.backend.isForeign(getter)) {
return giveup(node, 'handleStaticGetterInvoke: foreign: $getter');
}
- ir.Primitive target = irBuilder.buildStaticGetterGet(getter);
+ ir.Primitive target = irBuilder.buildStaticGetterGet(
+ getter, sourceInformationBuilder.buildGet(node));
return irBuilder.buildCallInvocation(target,
callStructure,
- translateDynamicArguments(arguments, callStructure));
+ translateDynamicArguments(arguments, callStructure),
+ sourceInformation:
+ sourceInformationBuilder.buildCall(node, arguments));
}
@override
@@ -1072,7 +1141,9 @@
ir.Primitive target = irBuilder.buildSuperFieldGet(field);
return irBuilder.buildCallInvocation(target,
callStructure,
- translateDynamicArguments(arguments, callStructure));
+ translateDynamicArguments(arguments, callStructure),
+ sourceInformation:
+ sourceInformationBuilder.buildCall(node, arguments));
}
@override
@@ -1082,10 +1153,13 @@
ast.NodeList arguments,
CallStructure callStructure,
_) {
- ir.Primitive target = irBuilder.buildSuperGetterGet(getter);
+ ir.Primitive target = irBuilder.buildSuperGetterGet(
+ getter, sourceInformationBuilder.buildGet(node));
return irBuilder.buildCallInvocation(target,
callStructure,
- translateDynamicArguments(arguments, callStructure));
+ translateDynamicArguments(arguments, callStructure),
+ sourceInformation:
+ sourceInformationBuilder.buildCall(node, arguments));
}
@override
@@ -1096,7 +1170,9 @@
CallStructure callStructure,
_) {
return irBuilder.buildSuperMethodInvocation(method, callStructure,
- translateDynamicArguments(arguments, callStructure));
+ translateDynamicArguments(arguments, callStructure),
+ sourceInformation:
+ sourceInformationBuilder.buildCall(node, node.selector));
}
@override
@@ -1129,7 +1205,11 @@
ast.NodeList arguments,
CallStructure callStructure,
_) {
- return translateCallInvoke(irBuilder.buildThis(), arguments, callStructure);
+ return translateCallInvoke(
+ irBuilder.buildThis(),
+ arguments,
+ callStructure,
+ sourceInformationBuilder.buildCall(node, arguments));
}
@override
@@ -1140,9 +1220,11 @@
CallStructure callStructure,
_) {
return translateCallInvoke(
- translateTypeVariableTypeLiteral(element),
+ translateTypeVariableTypeLiteral(
+ element, sourceInformationBuilder.buildGet(node)),
arguments,
- callStructure);
+ callStructure,
+ sourceInformationBuilder.buildCall(node, arguments));
}
@override
@@ -1291,7 +1373,10 @@
CompoundRhs rhs,
arg) {
return translateCompounds(
- getValue: () => buildConstantExpression(constant),
+ getValue: () {
+ return buildConstantExpression(constant,
+ sourceInformationBuilder.buildGet(node));
+ },
rhs: rhs,
setValue: (value) {}, // The binary operator will throw before this.
operatorTypeMask: elements.getOperatorTypeMaskInComplexSendSet(node));
@@ -1383,7 +1468,8 @@
SourceInformation src = sourceInformationBuilder.buildGet(node);
return irBuilder.buildStaticFieldGet(getter, src);
case CompoundGetter.GETTER:
- return irBuilder.buildStaticGetterGet(getter);
+ return irBuilder.buildStaticGetterGet(
+ getter, sourceInformationBuilder.buildGet(node));
case CompoundGetter.METHOD:
return irBuilder.buildStaticFunctionGet(getter);
case CompoundGetter.UNRESOLVED:
@@ -1437,7 +1523,8 @@
case CompoundGetter.FIELD:
return irBuilder.buildSuperFieldGet(getter);
case CompoundGetter.GETTER:
- return irBuilder.buildSuperGetterGet(getter);
+ return irBuilder.buildSuperGetterGet(
+ getter, sourceInformationBuilder.buildGet(node));
case CompoundGetter.METHOD:
return irBuilder.buildSuperMethodGet(getter);
case CompoundGetter.UNRESOLVED:
@@ -1469,7 +1556,11 @@
CompoundRhs rhs,
arg) {
return translateCompounds(
- getValue: () => irBuilder.buildReifyTypeVariable(typeVariable.type),
+ getValue: () {
+ return irBuilder.buildReifyTypeVariable(
+ typeVariable.type,
+ sourceInformationBuilder.buildGet(node));
+ },
rhs: rhs,
setValue: (value) {}, // The binary operator will throw before this.
operatorTypeMask: elements.getOperatorTypeMaskInComplexSendSet(node));
@@ -1585,7 +1676,9 @@
ir.Primitive translateConstant(ast.Node node) {
assert(irBuilder.isOpen);
- return irBuilder.buildConstant(getConstantForNode(node));
+ return irBuilder.buildConstant(
+ getConstantForNode(node),
+ sourceInformation: sourceInformationBuilder.buildGet(node));
}
ir.Primitive visitThrow(ast.Throw node) {
@@ -2219,13 +2312,15 @@
}
ir.Primitive visitFunctionExpression(ast.FunctionExpression node) {
- return irBuilder.buildFunctionExpression(makeSubFunction(node));
+ return irBuilder.buildFunctionExpression(makeSubFunction(node),
+ sourceInformationBuilder.buildCreate(node));
}
visitFunctionDeclaration(ast.FunctionDeclaration node) {
LocalFunctionElement element = elements[node.function];
Object inner = makeSubFunction(node.function);
- irBuilder.declareLocalFunction(element, inner);
+ irBuilder.declareLocalFunction(element, inner,
+ sourceInformationBuilder.buildCreate(node.function));
}
Map mapValues(Map map, dynamic fn(dynamic)) {
@@ -2340,7 +2435,12 @@
return withBuilder(builder, () {
irBuilder.buildFunctionHeader(<Local>[]);
ir.Primitive initialValue = visit(element.initializer);
- irBuilder.buildReturn(initialValue);
+ ast.VariableDefinitions node = element.node;
+ ast.SendSet sendSet = node.definitions.nodes.head;
+ irBuilder.buildReturn(
+ value: initialValue,
+ sourceInformation:
+ sourceInformationBuilder.buildReturn(sendSet.assignmentOperator));
return irBuilder.makeFunctionDefinition();
});
}
@@ -2465,10 +2565,16 @@
// Native fields are initialized elsewhere.
}
}, includeSuperAndInjectedMembers: true);
+
ir.Primitive instance = new ir.CreateInstance(
classElement,
instanceArguments,
- typeInformation);
+ typeInformation,
+ constructor.hasNode
+ ? sourceInformationBuilder.buildCreate(constructor.node)
+ // TODO(johnniwinther): Provide source information for creation
+ // through synthetic constructors.
+ : null);
irBuilder.add(new ir.LetPrim(instance));
// --- Call constructor bodies ---
@@ -2483,7 +2589,10 @@
}
// --- step 4: return the created object ----
- irBuilder.buildReturn(instance);
+ irBuilder.buildReturn(
+ value: instance,
+ sourceInformation:
+ sourceInformationBuilder.buildImplicitReturn(constructor));
return irBuilder.makeFunctionDefinition();
});
@@ -2938,7 +3047,8 @@
target,
callStructure,
constructor.computeEffectiveTargetType(type),
- arguments);
+ arguments,
+ sourceInformationBuilder.buildNew(node));
}
@override
@@ -2991,7 +3101,7 @@
ir.Primitive buildStaticFieldGet(FieldElement field, SourceInformation src) {
ConstantValue constant = getConstantForVariable(field);
if (constant != null && !field.isAssignable) {
- return irBuilder.buildConstant(constant);
+ return irBuilder.buildConstant(constant, sourceInformation: src);
} else if (backend.constants.lazyStatics.contains(field)) {
return irBuilder.buildStaticFieldLazyGet(field, src);
} else {
@@ -3186,16 +3296,16 @@
if (!compiler.hasIsolateSupport) {
// If the isolate library is not used, we just generate code
// to fetch the current isolate.
- continue GET_CURRENT_ISOLATE;
+ continue GET_STATIC_STATE;
}
return buildIsolateHelperInvocation('_currentIsolate',
CallStructure.NO_ARGS);
- GET_CURRENT_ISOLATE: case 'JS_CURRENT_ISOLATE':
+ GET_STATIC_STATE: case 'JS_GET_STATIC_STATE':
validateArgumentCount(exactly: 0);
return irBuilder.buildForeignCode(
- js.js.parseForeignJS(backend.namer.currentIsolate),
+ js.js.parseForeignJS(backend.namer.staticStateHolder),
const <ir.Primitive>[],
NativeBehavior.PURE);
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
index 29d324e..8c5bf34 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
@@ -128,6 +128,17 @@
}
if (next != null) next.previous = previous;
}
+
+ /// Changes the definition referenced by this object and updates
+ /// the reference chains accordingly.
+ void changeTo(Definition<T> newDefinition) {
+ unlink();
+ previous = null;
+ definition = newDefinition;
+ next = definition.firstRef;
+ if (next != null) next.previous = this;
+ definition.firstRef = this;
+ }
}
/// Evaluates a primitive and binds it to variable: `let val x = V in E`.
@@ -344,12 +355,14 @@
final Selector selector;
final List<Reference<Primitive>> arguments;
final Reference<Continuation> continuation;
+ final SourceInformation sourceInformation;
InvokeMethodDirectly(Primitive receiver,
this.target,
this.selector,
List<Primitive> arguments,
- Continuation continuation)
+ Continuation continuation,
+ this.sourceInformation)
: this.receiver = new Reference<Primitive>(receiver),
this.arguments = _referenceList(arguments),
this.continuation = new Reference<Continuation>(continuation);
@@ -378,12 +391,14 @@
final List<Reference<Primitive>> arguments;
final Reference<Continuation> continuation;
final Selector selector;
+ final SourceInformation sourceInformation;
InvokeConstructor(this.type,
this.target,
this.selector,
List<Primitive> args,
- Continuation cont)
+ Continuation cont,
+ this.sourceInformation)
: arguments = _referenceList(args),
continuation = new Reference<Continuation>(cont);
@@ -563,6 +578,7 @@
class InvokeContinuation extends Expression {
Reference<Continuation> continuation;
List<Reference<Primitive>> arguments;
+ SourceInformation sourceInformation;
// An invocation of a continuation is recursive if it occurs in the body of
// the continuation itself.
@@ -574,7 +590,8 @@
InvokeContinuation(Continuation cont, List<Primitive> args,
{this.isRecursive: false,
- this.isEscapingTry: false})
+ this.isEscapingTry: false,
+ this.sourceInformation})
: continuation = new Reference<Continuation>(cont),
arguments = _referenceList(args) {
assert(cont.parameters == null || cont.parameters.length == args.length);
@@ -586,10 +603,11 @@
///
/// Used as a placeholder for a jump whose target is not yet created
/// (e.g., in the translation of break and continue).
- InvokeContinuation.uninitialized({this.isRecursive: false,
+ InvokeContinuation.uninitialized({this.isRecursive: false,
this.isEscapingTry: false})
: continuation = null,
- arguments = null;
+ arguments = null,
+ sourceInformation = null;
accept(Visitor visitor) => visitor.visitInvokeContinuation(this);
}
@@ -661,6 +679,62 @@
bool get isSafeForReordering => objectIsNotNull && field.isFinal;
}
+/// Get the length of a native list.
+class GetLength extends Primitive {
+ final Reference<Primitive> object;
+
+ /// True if the object is known not to be null.
+ bool objectIsNotNull = false;
+
+ GetLength(Primitive object) : this.object = new Reference<Primitive>(object);
+
+ bool get isSafeForElimination => objectIsNotNull;
+ bool get isSafeForReordering => false;
+
+ accept(Visitor v) => v.visitGetLength(this);
+}
+
+/// Read an entry from a native list.
+///
+/// [object] must be null or a native list, and [index] must be an integer.
+class GetIndex extends Primitive {
+ final Reference<Primitive> object;
+ final Reference<Primitive> index;
+
+ /// True if the object is known not to be null.
+ bool objectIsNotNull = false;
+
+ GetIndex(Primitive object, Primitive index)
+ : this.object = new Reference<Primitive>(object),
+ this.index = new Reference<Primitive>(index);
+
+ bool get isSafeForElimination => objectIsNotNull;
+ bool get isSafeForReordering => false;
+
+ accept(Visitor v) => v.visitGetIndex(this);
+}
+
+/// Set an entry on a native list.
+///
+/// [object] must be null or a native list, and [index] must be an integer.
+///
+/// The primitive itself has no value and may not be referenced.
+class SetIndex extends Primitive {
+ final Reference<Primitive> object;
+ final Reference<Primitive> index;
+ final Reference<Primitive> value;
+
+ SetIndex(Primitive object, Primitive index, Primitive value)
+ : this.object = new Reference<Primitive>(object),
+ this.index = new Reference<Primitive>(index),
+ this.value = new Reference<Primitive>(value);
+
+ bool get isSafeForElimination => false;
+ bool get isSafeForReordering => false;
+
+ accept(Visitor v) => v.visitSetIndex(this);
+}
+
/// Reads the value of a static field or tears off a static method.
///
/// Note that lazily initialized fields should be read using GetLazyStatic.
@@ -672,7 +746,7 @@
GetStatic(this.element, [this.sourceInformation]);
accept(Visitor visitor) => visitor.visitGetStatic(this);
-
+
bool get isSafeForElimination {
return true;
}
@@ -742,8 +816,11 @@
/// is not needed at runtime.
final List<Reference<Primitive>> typeInformation;
+ final SourceInformation sourceInformation;
+
CreateInstance(this.classElement, List<Primitive> arguments,
- List<Primitive> typeInformation)
+ List<Primitive> typeInformation,
+ this.sourceInformation)
: this.arguments = _referenceList(arguments),
this.typeInformation = _referenceList(typeInformation);
@@ -800,8 +877,9 @@
class Constant extends Primitive {
final values.ConstantValue value;
+ final SourceInformation sourceInformation;
- Constant(this.value);
+ Constant(this.value, {this.sourceInformation});
accept(Visitor visitor) => visitor.visitConstant(this);
@@ -903,7 +981,7 @@
Continuation(this.parameters, {this.isRecursive: false});
- Continuation.retrn()
+ Continuation.retrn()
: parameters = <Parameter>[new Parameter(null)],
isRecursive = false;
@@ -945,7 +1023,10 @@
/// Reference to the internal representation of a type (as produced, for
/// example, by [ReadTypeVariable]).
final Reference<Primitive> value;
- ReifyRuntimeType(Primitive value)
+
+ final SourceInformation sourceInformation;
+
+ ReifyRuntimeType(Primitive value, this.sourceInformation)
: this.value = new Reference<Primitive>(value);
@override
@@ -963,8 +1044,9 @@
class ReadTypeVariable extends Primitive {
final TypeVariableType variable;
final Reference<Primitive> target;
+ final SourceInformation sourceInformation;
- ReadTypeVariable(this.variable, Primitive target)
+ ReadTypeVariable(this.variable, Primitive target, this.sourceInformation)
: this.target = new Reference<Primitive>(target);
@override
@@ -1052,6 +1134,9 @@
T visitCreateInvocationMirror(CreateInvocationMirror node);
T visitTypeTest(TypeTest node);
T visitApplyBuiltinOperator(ApplyBuiltinOperator node);
+ T visitGetLength(GetLength node);
+ T visitGetIndex(GetIndex node);
+ T visitSetIndex(SetIndex node);
// Conditions.
T visitIsTrue(IsTrue node);
@@ -1342,6 +1427,27 @@
visitUnreachable(Unreachable node) {
processUnreachable(node);
}
+
+ processGetLength(GetLength node) {}
+ visitGetLength(GetLength node) {
+ processGetLength(node);
+ processReference(node.object);
+ }
+
+ processGetIndex(GetIndex node) {}
+ visitGetIndex(GetIndex node) {
+ processGetIndex(node);
+ processReference(node.object);
+ processReference(node.index);
+ }
+
+ processSetIndex(SetIndex node) {}
+ visitSetIndex(SetIndex node) {
+ processSetIndex(node);
+ processReference(node.object);
+ processReference(node.index);
+ processReference(node.value);
+ }
}
/// Visit a just-deleted subterm and unlink all [Reference]s in it.
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
index 528edc2..e200071 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
@@ -340,6 +340,27 @@
: ' ${access(node.continuation)}';
return '(JS ${node.type} ${node.codeTemplate} ($arguments)$continuation)';
}
+
+ @override
+ String visitGetLength(GetLength node) {
+ String object = access(node.object);
+ return '(GetLength $object)';
+ }
+
+ @override
+ String visitGetIndex(GetIndex node) {
+ String object = access(node.object);
+ String index = access(node.index);
+ return '(GetIndex $object $index)';
+ }
+
+ @override
+ String visitSetIndex(SetIndex node) {
+ String object = access(node.object);
+ String index = access(node.index);
+ String value = access(node.value);
+ return '(SetIndex $object $index $value)';
+ }
}
class ConstantStringifier extends ConstantValueVisitor<String, Null> {
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
index 1c5adcf..0064b6b 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
@@ -110,10 +110,8 @@
visitLetCont(cps_ir.LetCont node) {
if (IR_TRACE_LET_CONT) {
String dummy = names.name(node);
- for (cps_ir.Continuation continuation in node.continuations) {
- String id = names.name(continuation);
- printStmt(dummy, "LetCont $id = <$id>");
- }
+ String ids = node.continuations.map(names.name).join(', ');
+ printStmt(dummy, "LetCont $ids");
}
visit(node.body);
}
@@ -192,20 +190,18 @@
}
visitLiteralList(cps_ir.LiteralList node) {
- String dummy = names.name(node);
String values = node.values.map(formatReference).join(', ');
- printStmt(dummy, "LiteralList ($values)");
+ return "LiteralList ($values)";
}
visitLiteralMap(cps_ir.LiteralMap node) {
- String dummy = names.name(node);
List<String> entries = new List<String>();
for (cps_ir.LiteralMapEntry entry in node.entries) {
String key = formatReference(entry.key);
String value = formatReference(entry.value);
entries.add("$key: $value");
}
- printStmt(dummy, "LiteralMap (${entries.join(', ')})");
+ return "LiteralMap (${entries.join(', ')})";
}
visitTypeCast(cps_ir.TypeCast node) {
@@ -374,6 +370,24 @@
printStmt(id, "ForeignCode ${node.type} ${node.codeTemplate.source} "
"$arguments $continuation");
}
+
+ visitGetLength(cps_ir.GetLength node) {
+ String object = formatReference(node.object);
+ return 'GetLength $object';
+ }
+
+ visitGetIndex(cps_ir.GetIndex node) {
+ String object = formatReference(node.object);
+ String index = formatReference(node.index);
+ return 'GetIndex $object $index';
+ }
+
+ visitSetIndex(cps_ir.SetIndex node) {
+ String object = formatReference(node.object);
+ String index = formatReference(node.index);
+ String value = formatReference(node.value);
+ return 'SetIndex $object $index $value';
+ }
}
/**
@@ -633,6 +647,18 @@
unexpectedNode(node);
}
+ visitGetLength(cps_ir.GetLength node) {
+ unexpectedNode(node);
+ }
+
+ visitGetIndex(cps_ir.GetIndex node) {
+ unexpectedNode(node);
+ }
+
+ visitSetIndex(cps_ir.SetIndex node) {
+ unexpectedNode(node);
+ }
+
@override
visitForeignCode(cps_ir.ForeignCode node) {
if (node.continuation != null) {
diff --git a/pkg/compiler/lib/src/cps_ir/optimizers.dart b/pkg/compiler/lib/src/cps_ir/optimizers.dart
index c80dfb0..3b48349 100644
--- a/pkg/compiler/lib/src/cps_ir/optimizers.dart
+++ b/pkg/compiler/lib/src/cps_ir/optimizers.dart
@@ -5,9 +5,11 @@
library dart2js.cps_ir.optimizers;
import 'cps_ir_nodes.dart';
+import '../constants/values.dart';
export 'type_propagation.dart' show TypePropagator;
export 'redundant_phi.dart' show RedundantPhiEliminator;
+export 'redundant_join.dart' show RedundantJoinEliminator;
export 'shrinking_reductions.dart' show ShrinkingReducer, ParentVisitor;
/// An optimization pass over the CPS IR.
@@ -17,3 +19,15 @@
String get passName;
}
+
+// Shared code between optimizations
+
+/// Returns true if [value] is false, null, 0, -0, NaN, or the empty string.
+bool isFalsyConstant(ConstantValue value) {
+ return value.isFalse ||
+ value.isNull ||
+ value.isZero ||
+ value.isMinusZero ||
+ value.isNaN ||
+ value is StringConstantValue && value.primitiveValue.isEmpty;
+}
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_join.dart b/pkg/compiler/lib/src/cps_ir/redundant_join.dart
new file mode 100644
index 0000000..92bd51b
--- /dev/null
+++ b/pkg/compiler/lib/src/cps_ir/redundant_join.dart
@@ -0,0 +1,276 @@
+// 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.cps_ir.redundant_join_elimination;
+
+import 'cps_ir_nodes.dart';
+import 'optimizers.dart';
+
+/// Eliminates redundant join points.
+///
+/// A redundant join point is a continuation that immediately branches
+/// based on one of its parameters, and that parameter is a constant value
+/// at every invocation. Each invocation is redirected to jump directly
+/// to the branch target.
+///
+/// Internally in this pass, parameters are treated as names with lexical
+/// scoping, and a given parameter "name" may be declared by more than
+/// one continuation. The reference chains for parameters are therefore
+/// meaningless during this pass, until repaired by [AlphaRenamer] at
+/// the end.
+class RedundantJoinEliminator extends RecursiveVisitor implements Pass {
+ String get passName => 'Redundant join elimination';
+
+ final Set<Branch> workSet = new Set<Branch>();
+
+ void rewrite(FunctionDefinition node) {
+ visit(node);
+
+ while (workSet.isNotEmpty) {
+ Branch branch = workSet.first;
+ workSet.remove(branch);
+ rewriteBranch(branch);
+ }
+
+ new AlphaRenamer().visit(node);
+ }
+
+ void processBranch(Branch node) {
+ workSet.add(node);
+ }
+
+ /// Returns the body of [node], ignoring all LetCont nodes.
+ Expression getEffectiveBody(InteriorNode node) {
+ while (true) {
+ Expression body = node.body;
+ if (body is LetCont) {
+ node = body;
+ } else {
+ return body;
+ }
+ }
+ }
+
+ /// Returns the parent of [node], ignoring all LetCont nodes.
+ InteriorNode getEffectiveParent(Expression node) {
+ while (true) {
+ Node parent = node.parent;
+ if (parent is LetCont) {
+ node = parent;
+ } else {
+ return parent;
+ }
+ }
+ }
+
+ /// Removes [movedNode] from its current position and inserts it
+ /// before [target].
+ void moveToBefore(Expression target, LetCont movedNode) {
+ if (movedNode.parent != null) {
+ movedNode.parent.body = movedNode.body;
+ movedNode.body.parent = movedNode.parent;
+ }
+ InteriorNode parent = target.parent;
+ parent.body = movedNode;
+ movedNode.body = target;
+ target.parent = movedNode;
+ movedNode.parent = parent;
+ }
+
+ void rewriteBranch(Branch branch) {
+ InteriorNode parent = getEffectiveParent(branch);
+ if (parent is! Continuation) return;
+ Continuation branchCont = parent;
+
+ // Other optimizations take care of single-use continuations.
+ if (!branchCont.hasMultipleUses) return;
+
+ // It might be beneficial to rewrite calls to recursive continuations,
+ // but we currently do not support this.
+ if (branchCont.isRecursive) return;
+
+ // Check that the branching condition is a parameter on the
+ // enclosing continuation.
+ // Note: Do not use the parent pointer for this check, because parameters
+ // are temporarily shared between different continuations during this pass.
+ IsTrue isTrue = branch.condition;
+ Primitive condition = isTrue.value.definition;
+ int parameterIndex = branchCont.parameters.indexOf(condition);
+ if (parameterIndex == -1) return;
+
+ // Check that all callers hit a fixed branch, and count the number
+ // of times each branch is hit.
+ // We know all callers are InvokeContinuations because they are the only
+ // valid uses of a multi-use continuation.
+ int trueHits = 0, falseHits = 0;
+ InvokeContinuation trueCall, falseCall;
+ for (Reference ref = branchCont.firstRef; ref != null; ref = ref.next) {
+ InvokeContinuation invoke = ref.parent;
+ Primitive argument = invoke.arguments[parameterIndex].definition;
+ if (argument is! Constant) return; // Branching condition is unknown.
+ Constant constant = argument;
+ if (isFalsyConstant(constant.value)) {
+ ++falseHits;
+ falseCall = invoke;
+ } else {
+ ++trueHits;
+ trueCall = invoke;
+ }
+ }
+
+ // The optimization is now known to be safe, but it only pays off if
+ // one of the callers can inline its target, since otherwise we end up
+ // replacing a boolean variable with a labeled break.
+ // TODO(asgerf): The labeled break might be better? Evaluate.
+ if (!(trueHits == 1 && !trueCall.isEscapingTry ||
+ falseHits == 1 && !falseCall.isEscapingTry)) {
+ return;
+ }
+
+ // Lift any continuations bound inside branchCont so they are in scope at
+ // the call sites. When lifting, the parameters of branchCont fall out of
+ // scope, so they are added as parameters on each lifted continuation.
+ // Schematically:
+ //
+ // (LetCont (branchCont (x1, x2, x3) =
+ // (LetCont (innerCont (y) = ...) in
+ // [... innerCont(y') ...]))
+ //
+ // =>
+ //
+ // (LetCont (innerCont (y, x1, x2, x3) = ...) in
+ // (LetCont (branchCont (x1, x2, x3) =
+ // [... innerCont(y', x1, x2, x3) ...])
+ //
+ // Parameter objects become shared between branchCont and the lifted
+ // continuations. [AlphaRenamer] will clean up at the end of this pass.
+ LetCont outerLetCont = branchCont.parent;
+ while (branchCont.body is LetCont) {
+ LetCont innerLetCont = branchCont.body;
+ for (Continuation innerCont in innerLetCont.continuations) {
+ innerCont.parameters.addAll(branchCont.parameters);
+ for (Reference ref = innerCont.firstRef; ref != null; ref = ref.next) {
+ Expression use = ref.parent;
+ if (use is InvokeContinuation) {
+ for (Parameter param in branchCont.parameters) {
+ use.arguments.add(new Reference<Primitive>(param));
+ }
+ } else {
+ // The branch will be eliminated, so don't worry about updating it.
+ assert(use == branch);
+ }
+ }
+ }
+ moveToBefore(outerLetCont, innerLetCont);
+ }
+
+ assert(branchCont.body == branch);
+
+ Continuation trueCont = branch.trueContinuation.definition;
+ Continuation falseCont = branch.falseContinuation.definition;
+
+ assert(branchCont != trueCont);
+ assert(branchCont != falseCont);
+
+ // Rewrite every invocation of branchCont to call either the true or false
+ // branch directly. Since these were lifted out above branchCont, they are
+ // now in scope.
+ // Since trueCont and falseCont were branch targets, they originally
+ // had no parameters, and so after the lifting, their parameters are
+ // exactly the same as those accepted by branchCont.
+ while (branchCont.firstRef != null) {
+ Reference reference = branchCont.firstRef;
+ InvokeContinuation invoke = branchCont.firstRef.parent;
+ Constant condition = invoke.arguments[parameterIndex].definition;
+ if (isFalsyConstant(condition.value)) {
+ invoke.continuation.changeTo(falseCont);
+ } else {
+ invoke.continuation.changeTo(trueCont);
+ }
+ assert(branchCont.firstRef != reference);
+ }
+
+ // Remove the now-unused branchCont continuation.
+ assert(branchCont.hasNoUses);
+ branch.trueContinuation.unlink();
+ branch.falseContinuation.unlink();
+ outerLetCont.continuations.remove(branchCont);
+ if (outerLetCont.continuations.isEmpty) {
+ InteriorNode parent = outerLetCont.parent;
+ parent.body = outerLetCont.body;
+ outerLetCont.body.parent = parent;
+ }
+
+ // We may have created new redundant join points in the two branches.
+ enqueueContinuation(trueCont);
+ enqueueContinuation(falseCont);
+ }
+
+ void enqueueContinuation(Continuation cont) {
+ Expression body = getEffectiveBody(cont);
+ if (body is Branch) {
+ workSet.add(body);
+ }
+ }
+}
+
+/// Ensures parameter objects are not shared between different continuations,
+/// akin to alpha-renaming variables so every variable is named uniquely.
+/// For example:
+///
+/// LetCont (k1 x = (return x)) in
+/// LetCont (k2 x = (InvokeContinuation k3 x)) in ...
+/// =>
+/// LetCont (k1 x = (return x)) in
+/// LetCont (k2 x' = (InvokeContinuation k3 x')) in ...
+///
+/// After lifting LetConts in the main pass above, parameter objects can have
+/// multiple bindings. Each reference implicitly refers to the binding that
+/// is currently in scope.
+///
+/// This returns the IR to its normal form after redundant joins have been
+/// eliminated.
+class AlphaRenamer extends RecursiveVisitor {
+ Map<Parameter, Parameter> renaming = <Parameter, Parameter>{};
+
+ visitContinuation(Continuation cont) {
+ if (cont.isReturnContinuation) return;
+
+ List<Parameter> shadowedKeys = <Parameter>[];
+ List<Parameter> shadowedValues = <Parameter>[];
+
+ // Create new parameters and update the environment.
+ for (int i = 0; i < cont.parameters.length; ++i) {
+ Parameter param = cont.parameters[i];
+ shadowedKeys.add(param);
+ shadowedValues.add(renaming.remove(param));
+ // If the parameter appears to belong to another continuation,
+ // create a new parameter object for this continuation.
+ if (param.parent != cont) {
+ Parameter newParam = new Parameter(param.hint);
+ renaming[param] = newParam;
+ cont.parameters[i] = newParam;
+ newParam.parent = cont;
+ }
+ }
+
+ // Visit the body with the updated environment.
+ visit(cont.body);
+
+ // Restore the original environment.
+ for (int i = 0; i < cont.parameters.length; ++i) {
+ renaming.remove(cont.parameters[i]);
+ if (shadowedValues[i] != null) {
+ renaming[shadowedKeys[i]] = shadowedValues[i];
+ }
+ }
+ }
+
+ processReference(Reference ref) {
+ Parameter target = renaming[ref.definition];
+ if (target != null) {
+ ref.changeTo(target);
+ }
+ }
+}
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_phi.dart b/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
index 1f40c03..e678a96 100644
--- a/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
+++ b/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
@@ -152,7 +152,7 @@
// invokes, and all such invokes must be within the scope of
// [uniqueDefinition]. Note that this is linear in the depth of
// the binding of [uniqueDefinition].
- assert(letCont != null);
+ letCont = _makeUniqueBinding(cont);
_moveIntoScopeOf(letCont, uniqueDefinition);
}
@@ -201,3 +201,19 @@
binding.body = letCont;
letCont.parent = binding;
}
+
+/// Ensures [continuation] has its own LetCont binding by creating
+/// a new LetCont below its current binding, if necessary.
+///
+/// Returns the LetCont that now binds [continuation].
+LetCont _makeUniqueBinding(Continuation continuation) {
+ LetCont letCont = continuation.parent;
+ if (letCont.continuations.length == 1) return letCont;
+ letCont.continuations.remove(continuation);
+ LetCont newBinding = new LetCont(continuation, letCont.body);
+ newBinding.body.parent = newBinding;
+ newBinding.parent = letCont;
+ letCont.body = newBinding;
+ continuation.parent = newBinding;
+ return newBinding;
+}
diff --git a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
index fb62a72..f1970de 100644
--- a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
+++ b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
@@ -676,6 +676,21 @@
}
node.arguments.forEach((Reference ref) => ref.parent = node);
}
+
+ processGetLength(GetLength node) {
+ node.object.parent = node;
+ }
+
+ processGetIndex(GetIndex node) {
+ node.object.parent = node;
+ node.index.parent = node;
+ }
+
+ processSetIndex(SetIndex node) {
+ node.object.parent = node;
+ node.index.parent = node;
+ node.value.parent = node;
+ }
}
class _ReductionKind {
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index 091ca53..50b77b1 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.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.
-import 'optimizers.dart' show Pass, ParentVisitor;
+import 'optimizers.dart';
import '../constants/constant_system.dart';
import '../resolution/operators.dart';
@@ -17,6 +17,8 @@
import '../dart2jslib.dart' show ClassWorld, World;
import '../universe/universe.dart';
import '../js_backend/js_backend.dart' show JavaScriptBackend;
+import '../io/source_information.dart' show SourceInformation;
+import 'cps_fragment.dart';
enum AbstractBool {
True, False, Maybe, Nothing
@@ -25,6 +27,7 @@
class TypeMaskSystem {
final TypesTask inferrer;
final World classWorld;
+ final JavaScriptBackend backend;
TypeMask get dynamicType => inferrer.dynamicType;
TypeMask get typeType => inferrer.typeType;
@@ -37,13 +40,15 @@
TypeMask get listType => inferrer.listType;
TypeMask get mapType => inferrer.mapType;
TypeMask get nonNullType => inferrer.nonNullType;
+ TypeMask get mutableNativeListType => backend.mutableArrayType;
TypeMask numStringBoolType;
// TODO(karlklose): remove compiler here.
TypeMaskSystem(dart2js.Compiler compiler)
: inferrer = compiler.typesTask,
- classWorld = compiler.world {
+ classWorld = compiler.world,
+ backend = compiler.backend {
numStringBoolType =
new TypeMask.unionOf(<TypeMask>[numType, stringType, boolType],
classWorld);
@@ -137,6 +142,26 @@
return areDisjoint(t, doubleType);
}
+ bool isDefinitelyInt(TypeMask t, {bool allowNull: false}) {
+ if (!allowNull && t.isNullable) return false;
+ return t.satisfies(backend.jsIntClass, classWorld);
+ }
+
+ bool isDefinitelyNativeList(TypeMask t, {bool allowNull: false}) {
+ if (!allowNull && t.isNullable) return false;
+ return t.satisfies(backend.jsArrayClass, classWorld);
+ }
+
+ bool isDefinitelyMutableNativeList(TypeMask t, {bool allowNull: false}) {
+ if (!allowNull && t.isNullable) return false;
+ return t.satisfies(backend.jsMutableArrayClass, classWorld);
+ }
+
+ bool isDefinitelyFixedNativeList(TypeMask t, {bool allowNull: false}) {
+ if (!allowNull && t.isNullable) return false;
+ return t.satisfies(backend.jsFixedArrayClass, classWorld);
+ }
+
bool areDisjoint(TypeMask leftType, TypeMask rightType) {
TypeMask intersection = leftType.intersection(rightType, classWorld);
return intersection.isEmpty && !intersection.isNullable;
@@ -265,6 +290,32 @@
typeSystem.isDefinitelyNotNonIntegerDouble(value.type);
}
+ bool isDefinitelyInt(AbstractValue value,
+ {bool allowNull: false}) {
+ return value.isNothing ||
+ typeSystem.isDefinitelyInt(value.type, allowNull: allowNull);
+ }
+
+ bool isDefinitelyNativeList(AbstractValue value,
+ {bool allowNull: false}) {
+ return value.isNothing ||
+ typeSystem.isDefinitelyNativeList(value.type, allowNull: allowNull);
+ }
+
+ bool isDefinitelyMutableNativeList(AbstractValue value,
+ {bool allowNull: false}) {
+ return value.isNothing ||
+ typeSystem.isDefinitelyMutableNativeList(value.type,
+ allowNull: allowNull);
+ }
+
+ bool isDefinitelyFixedNativeList(AbstractValue value,
+ {bool allowNull: false}) {
+ return value.isNothing ||
+ typeSystem.isDefinitelyFixedNativeList(value.type,
+ allowNull: allowNull);
+ }
+
/// Returns whether the given [value] is an instance of [type].
///
/// Since [value] and [type] are not always known, [AbstractBool.Maybe] is
@@ -357,7 +408,19 @@
if (result == null) return anything;
return constant(result);
}
- return null; // TODO(asgerf): Look up type?
+ // TODO(asgerf): Handle remaining operators and the UIntXX types.
+ switch (operator.kind) {
+ case BinaryOperatorKind.ADD:
+ case BinaryOperatorKind.SUB:
+ case BinaryOperatorKind.MUL:
+ if (isDefinitelyInt(left) && isDefinitelyInt(right)) {
+ return nonConstant(typeSystem.intType);
+ }
+ return null;
+
+ default:
+ return null; // The caller will use return type from type inference.
+ }
}
AbstractValue stringConstant(String value) {
@@ -380,22 +443,13 @@
}
}
- bool isEmptyString(ConstantValue value) {
- return value is StringConstantValue && value.primitiveValue.isEmpty;
- }
-
/// Returns whether [value] is one of the falsy values: false, 0, -0, NaN,
/// the empty string, or null.
AbstractBool boolify(AbstractValue value) {
if (value.isNothing) return AbstractBool.Nothing;
if (value.isConstant) {
ConstantValue constantValue = value.constant;
- if (constantValue.isFalse ||
- constantValue.isNull ||
- constantValue.isZero ||
- constantValue.isMinusZero ||
- constantValue.isNaN ||
- isEmptyString(constantValue)) {
+ if (isFalsyConstant(constantValue)) {
return AbstractBool.False;
} else {
return AbstractBool.True;
@@ -544,6 +598,30 @@
reanalyze(replacement);
}
+ /// Inserts [insertedCode] before [node].
+ ///
+ /// [node] will end up in the hole of [insertedCode], and [insertedCode]
+ /// will become rooted where [node] was.
+ void insertBefore(Expression node, CpsFragment insertedCode) {
+ if (insertedCode.isEmpty) return; // Nothing to do.
+ assert(insertedCode.isOpen);
+ InteriorNode parent = node.parent;
+ InteriorNode context = insertedCode.context;
+
+ parent.body = insertedCode.root;
+ insertedCode.root.parent = parent;
+
+ // We want to recompute the types for [insertedCode] without
+ // traversing the entire subtree of [node]. Temporarily close the
+ // term with a dummy node while recomputing types.
+ context.body = new Unreachable();
+ new ParentVisitor().visit(insertedCode.root);
+ reanalyze(insertedCode.root);
+
+ context.body = node;
+ node.parent = context;
+ }
+
/// Make a constant primitive for [constant] and set its entry in [values].
Constant makeConstantPrimitive(ConstantValue constant) {
Constant primitive = new Constant(constant);
@@ -764,6 +842,339 @@
}
}
+ /// Create a check that throws if [index] is not a valid index on [list].
+ ///
+ /// This function assumes that [index] is an integer.
+ ///
+ /// Returns a CPS fragment whose context is the branch where no error
+ /// was thrown.
+ CpsFragment makeBoundsCheck(Primitive list,
+ Primitive index,
+ SourceInformation sourceInfo) {
+ CpsFragment cps = new CpsFragment(sourceInfo);
+ Continuation fail = cps.letCont();
+ Primitive isTooSmall = cps.applyBuiltin(
+ BuiltinOperator.NumLt,
+ <Primitive>[index, cps.makeZero()]);
+ cps.ifTrue(isTooSmall).invokeContinuation(fail);
+ Primitive isTooLarge = cps.applyBuiltin(
+ BuiltinOperator.NumGe,
+ <Primitive>[index, cps.letPrim(new GetLength(list))]);
+ cps.ifTrue(isTooLarge).invokeContinuation(fail);
+ cps.insideContinuation(fail).invokeStaticThrower(
+ backend.getThrowIndexOutOfBoundsError(),
+ <Primitive>[list, index]);
+ return cps;
+ }
+
+ /// Create a check that throws if the length of [list] is not equal to
+ /// [originalLength].
+ ///
+ /// Returns a CPS fragment whose context is the branch where no error
+ /// was thrown.
+ CpsFragment makeConcurrentModificationCheck(Primitive list,
+ Primitive originalLength,
+ SourceInformation sourceInfo) {
+ CpsFragment cps = new CpsFragment(sourceInfo);
+ Primitive lengthChanged = cps.applyBuiltin(
+ BuiltinOperator.StrictNeq,
+ <Primitive>[originalLength, cps.letPrim(new GetLength(list))]);
+ cps.ifTrue(lengthChanged).invokeStaticThrower(
+ backend.getThrowConcurrentModificationError(),
+ <Primitive>[list]);
+ return cps;
+ }
+
+ /// Counts number of index accesses on [list] and determines based on
+ /// that number if we should try to inline them.
+ ///
+ /// This is a short-term solution to avoid inserting a lot of bounds checks,
+ /// since there is currently no optimization for eliminating them.
+ bool hasTooManyIndexAccesses(Primitive list) {
+ int count = 0;
+ for (Reference ref = list.firstRef; ref != null; ref = ref.next) {
+ Node use = ref.parent;
+ if (use is InvokeMethod &&
+ (use.selector.isIndex || use.selector.isIndexSet) &&
+ getDartReceiver(use) == list) {
+ ++count;
+ } else if (use is GetIndex && use.object.definition == list) {
+ ++count;
+ } else if (use is SetIndex && use.object.definition == list) {
+ ++count;
+ }
+ if (count > 2) return true;
+ }
+ return false;
+ }
+
+ /// Tries to replace [node] with one or more direct array access operations.
+ ///
+ /// Returns `true` if the node was replaced.
+ bool specializeArrayAccess(InvokeMethod node) {
+ Primitive list = getDartReceiver(node);
+ AbstractValue listValue = getValue(list);
+ // Ensure that the object is a native list or null.
+ if (!lattice.isDefinitelyNativeList(listValue, allowNull: true)) {
+ return false;
+ }
+ bool isFixedLength =
+ lattice.isDefinitelyFixedNativeList(listValue, allowNull: true);
+ bool isMutable =
+ lattice.isDefinitelyMutableNativeList(listValue, allowNull: true);
+ SourceInformation sourceInfo = node.sourceInformation;
+ Continuation cont = node.continuation.definition;
+ switch (node.selector.name) {
+ case 'length':
+ if (!node.selector.isGetter) return false;
+ CpsFragment cps = new CpsFragment(sourceInfo);
+ cps.invokeContinuation(cont, [cps.letPrim(new GetLength(list))]);
+ replaceSubtree(node, cps.result);
+ visit(cps.result);
+ return true;
+
+ case '[]':
+ if (listValue.isNullable) return false;
+ if (hasTooManyIndexAccesses(list)) return false;
+ Primitive index = getDartArgument(node, 0);
+ if (!lattice.isDefinitelyInt(getValue(index))) return false;
+ CpsFragment cps = makeBoundsCheck(list, index, sourceInfo);
+ GetIndex get = cps.letPrim(new GetIndex(list, index));
+ cps.invokeContinuation(cont, [get]);
+ replaceSubtree(node, cps.result);
+ visit(cps.result);
+ return true;
+
+ case '[]=':
+ if (listValue.isNullable) return false;
+ if (hasTooManyIndexAccesses(list)) return false;
+ Primitive index = getDartArgument(node, 0);
+ Primitive value = getDartArgument(node, 1);
+ if (!isMutable) return false;
+ if (!lattice.isDefinitelyInt(getValue(index))) return false;
+ CpsFragment cps = makeBoundsCheck(list, index, sourceInfo);
+ cps.letPrim(new SetIndex(list, index, value));
+ assert(cont.parameters.single.hasNoUses);
+ cont.parameters.clear();
+ cps.invokeContinuation(cont, []);
+ replaceSubtree(node, cps.result);
+ visit(cps.result);
+ return true;
+
+ case 'forEach':
+ if (!node.selector.isCall ||
+ node.selector.positionalArgumentCount != 1 ||
+ node.selector.namedArgumentCount != 0) {
+ return false;
+ }
+ Primitive callback = getDartArgument(node, 0);
+ // Rewrite to:
+ // var originalLength = array.length, i = 0;
+ // while (i < array.length) {
+ // callback(array[i]);
+ // if (array.length !== originalLength) throw;
+ // i = i + 1;
+ // }
+ CpsFragment cps = new CpsFragment(sourceInfo);
+ Primitive originalLength = cps.letPrim(new GetLength(list));
+ originalLength.hint = new OriginalLengthEntity();
+
+ // Build a loop.
+ Parameter loopIndex = new Parameter(new LoopIndexEntity());
+ Continuation loop = cps.beginLoop(
+ <Parameter>[loopIndex], [cps.makeZero()]);
+
+ // Check for loop exit.
+ Primitive loopCondition = cps.applyBuiltin(
+ BuiltinOperator.NumLt,
+ [loopIndex, cps.letPrim(new GetLength(list))]);
+ CpsFragment exitBranch = cps.ifFalse(loopCondition);
+ exitBranch.invokeContinuation(cont, [exitBranch.makeNull()]);
+
+ // Invoke the callback.
+ Primitive arrayItem = cps.letPrim(new GetIndex(list, loopIndex));
+ cps.invokeMethod(callback,
+ new Selector.callClosure(1),
+ getValue(callback).type,
+ [arrayItem]);
+
+ // Check for concurrent modification, unless the list is fixed-length.
+ if (!isFixedLength) {
+ cps.append(
+ makeConcurrentModificationCheck(list, originalLength, sourceInfo));
+ }
+
+ // Increment i and continue the loop.
+ Primitive addOne = cps.applyBuiltin(
+ BuiltinOperator.NumAdd,
+ [loopIndex, cps.makeOne()]);
+ cps.continueLoop(loop, [addOne]);
+
+ replaceSubtree(node, cps.result);
+ visit(cps.result);
+ return true;
+
+ case 'iterator':
+ if (!node.selector.isGetter) return false;
+ Primitive iterator = cont.parameters.single;
+ Continuation iteratorCont = cont;
+
+ // Check that all uses of the iterator are 'moveNext' and 'current'.
+ Selector moveNextSelector = new Selector.call('moveNext', null, 0);
+ Selector currentSelector = new Selector.getter('current', null);
+ assert(!isInterceptedSelector(moveNextSelector));
+ assert(!isInterceptedSelector(currentSelector));
+ for (Reference ref = iterator.firstRef; ref != null; ref = ref.next) {
+ if (ref.parent is! InvokeMethod) return false;
+ InvokeMethod use = ref.parent;
+ if (ref != use.receiver) return false;
+ if (use.selector != moveNextSelector &&
+ use.selector != currentSelector) {
+ return false;
+ }
+ }
+
+ // Rewrite the iterator variable to 'current' and 'index' variables.
+ Primitive originalLength = new GetLength(list);
+ originalLength.hint = new OriginalLengthEntity();
+ MutableVariable index = new MutableVariable(new LoopIndexEntity());
+ MutableVariable current = new MutableVariable(new LoopItemEntity());
+
+ // Rewrite all uses of the iterator.
+ while (iterator.firstRef != null) {
+ InvokeMethod use = iterator.firstRef.parent;
+ Continuation useCont = use.continuation.definition;
+ if (use.selector == currentSelector) {
+ // Rewrite iterator.current to a use of the 'current' variable.
+ Parameter result = useCont.parameters.single;
+ if (result.hint != null) {
+ // If 'current' was originally moved into a named variable, use
+ // that variable name for the mutable variable.
+ current.hint = result.hint;
+ }
+ LetPrim let =
+ makeLetPrimInvoke(new GetMutableVariable(current), useCont);
+ replaceSubtree(use, let);
+ } else {
+ assert (use.selector == moveNextSelector);
+ // Rewrite iterator.moveNext() to:
+ //
+ // if (index < list.length) {
+ // current = null;
+ // continuation(false);
+ // } else {
+ // current = list[index];
+ // index = index + 1;
+ // continuation(true);
+ // }
+ //
+ // (The above does not show concurrent modification checks)
+
+ // [cps] contains the code we insert instead of moveNext().
+ CpsFragment cps = new CpsFragment(node.sourceInformation);
+
+ // We must check for concurrent modification when calling moveNext.
+ // When moveNext is used as a loop condition, the check prevents
+ // `index < list.length` from becoming the loop condition, and we
+ // get code like this:
+ //
+ // while (true) {
+ // if (originalLength !== list.length) throw;
+ // if (index < list.length) {
+ // ...
+ // } else {
+ // ...
+ // break;
+ // }
+ // }
+ //
+ // For loops, we therefore check for concurrent modification before
+ // invoking the recursive continuation, so the loop becomes:
+ //
+ // if (originalLength !== list.length) throw;
+ // while (index < list.length) {
+ // ...
+ // if (originalLength !== list.length) throw;
+ // }
+ //
+ // The check before the loop can often be eliminated because it
+ // follows immediately after the 'iterator' call.
+ InteriorNode parent = getEffectiveParent(use);
+ if (!isFixedLength) {
+ if (parent is Continuation && parent.isRecursive) {
+ // Check for concurrent modification before every invocation
+ // of the continuation.
+ // TODO(asgerf): Do this in a continuation so multiple
+ // continues can share the same code.
+ for (Reference ref = parent.firstRef;
+ ref != null;
+ ref = ref.next) {
+ Expression invocationCaller = ref.parent;
+ if (getEffectiveParent(invocationCaller) == iteratorCont) {
+ // No need to check for concurrent modification immediately
+ // after the call to 'iterator'.
+ continue;
+ }
+ CpsFragment check = makeConcurrentModificationCheck(
+ list, originalLength, sourceInfo);
+ insertBefore(invocationCaller, check);
+ }
+ } else {
+ cps.append(makeConcurrentModificationCheck(
+ list, originalLength, sourceInfo));
+ }
+ }
+
+ // Check if there are more elements.
+ Primitive hasMore = cps.applyBuiltin(
+ BuiltinOperator.NumLt,
+ [cps.getMutable(index), cps.letPrim(new GetLength(list))]);
+
+ // Return false if there are no more.
+ CpsFragment falseBranch = cps.ifFalse(hasMore);
+ falseBranch
+ ..setMutable(current, falseBranch.makeNull())
+ ..invokeContinuation(useCont, [falseBranch.makeFalse()]);
+
+ // Return true if there are more element.
+ cps.setMutable(current,
+ cps.letPrim(new GetIndex(list, cps.getMutable(index))));
+ cps.setMutable(index, cps.applyBuiltin(
+ BuiltinOperator.NumAdd,
+ [cps.getMutable(index), cps.makeOne()]));
+ cps.invokeContinuation(useCont, [cps.makeTrue()]);
+
+ // Replace the moveNext() call. It will be visited later.
+ replaceSubtree(use, cps.result);
+ }
+ }
+
+ // Rewrite the iterator call to initializers for 'index' and 'current'.
+ CpsFragment cps = new CpsFragment();
+ cps.letMutable(index, cps.makeZero());
+ cps.letMutable(current, cps.makeNull());
+ cps.letPrim(originalLength);
+
+ // Insert this fragment before the continuation body and replace the
+ // iterator call with a call to the continuation without arguments.
+ // For scoping reasons, the variables must be bound inside the
+ // continuation, not at the invocation-site.
+ iteratorCont.parameters.clear();
+ insertBefore(iteratorCont.body, cps);
+ InvokeContinuation invoke = new InvokeContinuation(iteratorCont, []);
+ replaceSubtree(node, invoke);
+ visit(invoke);
+ // TODO(asgerf): A procedure for rewriting mutables into parameters
+ // might enable further optimizations after this.
+ return true;
+
+ // TODO(asgerf): Rewrite 'add', 'removeLast', ...
+
+ default:
+ return false;
+ }
+ }
+
/// If [prim] is the parameter to a call continuation, returns the
/// corresponding call.
Invoke getInvocationWithResult(Primitive prim) {
@@ -779,29 +1190,17 @@
return null;
}
- /// True if any side effect immediately before [current] can safely be
- /// postponed until immediately before [target].
- ///
- /// An expression `e` can be moved right before [target] if
- /// `canPostponeSideEffects(e.body, target)` is true and no reference
- /// falls out of scope.
- ///
- /// A more sophisticated analysis would track side-effect dependencies
- /// between `e` and the expressions between `e` and the target.
- bool canPostponeSideEffects(Expression current, Expression target) {
- Expression exp = current;
- while (exp != target) {
- if (exp is LetPrim && exp.primitive.isSafeForReordering) {
- LetPrim let = exp;
- exp = let.body;
- } else if (exp is LetCont) {
- LetCont let = exp;
- exp = let.body;
+ /// Returns the first parent of [node] that is not a pure expression.
+ InteriorNode getEffectiveParent(Expression node) {
+ while (true) {
+ Node parent = node.parent;
+ if (parent is LetCont ||
+ parent is LetPrim && parent.primitive.isSafeForReordering) {
+ node = parent;
} else {
- return false;
+ return parent;
}
}
- return true;
}
/// Rewrites an invocation of a torn-off method into a method call directly
@@ -847,6 +1246,10 @@
Invoke tearOffInvoke = getInvocationWithResult(tearOff);
if (tearOffInvoke is InvokeMethod && tearOffInvoke.selector.isGetter) {
Selector getter = tearOffInvoke.selector;
+
+ // TODO(asgerf): Support torn-off intercepted methods.
+ if (isInterceptedSelector(getter)) return false;
+
Continuation getterCont = tearOffInvoke.continuation.definition;
// TODO(asgerf): Support torn-off intercepted methods.
@@ -868,7 +1271,7 @@
if (!isPure && tearOff.hasMultipleUses) return false;
// If the getter call is impure, we risk reordering side effects.
- if (!isPure && !canPostponeSideEffects(getterCont.body, node)) {
+ if (!isPure && getEffectiveParent(node) != getterCont) {
return false;
}
@@ -905,6 +1308,7 @@
if (constifyExpression(node)) return;
if (specializeOperatorCall(node)) return;
if (specializeFieldAccess(node)) return;
+ if (specializeArrayAccess(node)) return;
if (specializeClosureCall(node)) return;
AbstractValue receiver = getValue(node.receiver.definition);
@@ -1075,6 +1479,10 @@
node.objectIsNotNull = getValue(node.object.definition).isDefinitelyNotNull;
}
+ void visitGetLength(GetLength node) {
+ node.objectIsNotNull = getValue(node.object.definition).isDefinitelyNotNull;
+ }
+
void visitLetPrim(LetPrim node) {
AbstractValue value = getValue(node.primitive);
if (node.primitive is! Constant && value.isConstant) {
@@ -1127,6 +1535,7 @@
!cont.isRecursive &&
!node.isEscapingTry) {
for (int i = 0; i < node.arguments.length; ++i) {
+ node.arguments[i].definition.useElementAsHint(cont.parameters[i].hint);
node.arguments[i].definition.substituteFor(cont.parameters[i]);
node.arguments[i].unlink();
}
@@ -1471,7 +1880,13 @@
case BuiltinOperator.NumAnd:
case BuiltinOperator.NumOr:
case BuiltinOperator.NumXor:
- setValue(node, nonConstant(typeSystem.numType));
+ AbstractValue left = getValue(node.arguments[0].definition);
+ AbstractValue right = getValue(node.arguments[1].definition);
+ if (lattice.isDefinitelyInt(left) && lattice.isDefinitelyInt(right)) {
+ setValue(node, nonConstant(typeSystem.intType));
+ } else {
+ setValue(node, nonConstant(typeSystem.numType));
+ }
break;
case BuiltinOperator.NumLt:
@@ -1599,7 +2014,7 @@
void visitLiteralList(LiteralList node) {
// Constant lists are translated into (Constant ListConstant(...)) IR nodes,
// and thus LiteralList nodes are NonConst.
- setValue(node, nonConstant(typeSystem.listType));
+ setValue(node, nonConstant(typeSystem.mutableNativeListType));
}
void visitLiteralMap(LiteralMap node) {
@@ -1756,6 +2171,21 @@
setValue(returnValue, nonConstant(node.type));
}
}
+
+ @override
+ void visitGetLength(GetLength node) {
+ setValue(node, nonConstant(typeSystem.intType));
+ }
+
+ @override
+ void visitGetIndex(GetIndex node) {
+ setValue(node, nonConstant());
+ }
+
+ @override
+ void visitSetIndex(SetIndex node) {
+ setValue(node, nonConstant());
+ }
}
/// Represents the abstract value of a primitive value at some point in the
@@ -1787,8 +2217,16 @@
AbstractValue.constantValue(ConstantValue constant, TypeMask type)
: this._internal(CONSTANT, constant, type);
- AbstractValue.nonConstant(TypeMask type)
- : this._internal(NONCONST, null, type);
+ factory AbstractValue.nonConstant(TypeMask type) {
+ if (type.isEmpty) {
+ if (type.isNullable)
+ return new AbstractValue.constantValue(new NullConstantValue(), type);
+ else
+ return new AbstractValue.nothing();
+ } else {
+ return new AbstractValue._internal(NONCONST, null, type);
+ }
+ }
bool get isNothing => (kind == NOTHING);
bool get isConstant => (kind == CONSTANT);
@@ -1825,6 +2263,22 @@
static const String Stringify = 'S';
}
+/// Suggested name for a synthesized loop index.
+class LoopIndexEntity extends Entity {
+ String get name => 'i';
+}
+
+/// Suggested name for the current element of a list being iterated.
+class LoopItemEntity extends Entity {
+ String get name => 'current';
+}
+
+/// Suggested name for the original length of a list, for use in checks
+/// for concurrent modification.
+class OriginalLengthEntity extends Entity {
+ String get name => 'length';
+}
+
class ResetAnalysisInfo extends RecursiveVisitor {
Set<Node> reachableNodes;
Map<Definition, AbstractValue> values;
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 2cbaf31..51cdae4 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -359,7 +359,12 @@
"Async-await is supported by default.",
api.Diagnostic.HINT);
}),
- new OptionHandler('--enable-null-aware-operators', passThrough),
+ new OptionHandler('--enable-null-aware-operators', (_) {
+ diagnosticHandler.info(
+ "Option '--enable-null-aware-operators' is no longer needed. "
+ "Null aware operators are supported by default.",
+ api.Diagnostic.HINT);
+ }),
new OptionHandler('--enable-enum', (_) {
diagnosticHandler.info(
"Option '--enable-enum' is no longer needed. "
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 3e4cda2..2524fb1 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -21,6 +21,7 @@
import 'types/types.dart' show TypeMask;
import 'deferred_load.dart' show OutputUnit;
import 'js_backend/js_backend.dart' show JavaScriptBackend;
+import 'js_emitter/full_emitter/emitter.dart' as full show Emitter;
import 'js/js.dart' as jsAst;
import 'universe/universe.dart' show Selector, UniverseSelector;
import 'util/util.dart' show NO_LOCATION_SPANNABLE;
@@ -596,6 +597,9 @@
new List<Map<String, dynamic>>();
JavaScriptBackend backend = compiler.backend;
+ // Dump-info currently only works with the full emitter. If another
+ // emitter is used it will fail here.
+ full.Emitter fullEmitter = backend.emitter.emitter;
for (OutputUnit outputUnit in
infoCollector.mapper._outputUnit._elementToId.keys) {
@@ -603,7 +607,7 @@
outputUnits.add(<String, dynamic> {
'id': id,
'name': outputUnit.name,
- 'size': backend.emitter.oldEmitter.outputBuffers[outputUnit].length,
+ 'size': fullEmitter.outputBuffers[outputUnit].length,
});
}
diff --git a/pkg/compiler/lib/src/helpers/helpers.dart b/pkg/compiler/lib/src/helpers/helpers.dart
index bcfa12c..9f7e284 100644
--- a/pkg/compiler/lib/src/helpers/helpers.dart
+++ b/pkg/compiler/lib/src/helpers/helpers.dart
@@ -93,3 +93,52 @@
compiler.reportInfo(node,
MessageKind.GENERIC, {'text': 'HERE: $debugMessage'});
}
+
+/// Set of tracked objects used by [track] and [ifTracked].
+var _trackedObjects = new Set();
+
+/// Global default value for the `printTrace` option of [track] and [ifTracked].
+bool trackWithTrace = false;
+
+/// If [doTrack] is `true`, add [object] to the set of tracked objects.
+///
+/// If tracked, [message] is printed along the hash code and toString of
+/// [object]. If [printTrace] is `true` a trace printed additionally.
+/// If [printTrace] is `null`, [trackWithTrace] determines whether a trace is
+/// printed.
+///
+/// [object] is returned as the result of the method.
+track(bool doTrack, Object object, String message, {bool printTrace}) {
+ if (!doTrack) return object;
+ _trackedObjects.add(object);
+ String msg = 'track: ${object.hashCode}:$object:$message';
+ if (printTrace == null) printTrace = trackWithTrace;
+ if (printTrace) {
+ trace(msg);
+ } else {
+ debugPrint(msg);
+ }
+ return object;
+}
+
+/// Returns `true` if [object] is in the set of tracked objects.
+///
+/// If [message] is provided it is printed along the hash code and toString of
+/// [object]. If [printTrace] is `true` a trace printed additionally. If
+/// [printTrace] is `null`, [trackWithTrace] determines whether a trace is
+/// printed.
+bool ifTracked(Object object, {String message, bool printTrace}) {
+ if (_trackedObjects.contains(object)) {
+ if (message != null) {
+ String msg = 'tracked: ${object.hashCode}:$object:$message';
+ if (printTrace == null) printTrace = trackWithTrace;
+ if (printTrace) {
+ trace(msg);
+ } else {
+ debugPrint(msg);
+ }
+ }
+ return true;
+ }
+ return false;
+}
diff --git a/pkg/compiler/lib/src/inferrer/concrete_types_inferrer.dart b/pkg/compiler/lib/src/inferrer/concrete_types_inferrer.dart
index 9369d1d..19bcab4 100644
--- a/pkg/compiler/lib/src/inferrer/concrete_types_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/concrete_types_inferrer.dart
@@ -557,12 +557,12 @@
@override
ConcreteType nonNullSubclass(ClassElement cls) {
- return nonNullSubX(cls, compiler.world.subclassesOf);
+ return nonNullSubX(cls, compiler.world.strictSubclassesOf);
}
@override
ConcreteType nonNullSubtype(ClassElement cls) {
- return nonNullSubX(cls, compiler.world.subtypesOf);
+ return nonNullSubX(cls, compiler.world.strictSubtypesOf);
}
@override
diff --git a/pkg/compiler/lib/src/inferrer/node_tracer.dart b/pkg/compiler/lib/src/inferrer/node_tracer.dart
index b037c2f..4bd3b4c 100644
--- a/pkg/compiler/lib/src/inferrer/node_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/node_tracer.dart
@@ -19,9 +19,7 @@
'isEmpty',
'isNotEmpty',
'length',
- 'any',
'contains',
- 'every',
'join',
// From List.
diff --git a/pkg/compiler/lib/src/io/position_information.dart b/pkg/compiler/lib/src/io/position_information.dart
index 9b91cab1..416d7ea 100644
--- a/pkg/compiler/lib/src/io/position_information.dart
+++ b/pkg/compiler/lib/src/io/position_information.dart
@@ -149,6 +149,9 @@
SourceInformation buildGeneric(Node node) => buildBegin(node);
@override
+ SourceInformation buildCreate(Node node) => buildBegin(node);
+
+ @override
SourceInformation buildReturn(Node node) => buildBegin(node);
@override
diff --git a/pkg/compiler/lib/src/io/source_information.dart b/pkg/compiler/lib/src/io/source_information.dart
index 3c4ea20..09d1ca9 100644
--- a/pkg/compiler/lib/src/io/source_information.dart
+++ b/pkg/compiler/lib/src/io/source_information.dart
@@ -61,6 +61,10 @@
@deprecated
SourceInformation buildGeneric(Node node) => null;
+ /// Generate [SourceInformation] for an instantiation of a class using [node]
+ /// for the source position.
+ SourceInformation buildCreate(Node node) => null;
+
/// Generate [SourceInformation] for the return [node].
SourceInformation buildReturn(Node node) => null;
diff --git a/pkg/compiler/lib/src/io/start_end_information.dart b/pkg/compiler/lib/src/io/start_end_information.dart
index b76a217..4547fca 100644
--- a/pkg/compiler/lib/src/io/start_end_information.dart
+++ b/pkg/compiler/lib/src/io/start_end_information.dart
@@ -203,9 +203,10 @@
}
@override
- SourceInformation buildReturn(Node node) {
- return buildGeneric(node);
- }
+ SourceInformation buildCreate(Node node) => buildGeneric(node);
+
+ @override
+ SourceInformation buildReturn(Node node) => buildGeneric(node);
@override
SourceInformation buildGet(Node node) => buildGeneric(node);
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index c48fed1..bbe0c3b 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -850,7 +850,7 @@
Iterable<MixinApplicationElement> uses = classWorld.mixinUsesOf(mixin);
Set<ClassElement> result = null;
for (MixinApplicationElement use in uses) {
- Iterable<ClassElement> subclasses = classWorld.subclassesOf(use);
+ Iterable<ClassElement> subclasses = classWorld.strictSubclassesOf(use);
for (ClassElement subclass in subclasses) {
if (Elements.isNativeOrExtendsNative(subclass)) {
if (result == null) result = new Set<ClassElement>();
@@ -1737,6 +1737,10 @@
return findHelper('throwConcurrentModificationError');
}
+ Element getThrowIndexOutOfBoundsError() {
+ return findHelper('ioore');
+ }
+
Element getStringInterpolationHelper() {
return findHelper('S');
}
@@ -2333,8 +2337,8 @@
}
});
// 4) all overriding members of subclasses/subtypes (should be resolved)
- if (compiler.world.hasAnySubtype(cls)) {
- for (ClassElement subcls in compiler.world.subtypesOf(cls)) {
+ if (compiler.world.hasAnyStrictSubtype(cls)) {
+ for (ClassElement subcls in compiler.world.strictSubtypesOf(cls)) {
subcls.forEachClassMember((Member member) {
if (memberNames.contains(member.name)) {
// TODO(20993): find out why this assertion fails.
diff --git a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
index 1447173..e0388d2 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
@@ -48,6 +48,12 @@
final tree_ir.FallthroughStack fallthrough = new tree_ir.FallthroughStack();
+ /// Stacks whose top element is the current target of an unlabeled break
+ /// or continue. For continues, this is the loop node itself.
+ final tree_ir.FallthroughStack shortBreak = new tree_ir.FallthroughStack();
+ final tree_ir.FallthroughStack shortContinue =
+ new tree_ir.FallthroughStack();
+
Set<tree_ir.Label> usedLabels = new Set<tree_ir.Label>();
List<js.Statement> accumulator = new List<js.Statement>();
@@ -177,14 +183,18 @@
visitExpression(node.elseExpression));
}
- js.Expression buildConstant(ConstantValue constant) {
+ js.Expression buildConstant(ConstantValue constant,
+ {SourceInformation sourceInformation}) {
registry.registerCompileTimeConstant(constant);
- return glue.constantReference(constant);
+ return glue.constantReference(constant)
+ .withSourceInformation(sourceInformation);
}
@override
js.Expression visitConstant(tree_ir.Constant node) {
- return buildConstant(node.value);
+ return buildConstant(
+ node.value,
+ sourceInformation: node.sourceInformation);
}
js.Expression compileConstant(ParameterElement parameter) {
@@ -207,7 +217,8 @@
registry.registerInstantiatedType(node.type);
FunctionElement target = node.target;
List<js.Expression> arguments = visitExpressionList(node.arguments);
- return buildStaticInvoke(target, arguments);
+ return buildStaticInvoke(
+ target, arguments, sourceInformation: node.sourceInformation);
}
void registerMethodInvoke(tree_ir.InvokeMethod node) {
@@ -234,7 +245,8 @@
registerMethodInvoke(node);
return js.propertyCall(visitExpression(node.receiver),
glue.invocationName(node.selector),
- visitExpressionList(node.arguments));
+ visitExpressionList(node.arguments))
+ .withSourceInformation(node.sourceInformation);
}
@override
@@ -254,13 +266,15 @@
return js.js('#.#(#)',
[visitExpression(node.receiver),
glue.instanceMethodName(node.target),
- visitExpressionList(node.arguments)]);
+ visitExpressionList(node.arguments)])
+ .withSourceInformation(node.sourceInformation);
}
return js.js('#.#.call(#, #)',
[glue.prototypeAccess(node.target.enclosingClass),
glue.invocationName(node.selector),
visitExpression(node.receiver),
- visitExpressionList(node.arguments)]);
+ visitExpressionList(node.arguments)])
+ .withSourceInformation(node.sourceInformation);
}
@override
@@ -390,27 +404,36 @@
@override
void visitContinue(tree_ir.Continue node) {
tree_ir.Statement next = fallthrough.target;
- if (node.target.binding == next) {
- // Fall through to continue target
+ if (node.target.binding == next ||
+ next is tree_ir.Continue && node.target == next.target) {
+ // Fall through to continue target or to equivalent continue.
fallthrough.use();
- } else if (next is tree_ir.Continue && next.target == node.target) {
- // Fall through to equivalent continue
- fallthrough.use();
+ } else if (node.target.binding == shortContinue.target) {
+ // The target is the immediately enclosing loop.
+ shortContinue.use();
+ accumulator.add(new js.Continue(null));
} else {
usedLabels.add(node.target);
accumulator.add(new js.Continue(node.target.name));
}
}
+ /// True if [other] is the target of [node] or is a [Break] with the same
+ /// target. This means jumping to [other] is equivalent to executing [node].
+ bool isEffectiveBreakTarget(tree_ir.Break node, tree_ir.Statement other) {
+ return node.target.binding.next == other ||
+ other is tree_ir.Break && node.target == other.target;
+ }
+
@override
void visitBreak(tree_ir.Break node) {
- tree_ir.Statement next = fallthrough.target;
- if (node.target.binding.next == next) {
- // Fall through to break target
+ if (isEffectiveBreakTarget(node, fallthrough.target)) {
+ // Fall through to break target or to equivalent break.
fallthrough.use();
- } else if (next is tree_ir.Break && next.target == node.target) {
- // Fall through to equivalent break
- fallthrough.use();
+ } else if (isEffectiveBreakTarget(node, shortBreak.target)) {
+ // Unlabeled break to the break target or to an equivalent break.
+ shortBreak.use();
+ accumulator.add(new js.Break(null));
} else {
usedLabels.add(node.target);
accumulator.add(new js.Break(node.target.name));
@@ -443,22 +466,20 @@
@override
void visitLabeledStatement(tree_ir.LabeledStatement node) {
- accumulator.add(buildLabeled(() => buildBodyStatement(node.body),
- node.label,
- node.next));
+ fallthrough.push(node.next);
+ js.Statement body = buildBodyStatement(node.body);
+ fallthrough.pop();
+ accumulator.add(insertLabel(node.label, body));
visitStatement(node.next);
}
- js.Statement buildLabeled(js.Statement buildBody(),
- tree_ir.Label label,
- tree_ir.Statement fallthroughStatement) {
- fallthrough.push(fallthroughStatement);
- js.Statement result = buildBody();
+ /// Wraps a node in a labeled statement unless the label is unused.
+ js.Statement insertLabel(tree_ir.Label label, js.Statement node) {
if (usedLabels.remove(label)) {
- result = new js.LabeledStatement(label.name, result);
+ return new js.LabeledStatement(label.name, node);
+ } else {
+ return node;
}
- fallthrough.pop();
- return result;
}
/// Returns the current [accumulator] wrapped in a block if neccessary.
@@ -491,29 +512,36 @@
return result;
}
- js.Statement buildWhile(js.Expression condition,
- tree_ir.Statement body,
- tree_ir.Label label,
- tree_ir.Statement fallthroughStatement) {
- return buildLabeled(() => new js.While(condition, buildBodyStatement(body)),
- label,
- fallthroughStatement);
- }
-
@override
void visitWhileCondition(tree_ir.WhileCondition node) {
- accumulator.add(
- buildWhile(visitExpression(node.condition),
- node.body,
- node.label,
- node));
+ js.Expression condition = visitExpression(node.condition);
+ shortBreak.push(node.next);
+ shortContinue.push(node);
+ fallthrough.push(node);
+ js.Statement jsBody = buildBodyStatement(node.body);
+ fallthrough.pop();
+ shortContinue.pop();
+ shortBreak.pop();
+ accumulator.add(insertLabel(node.label, new js.While(condition, jsBody)));
visitStatement(node.next);
}
@override
void visitWhileTrue(tree_ir.WhileTrue node) {
- accumulator.add(
- buildWhile(new js.LiteralBool(true), node.body, node.label, node));
+ js.Expression condition = new js.LiteralBool(true);
+ // A short break in the while will jump to the current fallthrough target.
+ shortBreak.push(fallthrough.target);
+ shortContinue.push(node);
+ fallthrough.push(node);
+ js.Statement jsBody = buildBodyStatement(node.body);
+ fallthrough.pop();
+ shortContinue.pop();
+ if (shortBreak.useCount > 0) {
+ // Short breaks use the current fallthrough target.
+ fallthrough.use();
+ }
+ shortBreak.pop();
+ accumulator.add(insertLabel(node.label, new js.While(condition, jsBody)));
}
bool isNull(tree_ir.Expression node) {
@@ -527,7 +555,8 @@
registry.registerCompileTimeConstant(new NullConstantValue());
fallthrough.use();
} else {
- accumulator.add(new js.Return(visitExpression(node.value)));
+ accumulator.add(new js.Return(visitExpression(node.value))
+ .withSourceInformation(node.sourceInformation));
}
}
@@ -576,7 +605,8 @@
}
js.Expression instance = new js.New(
glue.constructorAccess(classElement),
- visitExpressionList(node.arguments));
+ visitExpressionList(node.arguments))
+ .withSourceInformation(node.sourceInformation);
List<tree_ir.Expression> typeInformation = node.typeInformation;
assert(typeInformation.isEmpty ||
@@ -586,7 +616,8 @@
js.Expression typeArguments = new js.ArrayInitializer(
visitExpressionList(typeInformation));
return buildStaticHelperInvocation(helper,
- <js.Expression>[instance, typeArguments]);
+ <js.Expression>[instance, typeArguments],
+ sourceInformation: node.sourceInformation);
} else {
return instance;
}
@@ -664,19 +695,45 @@
return new js.Assignment(field, value);
}
- js.Expression buildStaticHelperInvocation(FunctionElement helper,
- List<js.Expression> arguments) {
+ @override
+ js.Expression visitGetLength(tree_ir.GetLength node) {
+ return new js.PropertyAccess.field(visitExpression(node.object), 'length');
+ }
+
+ @override
+ js.Expression visitGetIndex(tree_ir.GetIndex node) {
+ return new js.PropertyAccess(
+ visitExpression(node.object),
+ visitExpression(node.index));
+ }
+
+ @override
+ js.Expression visitSetIndex(tree_ir.SetIndex node) {
+ return js.js('#[#] = #',
+ [visitExpression(node.object),
+ visitExpression(node.index),
+ visitExpression(node.value)]);
+ }
+
+ js.Expression buildStaticHelperInvocation(
+ FunctionElement helper,
+ List<js.Expression> arguments,
+ {SourceInformation sourceInformation}) {
registry.registerStaticUse(helper);
- return buildStaticInvoke(helper, arguments);
+ return buildStaticInvoke(
+ helper, arguments, sourceInformation: sourceInformation);
}
@override
js.Expression visitReifyRuntimeType(tree_ir.ReifyRuntimeType node) {
- FunctionElement createType = glue.getCreateRuntimeType();
- FunctionElement typeToString = glue.getRuntimeTypeToString();
- return buildStaticHelperInvocation(createType,
- [buildStaticHelperInvocation(typeToString,
- [visitExpression(node.value)])]);
+ js.Expression typeToString = buildStaticHelperInvocation(
+ glue.getRuntimeTypeToString(),
+ [visitExpression(node.value)],
+ sourceInformation: node.sourceInformation);
+ return buildStaticHelperInvocation(
+ glue.getCreateRuntimeType(),
+ [typeToString],
+ sourceInformation: node.sourceInformation);
}
@override
@@ -687,11 +744,13 @@
js.Expression typeName = glue.getRuntimeTypeName(context);
return buildStaticHelperInvocation(
glue.getRuntimeTypeArgument(),
- [visitExpression(node.target), typeName, index]);
+ [visitExpression(node.target), typeName, index],
+ sourceInformation: node.sourceInformation);
} else {
return buildStaticHelperInvocation(
glue.getTypeArgumentByIndex(),
- [visitExpression(node.target), index]);
+ [visitExpression(node.target), index],
+ sourceInformation: node.sourceInformation);
}
}
diff --git a/pkg/compiler/lib/src/js_backend/codegen/task.dart b/pkg/compiler/lib/src/js_backend/codegen/task.dart
index 9ed2829..9c4658c 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/task.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/task.dart
@@ -181,9 +181,12 @@
assert(checkCpsIntegrity(cpsNode));
}
+ applyCpsPass(new RedundantPhiEliminator());
TypePropagator typePropagator = new TypePropagator(compiler);
applyCpsPass(typePropagator);
dumpTypedIR(cpsNode, typePropagator);
+ applyCpsPass(new ShrinkingReducer());
+ applyCpsPass(new RedundantJoinEliminator());
applyCpsPass(new RedundantPhiEliminator());
applyCpsPass(new ShrinkingReducer());
diff --git a/pkg/compiler/lib/src/js_backend/minify_namer.dart b/pkg/compiler/lib/src/js_backend/minify_namer.dart
index dd01a92..b781bc0 100644
--- a/pkg/compiler/lib/src/js_backend/minify_namer.dart
+++ b/pkg/compiler/lib/src/js_backend/minify_namer.dart
@@ -342,9 +342,11 @@
String prefix = selector.isGetter
? r"$get"
: selector.isSetter ? r"$set" : "";
- String arity = selector.isCall ? "${selector.argumentCount}" : "";
+ String callSuffix =
+ selector.isCall ? callSuffixForStructure(selector.callStructure).join()
+ : "";
String suffix = suffixForGetInterceptor(classes);
- String fullName = "\$intercepted$prefix\$$root$arity\$$suffix";
+ String fullName = "\$intercepted$prefix\$$root$callSuffix\$$suffix";
return _disambiguateInternalGlobal(fullName);
}
}
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 9ce0b81..ad7f725 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -321,7 +321,7 @@
}
final String asyncPrefix = r"$async$";
- final String currentIsolate = r'$';
+ final String staticStateHolder = r'$';
final String getterPrefix = r'get$';
final String lazyGetterPrefix = r'$get$';
final String setterPrefix = r'set$';
@@ -1313,17 +1313,19 @@
: globalPropertyName(method);
}
- /// Returns true if [element] is stored on current isolate ('$'). We intend
- /// to store only mutable static state in [currentIsolate], constants are
- /// stored in 'C', and functions, accessors, classes, etc. are stored in one
- /// of the other objects in [reservedGlobalObjectNames].
- bool isPropertyOfCurrentIsolate(Element element) {
+ /// Returns true if [element] is stored in the static state holder
+ /// ([staticStateHolder]). We intend to store only mutable static state
+ /// there, whereas constants are stored in 'C'. Functions, accessors,
+ /// classes, etc. are stored in one of the other objects in
+ /// [reservedGlobalObjectNames].
+ bool _isPropertyOfStaticStateHolder(Element element) {
// TODO(ahe): Make sure this method's documentation is always true and
// remove the word "intend".
return
// TODO(ahe): Re-write these tests to be positive (so it only returns
// true for static/top-level mutable fields). Right now, a number of
- // other elements, such as bound closures also live in [currentIsolate].
+ // other elements, such as bound closures also live in
+ // [staticStateHolder].
!element.isAccessor &&
!element.isClass &&
!element.isTypedef &&
@@ -1332,9 +1334,9 @@
!element.isLibrary;
}
- /// Returns [currentIsolate] or one of [reservedGlobalObjectNames].
+ /// Returns [staticStateHolder] or one of [reservedGlobalObjectNames].
String globalObjectFor(Element element) {
- if (isPropertyOfCurrentIsolate(element)) return currentIsolate;
+ if (_isPropertyOfStaticStateHolder(element)) return staticStateHolder;
LibraryElement library = element.library;
if (library == backend.interceptorsLibrary) return 'J';
if (library.isInternalLibrary) return 'H';
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index 66be56a..d6f02eb 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -134,7 +134,7 @@
classesNeedingRti.add(cls);
// TODO(ngeoffray): This should use subclasses, not subtypes.
- Iterable<ClassElement> classes = compiler.world.subtypesOf(cls);
+ Iterable<ClassElement> classes = compiler.world.strictSubtypesOf(cls);
classes.forEach((ClassElement sub) {
potentiallyAddForRti(sub);
});
diff --git a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
index b8fa032..0b9cdb2 100644
--- a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
+++ b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
@@ -18,46 +18,29 @@
final TypeTestRegistry typeTestRegistry;
NativeEmitter nativeEmitter;
MetadataCollector metadataCollector;
- OldEmitter oldEmitter;
Emitter emitter;
- final Set<ClassElement> neededClasses = new Set<ClassElement>();
- Set<ClassElement> classesOnlyNeededForRti;
- final Map<OutputUnit, List<ClassElement>> outputClassLists =
- new Map<OutputUnit, List<ClassElement>>();
- final Map<OutputUnit, List<ConstantValue>> outputConstantLists =
- new Map<OutputUnit, List<ConstantValue>>();
- final Map<OutputUnit, List<Element>> outputStaticLists =
- new Map<OutputUnit, List<Element>>();
- final Map<OutputUnit, List<VariableElement>> outputStaticNonFinalFieldLists =
- new Map<OutputUnit, List<VariableElement>>();
- final Map<OutputUnit, Set<LibraryElement>> outputLibraryLists =
- new Map<OutputUnit, Set<LibraryElement>>();
-
- /// True, if the output contains a constant list.
- ///
- /// This flag is updated in [computeNeededConstants].
- bool outputContainsConstantList = false;
-
- final List<ClassElement> nativeClassesAndSubclasses = <ClassElement>[];
-
/// Records if a type variable is read dynamically for type tests.
final Set<TypeVariableElement> readTypeVariables =
new Set<TypeVariableElement>();
- List<TypedefElement> typedefsNeededForReflection;
-
JavaScriptBackend get backend => compiler.backend;
+ @deprecated
+ // This field should be removed. It's currently only needed for dump-info and
+ // tests.
+ // The field is set after the program has been emitted.
+ /// Contains a list of all classes that are emitted.
+ Set<ClassElement> neededClasses;
+
CodeEmitterTask(Compiler compiler, Namer namer, bool generateSourceMap)
: super(compiler),
this.namer = namer,
this.typeTestRegistry = new TypeTestRegistry(compiler) {
nativeEmitter = new NativeEmitter(this);
- oldEmitter = new OldEmitter(compiler, namer, generateSourceMap, this);
emitter = USE_LAZY_EMITTER
? new lazy_js_emitter.Emitter(compiler, namer, nativeEmitter)
- : oldEmitter;
+ : new full_js_emitter.Emitter(compiler, namer, generateSourceMap, this);
metadataCollector = new MetadataCollector(compiler, emitter);
}
@@ -134,277 +117,25 @@
readTypeVariables.add(element);
}
- Set<ClassElement> computeInterceptorsReferencedFromConstants() {
- Set<ClassElement> classes = new Set<ClassElement>();
- JavaScriptConstantCompiler handler = backend.constants;
- List<ConstantValue> constants = handler.getConstantsForEmission();
- for (ConstantValue constant in constants) {
- if (constant is InterceptorConstantValue) {
- InterceptorConstantValue interceptorConstant = constant;
- classes.add(interceptorConstant.dispatchedType.element);
- }
- }
- return classes;
- }
-
- /**
- * Return a function that returns true if its argument is a class
- * that needs to be emitted.
- */
- Function computeClassFilter() {
- if (backend.isTreeShakingDisabled) return (ClassElement cls) => true;
-
- Set<ClassElement> unneededClasses = new Set<ClassElement>();
- // The [Bool] class is not marked as abstract, but has a factory
- // constructor that always throws. We never need to emit it.
- unneededClasses.add(compiler.boolClass);
-
- // Go over specialized interceptors and then constants to know which
- // interceptors are needed.
- Set<ClassElement> needed = new Set<ClassElement>();
- backend.specializedGetInterceptors.forEach(
- (_, Iterable<ClassElement> elements) {
- needed.addAll(elements);
- }
- );
-
- // Add interceptors referenced by constants.
- needed.addAll(computeInterceptorsReferencedFromConstants());
-
- // Add unneeded interceptors to the [unneededClasses] set.
- for (ClassElement interceptor in backend.interceptedClasses) {
- if (!needed.contains(interceptor)
- && interceptor != compiler.objectClass) {
- unneededClasses.add(interceptor);
- }
- }
-
- // These classes are just helpers for the backend's type system.
- unneededClasses.add(backend.jsMutableArrayClass);
- unneededClasses.add(backend.jsFixedArrayClass);
- unneededClasses.add(backend.jsExtendableArrayClass);
- unneededClasses.add(backend.jsUInt32Class);
- unneededClasses.add(backend.jsUInt31Class);
- unneededClasses.add(backend.jsPositiveIntClass);
-
- return (ClassElement cls) => !unneededClasses.contains(cls);
- }
-
- /**
- * Compute all the constants that must be emitted.
- */
- void computeNeededConstants() {
- // Make sure we retain all metadata of all elements. This could add new
- // constants to the handler.
- if (backend.mustRetainMetadata) {
- // TODO(floitsch): verify that we don't run through the same elements
- // multiple times.
- for (Element element in backend.generatedCode.keys) {
- if (backend.isAccessibleByReflection(element)) {
- bool shouldRetainMetadata = backend.retainMetadataOf(element);
- if (shouldRetainMetadata &&
- (element.isFunction || element.isConstructor ||
- element.isSetter)) {
- FunctionElement function = element;
- function.functionSignature.forEachParameter(
- backend.retainMetadataOf);
- }
- }
- }
- for (ClassElement cls in neededClasses) {
- final onlyForRti = classesOnlyNeededForRti.contains(cls);
- if (!onlyForRti) {
- backend.retainMetadataOf(cls);
- oldEmitter.classEmitter.visitFields(cls, false,
- (Element member,
- jsAst.Name name,
- jsAst.Name accessorName,
- bool needsGetter,
- bool needsSetter,
- bool needsCheckedSetter) {
- bool needsAccessor = needsGetter || needsSetter;
- if (needsAccessor && backend.isAccessibleByReflection(member)) {
- backend.retainMetadataOf(member);
- }
- });
- }
- }
- typedefsNeededForReflection.forEach(backend.retainMetadataOf);
- }
-
- JavaScriptConstantCompiler handler = backend.constants;
- List<ConstantValue> constants = handler.getConstantsForEmission(
- compiler.hasIncrementalSupport ? null : emitter.compareConstants);
- for (ConstantValue constant in constants) {
- if (emitter.isConstantInlinedOrAlreadyEmitted(constant)) continue;
-
- if (constant.isList) outputContainsConstantList = true;
-
- OutputUnit constantUnit =
- compiler.deferredLoadTask.outputUnitForConstant(constant);
- if (constantUnit == null) {
- // The back-end introduces some constants, like "InterceptorConstant" or
- // some list constants. They are emitted in the main output-unit.
- // TODO(sigurdm): We should track those constants.
- constantUnit = compiler.deferredLoadTask.mainOutputUnit;
- }
- outputConstantLists.putIfAbsent(
- constantUnit, () => new List<ConstantValue>()).add(constant);
- }
- }
-
- /// Compute all the classes and typedefs that must be emitted.
- void computeNeededDeclarations(Set<ClassElement> rtiNeededClasses) {
- // Compute needed typedefs.
- typedefsNeededForReflection = Elements.sortedByPosition(
- compiler.world.allTypedefs
- .where(backend.isAccessibleByReflection)
- .toList());
-
- // Compute needed classes.
- Set<ClassElement> instantiatedClasses =
- compiler.codegenWorld.directlyInstantiatedClasses
- .where(computeClassFilter()).toSet();
-
- void addClassWithSuperclasses(ClassElement cls) {
- neededClasses.add(cls);
- for (ClassElement superclass = cls.superclass;
- superclass != null;
- superclass = superclass.superclass) {
- neededClasses.add(superclass);
- }
- }
-
- void addClassesWithSuperclasses(Iterable<ClassElement> classes) {
- for (ClassElement cls in classes) {
- addClassWithSuperclasses(cls);
- }
- }
-
- // 1. We need to generate all classes that are instantiated.
- addClassesWithSuperclasses(instantiatedClasses);
-
- // 2. Add all classes used as mixins.
- Set<ClassElement> mixinClasses = neededClasses
- .where((ClassElement element) => element.isMixinApplication)
- .map(computeMixinClass)
- .toSet();
- neededClasses.addAll(mixinClasses);
-
- // 3. Find all classes needed for rti.
- // It is important that this is the penultimate step, at this point,
- // neededClasses must only contain classes that have been resolved and
- // codegen'd. The rtiNeededClasses may contain additional classes, but
- // these are thought to not have been instantiated, so we neeed to be able
- // to identify them later and make sure we only emit "empty shells" without
- // fields, etc.
- classesOnlyNeededForRti = rtiNeededClasses.difference(neededClasses);
-
- neededClasses.addAll(classesOnlyNeededForRti);
-
- // TODO(18175, floitsch): remove once issue 18175 is fixed.
- if (neededClasses.contains(backend.jsIntClass)) {
- neededClasses.add(compiler.intClass);
- }
- if (neededClasses.contains(backend.jsDoubleClass)) {
- neededClasses.add(compiler.doubleClass);
- }
- if (neededClasses.contains(backend.jsNumberClass)) {
- neededClasses.add(compiler.numClass);
- }
- if (neededClasses.contains(backend.jsStringClass)) {
- neededClasses.add(compiler.stringClass);
- }
- if (neededClasses.contains(backend.jsBoolClass)) {
- neededClasses.add(compiler.boolClass);
- }
- if (neededClasses.contains(backend.jsArrayClass)) {
- neededClasses.add(compiler.listClass);
- }
-
- // 4. Finally, sort the classes.
- List<ClassElement> sortedClasses = Elements.sortedByPosition(neededClasses);
-
- for (ClassElement element in sortedClasses) {
- if (Elements.isNativeOrExtendsNative(element) &&
- !classesOnlyNeededForRti.contains(element)) {
- // For now, native classes and related classes cannot be deferred.
- nativeClassesAndSubclasses.add(element);
- assert(invariant(element,
- !compiler.deferredLoadTask.isDeferred(element)));
- outputClassLists.putIfAbsent(compiler.deferredLoadTask.mainOutputUnit,
- () => new List<ClassElement>()).add(element);
- } else {
- outputClassLists.putIfAbsent(
- compiler.deferredLoadTask.outputUnitForElement(element),
- () => new List<ClassElement>())
- .add(element);
- }
- }
- }
-
- void computeNeededStatics() {
- bool isStaticFunction(Element element) =>
- !element.isInstanceMember && !element.isField;
-
- Iterable<Element> elements =
- backend.generatedCode.keys.where(isStaticFunction);
-
- for (Element element in Elements.sortedByPosition(elements)) {
- List<Element> list = outputStaticLists.putIfAbsent(
- compiler.deferredLoadTask.outputUnitForElement(element),
- () => new List<Element>());
- list.add(element);
- }
- }
-
- void computeNeededStaticNonFinalFields() {
- JavaScriptConstantCompiler handler = backend.constants;
- Iterable<VariableElement> staticNonFinalFields = handler
- .getStaticNonFinalFieldsForEmission()
- .where(compiler.codegenWorld.allReferencedStaticFields.contains);
- for (Element element in Elements.sortedByPosition(staticNonFinalFields)) {
- List<VariableElement> list = outputStaticNonFinalFieldLists.putIfAbsent(
- compiler.deferredLoadTask.outputUnitForElement(element),
- () => new List<VariableElement>());
- list.add(element);
- }
- }
-
- void computeNeededLibraries() {
- void addSurroundingLibraryToSet(Element element) {
- OutputUnit unit = compiler.deferredLoadTask.outputUnitForElement(element);
- LibraryElement library = element.library;
- outputLibraryLists.putIfAbsent(unit, () => new Set<LibraryElement>())
- .add(library);
- }
-
- backend.generatedCode.keys.forEach(addSurroundingLibraryToSet);
- neededClasses.forEach(addSurroundingLibraryToSet);
- }
-
- void computeAllNeededEntities() {
+ Set<ClassElement> _finalizeRti() {
// Compute the required type checks to know which classes need a
// 'is$' method.
typeTestRegistry.computeRequiredTypeChecks();
// Compute the classes needed by RTI.
- Set<ClassElement> rtiClasses = typeTestRegistry.computeRtiNeededClasses();
-
- computeNeededDeclarations(rtiClasses);
- computeNeededConstants();
- computeNeededStatics();
- computeNeededStaticNonFinalFields();
- computeNeededLibraries();
+ return typeTestRegistry.computeRtiNeededClasses();
}
int assembleProgram() {
return measure(() {
emitter.invalidateCaches();
- computeAllNeededEntities();
-
- ProgramBuilder programBuilder = new ProgramBuilder(compiler, namer, this);
- return emitter.emitProgram(programBuilder);
+ Set<ClassElement> rtiNeededClasses = _finalizeRti();
+ ProgramBuilder programBuilder = new ProgramBuilder(
+ compiler, namer, this, emitter, rtiNeededClasses);
+ int size = emitter.emitProgram(programBuilder);
+ // TODO(floitsch): we shouldn't need the `neededClasses` anymore.
+ neededClasses = programBuilder.collector.neededClasses;
+ return size;
});
}
}
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/class_builder.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/class_builder.dart
index 4d69d92..6220c4e 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/class_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/class_builder.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.
-part of dart2js.js_emitter;
+part of dart2js.js_emitter.full_emitter;
/**
* A data structure for collecting fragments of a class definition.
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 3a7ab57..c12637c 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
@@ -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.
-part of dart2js.js_emitter;
+part of dart2js.js_emitter.full_emitter;
class ClassEmitter extends CodeEmitterHelper {
@@ -358,103 +358,6 @@
}
}
- /**
- * Invokes [f] for each of the fields of [element].
- *
- * [element] must be a [ClassElement] or a [LibraryElement].
- *
- * If [element] is a [ClassElement], the static fields of the class are
- * visited if [visitStatics] is true and the instance fields are visited if
- * [visitStatics] is false.
- *
- * If [element] is a [LibraryElement], [visitStatics] must be true.
- *
- * When visiting the instance fields of a class, the fields of its superclass
- * are also visited if the class is instantiated.
- *
- * Invariant: [element] must be a declaration element.
- */
- void visitFields(Element element, bool visitStatics, AcceptField f) {
- assert(invariant(element, element.isDeclaration));
-
- bool isClass = false;
- bool isLibrary = false;
- if (element.isClass) {
- isClass = true;
- } else if (element.isLibrary) {
- isLibrary = true;
- assert(invariant(element, visitStatics));
- } else {
- throw new SpannableAssertionFailure(
- element, 'Expected a ClassElement or a LibraryElement.');
- }
-
- // If the class is never instantiated we still need to set it up for
- // inheritance purposes, but we can simplify its JavaScript constructor.
- bool isInstantiated =
- compiler.codegenWorld.directlyInstantiatedClasses.contains(element);
-
- void visitField(Element holder, FieldElement field) {
- assert(invariant(element, field.isDeclaration));
-
- // Keep track of whether or not we're dealing with a field mixin
- // into a native class.
- bool isMixinNativeField =
- isClass && element.isNative && holder.isMixinApplication;
-
- // See if we can dynamically create getters and setters.
- // We can only generate getters and setters for [element] since
- // the fields of super classes could be overwritten with getters or
- // setters.
- bool needsGetter = false;
- bool needsSetter = false;
- if (isLibrary || isMixinNativeField || holder == element) {
- needsGetter = fieldNeedsGetter(field);
- needsSetter = fieldNeedsSetter(field);
- }
-
- if ((isInstantiated && !holder.isNative)
- || needsGetter
- || needsSetter) {
- jsAst.Name accessorName = namer.fieldAccessorName(field);
- jsAst.Name fieldName = namer.fieldPropertyName(field);
- bool needsCheckedSetter = false;
- if (compiler.enableTypeAssertions
- && needsSetter
- && !canAvoidGeneratedCheckedSetter(field)) {
- needsCheckedSetter = true;
- needsSetter = false;
- }
- // Getters and setters with suffixes will be generated dynamically.
- f(field, fieldName, accessorName, needsGetter, needsSetter,
- needsCheckedSetter);
- }
- }
-
- if (isLibrary) {
- LibraryElement library = element;
- library.implementation.forEachLocalMember((Element member) {
- if (member.isField) visitField(library, member);
- });
- } else if (visitStatics) {
- ClassElement cls = element;
- cls.implementation.forEachStaticField(visitField);
- } else {
- ClassElement cls = element;
- // TODO(kasperl): We should make sure to only emit one version of
- // overridden fields. Right now, we rely on the ordering so the
- // fields pulled in from mixins are replaced with the fields from
- // the class definition.
-
- // If a class is not instantiated then we add the field just so we can
- // generate the field getter/setter dynamically. Since this is only
- // allowed on fields that are in [element] we don't need to visit
- // superclasses for non-instantiated classes.
- cls.implementation.forEachInstanceField(
- visitField, includeSuperAndInjectedMembers: isInstantiated);
- }
- }
-
void recordMangledField(Element member,
jsAst.Name accessorName,
String memberName) {
@@ -473,39 +376,6 @@
message: '$previousName != ${memberName}'));
}
- bool fieldNeedsGetter(VariableElement field) {
- assert(field.isField);
- if (fieldAccessNeverThrows(field)) return false;
- if (backend.shouldRetainGetter(field)) return true;
- return field.isClassMember &&
- compiler.codegenWorld.hasInvokedGetter(field, compiler.world);
- }
-
- bool fieldNeedsSetter(VariableElement field) {
- assert(field.isField);
- if (fieldAccessNeverThrows(field)) return false;
- if (field.isFinal || field.isConst) return false;
- if (backend.shouldRetainSetter(field)) return true;
- return field.isClassMember &&
- compiler.codegenWorld.hasInvokedSetter(field, compiler.world);
- }
-
- static bool fieldAccessNeverThrows(VariableElement field) {
- return
- // We never access a field in a closure (a captured variable) without
- // knowing that it is there. Therefore we don't need to use a getter
- // (that will throw if the getter method is missing), but can always
- // access the field directly.
- field is ClosureFieldElement;
- }
-
- bool canAvoidGeneratedCheckedSetter(VariableElement member) {
- // We never generate accessors for top-level/static fields.
- if (!member.isInstanceMember) return true;
- DartType type = member.type;
- return type.treatAsDynamic || (type.element == compiler.objectClass);
- }
-
void generateCheckedSetter(Element member,
jsAst.Name fieldName,
jsAst.Name accessorName,
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 568e2515..f777014 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
@@ -2,10 +2,10 @@
// 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 dart2js.js_emitter;
+part of dart2js.js_emitter.full_emitter;
class CodeEmitterHelper {
- OldEmitter emitter;
+ Emitter emitter;
Namer get namer => emitter.namer;
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/container_builder.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/container_builder.dart
index eeff7d5..b0a94ce 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/container_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/container_builder.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.
-part of dart2js.js_emitter;
+part of dart2js.js_emitter.full_emitter;
/// This class should morph into something that makes it easy to build
/// JavaScript representations of libraries, class-sides, and instance-sides.
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/declarations.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/declarations.dart
index 833abeb..01fda29 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/declarations.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/declarations.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.
-part of dart2js.js_emitter;
+part of dart2js.js_emitter.full_emitter;
/// Enables debugging of fast/slow objects using V8-specific primitives.
const DEBUG_FAST_OBJECTS = false;
@@ -13,37 +13,6 @@
typedef jsAst.Property AddPropertyFunction(jsAst.Name name,
jsAst.Expression value);
-/**
- * [member] is a field (instance, static, or top level).
- *
- * [name] is the field name that the [Namer] has picked for this field's
- * storage, that is, the JavaScript property name.
- *
- * [accessorName] is the name of the accessor. For instance fields this is
- * mostly the same as [name] except when [member] is shadowing a field in its
- * superclass. For other fields, they are rarely the same.
- *
- * [needsGetter] and [needsSetter] represent if a getter or a setter
- * respectively is needed. There are many factors in this, for example, if the
- * accessor can be inlined.
- *
- * [needsCheckedSetter] indicates that a checked getter is needed, and in this
- * case, [needsSetter] is always false. [needsCheckedSetter] is only true when
- * type assertions are enabled (checked mode).
- */
-typedef void AcceptField(VariableElement member,
- jsAst.Name name,
- jsAst.Name accessorName,
- bool needsGetter,
- bool needsSetter,
- bool needsCheckedSetter);
-
-// Function signatures used in the generation of runtime type information.
-typedef void FunctionTypeSignatureEmitter(Element method,
- FunctionType methodType);
-
-typedef void SubstitutionEmitter(Element element, {bool emitNull});
-
const String GENERATED_BY = """
// Generated by dart2js, the Dart to JavaScript compiler.
""";
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/deferred_output_unit_hash.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/deferred_output_unit_hash.dart
new file mode 100644
index 0000000..8c79a8b
--- /dev/null
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/deferred_output_unit_hash.dart
@@ -0,0 +1,24 @@
+// 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.
+
+part of dart2js.js_emitter.full_emitter;
+
+class _DeferredOutputUnitHash extends jsAst.DeferredString {
+ String _hash;
+ final OutputUnit _outputUnit;
+
+ _DeferredOutputUnitHash(this._outputUnit);
+
+ void setHash(String hash) {
+ assert(_hash == null);
+ _hash = hash;
+ }
+
+ String get value {
+ assert(_hash != null);
+ return '"$_hash"';
+ }
+
+ String toString() => "HashCode for ${_outputUnit} [$_hash]";
+}
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 ac0bd3a..278e356 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
@@ -2,13 +2,102 @@
// 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 dart2js.js_emitter;
+library dart2js.js_emitter.full_emitter;
+
+import 'dart:convert';
+import 'dart:collection' show HashMap;
+
+import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames;
+import 'package:js_runtime/shared/embedded_names.dart' show JsBuiltin;
+
+import '../js_emitter.dart' hide Emitter;
+import '../js_emitter.dart' as js_emitter show Emitter;
+
+import '../model.dart';
+import '../program_builder/program_builder.dart';
+
+import '../../common.dart';
+
+import '../../constants/values.dart';
+
+import '../../deferred_load.dart' show OutputUnit;
+
+import '../../elements/elements.dart' show
+ ConstructorBodyElement,
+ ElementKind,
+ FieldElement,
+ ParameterElement,
+ TypeVariableElement,
+ MethodElement,
+ MemberElement;
+
+import '../../hash/sha1.dart' show Hasher;
+
+import '../../io/code_output.dart';
+
+import '../../io/line_column_provider.dart' show
+ LineColumnCollector,
+ LineColumnProvider;
+
+import '../../io/source_map_builder.dart' show
+ SourceMapBuilder;
+
+import '../../js/js.dart' as jsAst;
+import '../../js/js.dart' show js;
+
+import '../../js_backend/js_backend.dart' show
+ CheckedModeHelper,
+ CompoundName,
+ ConstantEmitter,
+ CustomElementsAnalysis,
+ GetterName,
+ JavaScriptBackend,
+ JavaScriptConstantCompiler,
+ Namer,
+ RuntimeTypes,
+ SetterName,
+ Substitution,
+ TypeCheck,
+ TypeChecks,
+ TypeVariableHandler;
+
+import '../../util/characters.dart' show
+ $$,
+ $A,
+ $HASH,
+ $PERIOD,
+ $Z,
+ $a,
+ $z;
+
+import '../../util/uri_extras.dart' show
+ relativize;
+
+import '../../util/util.dart' show
+ NO_LOCATION_SPANNABLE,
+ equalElements;
+
+part 'class_builder.dart';
+part 'class_emitter.dart';
+part 'code_emitter_helper.dart';
+part 'container_builder.dart';
+part 'declarations.dart';
+part 'deferred_output_unit_hash.dart';
+part 'interceptor_emitter.dart';
+part 'nsm_emitter.dart';
+part 'setup_program_builder.dart';
-class OldEmitter implements Emitter {
+class Emitter implements js_emitter.Emitter {
final Compiler compiler;
final CodeEmitterTask task;
+ // The following fields will be set to copies of the program-builder's
+ // collector.
+ Map<OutputUnit, List<VariableElement>> outputStaticNonFinalFieldLists;
+ Map<OutputUnit, Set<LibraryElement>> outputLibraryLists;
+ List<TypedefElement> typedefsNeededForReflection;
+
final ContainerBuilder containerBuilder = new ContainerBuilder();
final ClassEmitter classEmitter = new ClassEmitter();
final NsmEmitter nsmEmitter = new NsmEmitter();
@@ -44,9 +133,6 @@
new HashMap<jsAst.Name, String>();
final Set<jsAst.Name> recordedMangledNames = new Set<jsAst.Name>();
- List<TypedefElement> get typedefsNeededForReflection =>
- task.typedefsNeededForReflection;
-
JavaScriptBackend get backend => compiler.backend;
TypeVariableHandler get typeVariableHandler => backend.typeVariableHandler;
@@ -83,7 +169,7 @@
final bool generateSourceMap;
- OldEmitter(Compiler compiler, Namer namer, this.generateSourceMap, this.task)
+ Emitter(Compiler compiler, Namer namer, this.generateSourceMap, this.task)
: this.compiler = compiler,
this.namer = namer,
cachedEmittedConstants = compiler.cacheStrategy.newSet(),
@@ -524,8 +610,7 @@
OutputUnit outputUnit) {
jsAst.Statement buildInitialization(Element element,
jsAst.Expression initialValue) {
- // Note: `namer.currentIsolate` refers to the isolate properties here.
- return js.statement('${namer.currentIsolate}.# = #',
+ return js.statement('${namer.staticStateHolder}.# = #',
[namer.globalPropertyName(element), initialValue]);
}
@@ -533,7 +618,7 @@
JavaScriptConstantCompiler handler = backend.constants;
List<jsAst.Statement> parts = <jsAst.Statement>[];
- Iterable<Element> fields = task.outputStaticNonFinalFieldLists[outputUnit];
+ Iterable<Element> fields = outputStaticNonFinalFieldLists[outputUnit];
// If the outputUnit does not contain any static non-final fields, then
// [fields] is `null`.
if (fields != null) {
@@ -545,10 +630,10 @@
}
}
- if (inMainUnit && task.outputStaticNonFinalFieldLists.length > 1) {
+ if (inMainUnit && outputStaticNonFinalFieldLists.length > 1) {
// In the main output-unit we output a stub initializer for deferred
// variables, so that `isolateProperties` stays a fast object.
- task.outputStaticNonFinalFieldLists.forEach(
+ outputStaticNonFinalFieldLists.forEach(
(OutputUnit fieldsOutputUnit, Iterable<VariableElement> fields) {
if (fieldsOutputUnit == outputUnit) return; // Skip the main unit.
for (Element element in fields) {
@@ -710,8 +795,8 @@
return js('${namer.isolateName}.#(#)', [makeConstListProperty, array]);
}
- jsAst.Statement buildMakeConstantList() {
- if (task.outputContainsConstantList) {
+ jsAst.Statement buildMakeConstantList(bool outputContainsConstantList) {
+ if (outputContainsConstantList) {
return js.statement(r'''
// Functions are stored in the hidden class and not as properties in
// the object. We never actually look at the value, but only want
@@ -758,7 +843,7 @@
return new jsAst.Block(parts);
}
- jsAst.Statement buildInitFunction() {
+ jsAst.Statement buildInitFunction(bool outputContainsConstantList) {
jsAst.Expression allClassesAccess =
generateEmbeddedGlobalAccess(embeddedNames.ALL_CLASSES);
jsAst.Expression getTypeFromNameAccess =
@@ -892,7 +977,7 @@
'needsLazyInitializer': needsLazyInitializer,
'lazies': laziesAccess, 'cyclicThrow': cyclicThrow,
'isolatePropertiesName': namer.isolatePropertiesName,
- 'outputContainsConstantList': task.outputContainsConstantList,
+ 'outputContainsConstantList': outputContainsConstantList,
'makeConstListProperty': makeConstListProperty,
'functionThatReturnsNullProperty':
backend.rti.getFunctionThatReturnsNullName,
@@ -1277,8 +1362,7 @@
checkEverythingEmitted(descriptors.keys);
- Iterable<LibraryElement> libraries =
- task.outputLibraryLists[mainOutputUnit];
+ Iterable<LibraryElement> libraries = outputLibraryLists[mainOutputUnit];
if (libraries == null) libraries = <LibraryElement>[];
List<jsAst.Expression> parts = <jsAst.Expression>[];
@@ -1381,7 +1465,7 @@
// We abuse the short name used for the isolate here to store
// the isolate properties. This is safe as long as the real isolate
// object does not exist yet.
- var ${namer.currentIsolate} = #isolatePropertiesName;
+ var ${namer.staticStateHolder} = #isolatePropertiesName;
// Constants in checked mode call into RTI code to set type information
// which may need getInterceptor (and one-shot interceptor) methods, so
@@ -1393,7 +1477,7 @@
// constants to be set up.
#staticNonFinalInitializers;
- ${namer.currentIsolate} = null;
+ ${namer.staticStateHolder} = null;
#deferredBoilerPlate;
@@ -1403,7 +1487,7 @@
#isolateName = $finishIsolateConstructorName(#isolateName);
- ${namer.currentIsolate} = new #isolateName();
+ ${namer.staticStateHolder} = new #isolateName();
#metadata;
@@ -1438,7 +1522,8 @@
"cspPrecompiledFunctions": buildCspPrecompiledFunctionFor(mainOutputUnit),
"getInterceptorMethods": interceptorEmitter.buildGetInterceptorMethods(),
"oneShotInterceptors": interceptorEmitter.buildOneShotInterceptors(),
- "makeConstantList": buildMakeConstantList(),
+ "makeConstantList":
+ buildMakeConstantList(program.outputContainsConstantList),
"compileTimeConstants": buildCompileTimeConstants(mainFragment.constants,
isMainFragment: true),
"deferredBoilerPlate": buildDeferredBoilerPlate(deferredLoadHashes),
@@ -1453,7 +1538,7 @@
"convertGlobalObjectsToFastObjects":
buildConvertGlobalObjectToFastObjects(),
"debugFastObjects": buildDebugFastObjectCode(),
- "init": buildInitFunction(),
+ "init": buildInitFunction(program.outputContainsConstantList),
"main": buildMain(mainFragment.invokeMain)
}));
@@ -1623,8 +1708,7 @@
Map<Element, ClassBuilder> descriptors = elementDescriptors[fragment];
if (descriptors != null && descriptors.isNotEmpty) {
- Iterable<LibraryElement> libraries =
- task.outputLibraryLists[outputUnit];
+ Iterable<LibraryElement> libraries = outputLibraryLists[outputUnit];
if (libraries == null) libraries = [];
// TODO(johnniwinther): Avoid creating [CodeBuffer]s.
@@ -1654,8 +1738,14 @@
}
int emitProgram(ProgramBuilder programBuilder) {
- Program program = programBuilder.buildProgram(
- storeFunctionTypesInMetadata: true);
+ Program program =
+ programBuilder.buildProgram(storeFunctionTypesInMetadata: true);
+
+ outputStaticNonFinalFieldLists =
+ programBuilder.collector.outputStaticNonFinalFieldLists;
+ outputLibraryLists = programBuilder.collector.outputLibraryLists;
+ typedefsNeededForReflection =
+ programBuilder.collector.typedefsNeededForReflection;
assembleProgram(program);
@@ -1710,7 +1800,6 @@
ClassBuilder getElementDescriptor(Element element, Fragment fragment) {
Element owner = element.library;
- bool isClass = false;
if (!element.isLibrary && !element.isTopLevel && !element.isNative) {
// For static (not top level) elements, record their code in a buffer
// specific to the class. For now, not supported for native classes and
@@ -1753,7 +1842,7 @@
// Function for initializing a loaded hunk, given its hash.
#initializeLoadedHunk = function(hunkHash) {
$deferredInitializers[hunkHash](
- #globalsHolder, ${namer.currentIsolate});
+ #globalsHolder, ${namer.staticStateHolder});
#deferredInitialized[hunkHash] = true;
};
}
@@ -1862,9 +1951,9 @@
..add(js.statement('${typesAccess}.push.apply(${typesAccess}, '
'${namer.deferredTypesName});'));
- // Set the currentIsolate variable to the current isolate (which is
- // provided as second argument).
- body.add(js.statement("${namer.currentIsolate} = arguments[1];"));
+ // Sets the static state variable to the state of the current isolate
+ // (which is provided as second argument).
+ body.add(js.statement("${namer.staticStateHolder} = arguments[1];"));
body.add(buildCompileTimeConstants(fragment.constants,
isMainFragment: false));
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/interceptor_emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/interceptor_emitter.dart
index 5605aa5..c9132ed 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/interceptor_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/interceptor_emitter.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.
-part of dart2js.js_emitter;
+part of dart2js.js_emitter.full_emitter;
class InterceptorEmitter extends CodeEmitterHelper {
final Set<jsAst.Name> interceptorInvocationNames =
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/nsm_emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/nsm_emitter.dart
index 5d7df35..7aa34bd 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/nsm_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/nsm_emitter.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.
-part of dart2js.js_emitter;
+part of dart2js.js_emitter.full_emitter;
class NsmEmitter extends CodeEmitterHelper {
final List<Selector> trivialNsmHandlers = <Selector>[];
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart
index 115ec4f..aa30bd9 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.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.
-part of dart2js.js_emitter;
+part of dart2js.js_emitter.full_emitter;
// TODO(ahe): Share these with js_helper.dart.
const FUNCTION_INDEX = 0;
@@ -29,7 +29,7 @@
jsAst.Statement buildSetupProgram(Program program, Compiler compiler,
JavaScriptBackend backend,
Namer namer,
- OldEmitter emitter) {
+ Emitter emitter) {
jsAst.Expression typeInformationAccess =
emitter.generateEmbeddedGlobalAccess(embeddedNames.TYPE_INFORMATION);
@@ -111,7 +111,7 @@
'inCspMode': compiler.useContentSecurityPolicy,
'deferredAction': namer.deferredAction,
'hasIsolateSupport': program.hasIsolateSupport,
- 'fieldNamesProperty': js.string(OldEmitter.FIELD_NAMES_PROPERTY_NAME),
+ 'fieldNamesProperty': js.string(Emitter.FIELD_NAMES_PROPERTY_NAME),
'hasIncrementalSupport': compiler.hasIncrementalSupport,
'incrementalHelper': namer.accessIncrementalHelper,
'createNewIsolateFunction': createNewIsolateFunctionAccess,
diff --git a/pkg/compiler/lib/src/js_emitter/helpers.dart b/pkg/compiler/lib/src/js_emitter/helpers.dart
index a5591ac..017094b 100644
--- a/pkg/compiler/lib/src/js_emitter/helpers.dart
+++ b/pkg/compiler/lib/src/js_emitter/helpers.dart
@@ -12,22 +12,3 @@
}
return mixin;
}
-
-class _DeferredOutputUnitHash extends jsAst.DeferredString {
- String _hash;
- final OutputUnit _outputUnit;
-
- _DeferredOutputUnitHash(this._outputUnit);
-
- void setHash(String hash) {
- assert(_hash == null);
- _hash = hash;
- }
-
- String get value {
- assert(_hash != null);
- return '"$_hash"';
- }
-
- String toString() => "HashCode for ${_outputUnit} [$_hash]";
-}
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/js_emitter/js_emitter.dart b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
index 4049f43..4c642eb 100644
--- a/pkg/compiler/lib/src/js_emitter/js_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
@@ -4,9 +4,6 @@
library dart2js.js_emitter;
-import 'dart:convert';
-import 'dart:collection' show HashMap;
-
import '../common.dart';
import '../constants/values.dart';
@@ -20,8 +17,6 @@
import '../dart_types.dart' show
TypedefType;
-import '../io/code_output.dart';
-
import '../elements/elements.dart' show
ConstructorBodyElement,
ElementKind,
@@ -31,8 +26,6 @@
MethodElement,
MemberElement;
-import '../hash/sha1.dart' show Hasher;
-
import '../js/js.dart' as jsAst;
import '../js/js.dart' show js;
@@ -58,37 +51,16 @@
import 'program_builder/program_builder.dart';
import 'lazy_emitter/emitter.dart' as lazy_js_emitter;
-
-import '../io/line_column_provider.dart' show
- LineColumnCollector,
- LineColumnProvider;
-
-import '../io/source_map_builder.dart' show
- SourceMapBuilder;
+import 'full_emitter/emitter.dart' as full_js_emitter;
import '../universe/universe.dart' show
TypeMaskSet,
TypedSelector;
-import '../util/characters.dart' show
- $$,
- $A,
- $HASH,
- $PERIOD,
- $Z,
- $a,
- $z;
-
import '../util/util.dart' show
NO_LOCATION_SPANNABLE,
Setlet;
-import '../util/uri_extras.dart' show
- relativize;
-
-import '../util/util.dart' show
- equalElements;
-
import '../deferred_load.dart' show
OutputUnit;
@@ -96,6 +68,7 @@
import 'package:js_runtime/shared/embedded_names.dart' show JsBuiltin;
import '../native/native.dart' as native;
+
part 'class_stub_generator.dart';
part 'code_emitter_task.dart';
part 'helpers.dart';
@@ -107,13 +80,3 @@
part 'parameter_stub_generator.dart';
part 'runtime_type_generator.dart';
part 'type_test_registry.dart';
-
-part 'full_emitter/class_builder.dart';
-part 'full_emitter/class_emitter.dart';
-part 'full_emitter/code_emitter_helper.dart';
-part 'full_emitter/container_builder.dart';
-part 'full_emitter/declarations.dart';
-part 'full_emitter/emitter.dart';
-part 'full_emitter/interceptor_emitter.dart';
-part 'full_emitter/nsm_emitter.dart';
-part 'full_emitter/setup_program_builder.dart';
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 0c3ae73..e8b7a5d 100644
--- a/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.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 dart2js.new_js_emitter.emitter;
+library dart2js.js_emitter.lazy_emitter;
import 'package:js_runtime/shared/embedded_names.dart' show
JsBuiltin,
@@ -47,13 +47,13 @@
return _emitter.emitProgram(program);
}
- // TODO(floitsch): copied from OldEmitter. Adjust or share.
+ // TODO(floitsch): copied from full emitter. Adjust or share.
@override
bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) {
return _emitter.isConstantInlinedOrAlreadyEmitted(constant);
}
- // TODO(floitsch): copied from OldEmitter. Adjust or share.
+ // TODO(floitsch): copied from full emitter. Adjust or share.
@override
int compareConstants(ConstantValue a, ConstantValue b) {
return _emitter.compareConstants(a, b);
diff --git a/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
index 6a05e29..ee7030e 100644
--- a/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.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 dart2js.new_js_emitter.model_emitter;
+library dart2js.js_emitter.lazy_emitter.model_emitter;
import '../../constants/values.dart' show ConstantValue, FunctionConstantValue;
import '../../dart2jslib.dart' show Compiler;
@@ -83,7 +83,7 @@
return false;
}
- // TODO(floitsch): copied from OldEmitter. Adjust or share.
+ // TODO(floitsch): copied from full emitter. Adjust or share.
int compareConstants(ConstantValue a, ConstantValue b) {
// Inlined constants don't affect the order and sometimes don't even have
// names.
@@ -305,7 +305,7 @@
}
if (program.hasIsolateSupport) {
- String isolateName = namer.currentIsolate;
+ String isolateName = namer.staticStateHolder;
globals.add(
new js.Property(js.string(CREATE_NEW_ISOLATE),
js.js('function () { return $isolateName; }')));
diff --git a/pkg/compiler/lib/src/js_emitter/model.dart b/pkg/compiler/lib/src/js_emitter/model.dart
index 6b06eec..b43c51c 100644
--- a/pkg/compiler/lib/src/js_emitter/model.dart
+++ b/pkg/compiler/lib/src/js_emitter/model.dart
@@ -83,7 +83,9 @@
class Holder {
final String name;
final int index;
- Holder(this.name, this.index);
+ final bool isStaticStateHolder;
+
+ Holder(this.name, this.index, {this.isStaticStateHolder: false});
}
/**
diff --git a/pkg/compiler/lib/src/js_emitter/native_emitter.dart b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
index 56bb8de..0d90d2f 100644
--- a/pkg/compiler/lib/src/js_emitter/native_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
@@ -6,7 +6,8 @@
class NativeEmitter {
- final Map<Element, ClassBuilder> cachedBuilders;
+ // TODO(floitsch): the native-emitter should not know about ClassBuilders.
+ final Map<Element, full_js_emitter.ClassBuilder> cachedBuilders;
final CodeEmitterTask emitterTask;
@@ -61,8 +62,16 @@
*
* [classes] contains native classes, mixin applications, and user subclasses
* of native classes.
+ *
+ * [interceptorClassesNeededByConstants] contains the interceptors that are
+ * referenced by constants.
+ *
+ * [classesModifiedByEmitRTISupport] contains the list of classes that must
+ * exist, because runtime-type support adds information to the class.
*/
- Set<Class> prepareNativeClasses(List<Class> classes) {
+ Set<Class> prepareNativeClasses(List<Class> classes,
+ Set<ClassElement> interceptorClassesNeededByConstants,
+ Set<ClassElement> classesModifiedByEmitRTISupport) {
assert(classes.every((Class cls) => cls != null));
hasNativeClasses = classes.isNotEmpty;
@@ -103,11 +112,6 @@
neededClasses.add(objectClass);
- Set<ClassElement> neededByConstant = emitterTask
- .computeInterceptorsReferencedFromConstants();
- Set<ClassElement> modifiedClasses = emitterTask.typeTestRegistry
- .computeClassesModifiedByEmitRuntimeTypeSupport();
-
for (Class cls in preOrder.reversed) {
ClassElement classElement = cls.element;
// Post-order traversal ensures we visit the subclasses before their
@@ -121,9 +125,9 @@
needed = true;
} else if (!isTrivialClass(cls)) {
needed = true;
- } else if (neededByConstant.contains(classElement)) {
+ } else if (interceptorClassesNeededByConstants.contains(classElement)) {
needed = true;
- } else if (modifiedClasses.contains(classElement)) {
+ } else if (classesModifiedByEmitRTISupport.contains(classElement)) {
// TODO(9556): Remove this test when [emitRuntimeTypeSupport] no longer
// adds information to a class prototype or constructor.
needed = true;
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart b/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart
new file mode 100644
index 0000000..62ba314
--- /dev/null
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart
@@ -0,0 +1,313 @@
+// 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 dart2js.js_emitter.program_builder;
+
+/**
+ * Generates the code for all used classes in the program. Static fields (even
+ * in classes) are ignored, since they can be treated as non-class elements.
+ *
+ * The code for the containing (used) methods must exist in the `universe`.
+ */
+class Collector {
+ // TODO(floitsch): the code-emitter task should not need a namer.
+ final Namer namer;
+ final Compiler compiler;
+ final Set<ClassElement> rtiNeededClasses;
+ final Emitter emitter;
+
+ final Set<ClassElement> neededClasses = new Set<ClassElement>();
+ // This field is set in [computeNeededDeclarations].
+ Set<ClassElement> classesOnlyNeededForRti;
+ final Map<OutputUnit, List<ClassElement>> outputClassLists =
+ new Map<OutputUnit, List<ClassElement>>();
+ final Map<OutputUnit, List<ConstantValue>> outputConstantLists =
+ new Map<OutputUnit, List<ConstantValue>>();
+ final Map<OutputUnit, List<Element>> outputStaticLists =
+ new Map<OutputUnit, List<Element>>();
+ final Map<OutputUnit, List<VariableElement>> outputStaticNonFinalFieldLists =
+ new Map<OutputUnit, List<VariableElement>>();
+ final Map<OutputUnit, Set<LibraryElement>> outputLibraryLists =
+ new Map<OutputUnit, Set<LibraryElement>>();
+
+ /// True, if the output contains a constant list.
+ ///
+ /// This flag is updated in [computeNeededConstants].
+ bool outputContainsConstantList = false;
+
+ final List<ClassElement> nativeClassesAndSubclasses = <ClassElement>[];
+
+ List<TypedefElement> typedefsNeededForReflection;
+
+ JavaScriptBackend get backend => compiler.backend;
+
+ Collector(this.compiler, this.namer, this.rtiNeededClasses, this.emitter);
+
+ Set<ClassElement> computeInterceptorsReferencedFromConstants() {
+ Set<ClassElement> classes = new Set<ClassElement>();
+ JavaScriptConstantCompiler handler = backend.constants;
+ List<ConstantValue> constants = handler.getConstantsForEmission();
+ for (ConstantValue constant in constants) {
+ if (constant is InterceptorConstantValue) {
+ InterceptorConstantValue interceptorConstant = constant;
+ classes.add(interceptorConstant.dispatchedType.element);
+ }
+ }
+ return classes;
+ }
+
+ /**
+ * Return a function that returns true if its argument is a class
+ * that needs to be emitted.
+ */
+ Function computeClassFilter() {
+ if (backend.isTreeShakingDisabled) return (ClassElement cls) => true;
+
+ Set<ClassElement> unneededClasses = new Set<ClassElement>();
+ // The [Bool] class is not marked as abstract, but has a factory
+ // constructor that always throws. We never need to emit it.
+ unneededClasses.add(compiler.boolClass);
+
+ // Go over specialized interceptors and then constants to know which
+ // interceptors are needed.
+ Set<ClassElement> needed = new Set<ClassElement>();
+ backend.specializedGetInterceptors.forEach(
+ (_, Iterable<ClassElement> elements) {
+ needed.addAll(elements);
+ }
+ );
+
+ // Add interceptors referenced by constants.
+ needed.addAll(computeInterceptorsReferencedFromConstants());
+
+ // Add unneeded interceptors to the [unneededClasses] set.
+ for (ClassElement interceptor in backend.interceptedClasses) {
+ if (!needed.contains(interceptor)
+ && interceptor != compiler.objectClass) {
+ unneededClasses.add(interceptor);
+ }
+ }
+
+ // These classes are just helpers for the backend's type system.
+ unneededClasses.add(backend.jsMutableArrayClass);
+ unneededClasses.add(backend.jsFixedArrayClass);
+ unneededClasses.add(backend.jsExtendableArrayClass);
+ unneededClasses.add(backend.jsUInt32Class);
+ unneededClasses.add(backend.jsUInt31Class);
+ unneededClasses.add(backend.jsPositiveIntClass);
+
+ return (ClassElement cls) => !unneededClasses.contains(cls);
+ }
+
+ /**
+ * Compute all the constants that must be emitted.
+ */
+ void computeNeededConstants() {
+ // Make sure we retain all metadata of all elements. This could add new
+ // constants to the handler.
+ if (backend.mustRetainMetadata) {
+ // TODO(floitsch): verify that we don't run through the same elements
+ // multiple times.
+ for (Element element in backend.generatedCode.keys) {
+ if (backend.isAccessibleByReflection(element)) {
+ bool shouldRetainMetadata = backend.retainMetadataOf(element);
+ if (shouldRetainMetadata &&
+ (element.isFunction || element.isConstructor ||
+ element.isSetter)) {
+ FunctionElement function = element;
+ function.functionSignature.forEachParameter(
+ backend.retainMetadataOf);
+ }
+ }
+ }
+ for (ClassElement cls in neededClasses) {
+ final onlyForRti = classesOnlyNeededForRti.contains(cls);
+ if (!onlyForRti) {
+ backend.retainMetadataOf(cls);
+ new FieldVisitor(compiler, namer).visitFields(cls, false,
+ (Element member,
+ js.Name name,
+ js.Name accessorName,
+ bool needsGetter,
+ bool needsSetter,
+ bool needsCheckedSetter) {
+ bool needsAccessor = needsGetter || needsSetter;
+ if (needsAccessor && backend.isAccessibleByReflection(member)) {
+ backend.retainMetadataOf(member);
+ }
+ });
+ }
+ }
+ typedefsNeededForReflection.forEach(backend.retainMetadataOf);
+ }
+
+ JavaScriptConstantCompiler handler = backend.constants;
+ List<ConstantValue> constants = handler.getConstantsForEmission(
+ compiler.hasIncrementalSupport ? null : emitter.compareConstants);
+ for (ConstantValue constant in constants) {
+ if (emitter.isConstantInlinedOrAlreadyEmitted(constant)) continue;
+
+ if (constant.isList) outputContainsConstantList = true;
+
+ OutputUnit constantUnit =
+ compiler.deferredLoadTask.outputUnitForConstant(constant);
+ if (constantUnit == null) {
+ // The back-end introduces some constants, like "InterceptorConstant" or
+ // some list constants. They are emitted in the main output-unit.
+ // TODO(sigurdm): We should track those constants.
+ constantUnit = compiler.deferredLoadTask.mainOutputUnit;
+ }
+ outputConstantLists.putIfAbsent(
+ constantUnit, () => new List<ConstantValue>()).add(constant);
+ }
+ }
+
+ /// Compute all the classes and typedefs that must be emitted.
+ void computeNeededDeclarations() {
+ // Compute needed typedefs.
+ typedefsNeededForReflection = Elements.sortedByPosition(
+ compiler.world.allTypedefs
+ .where(backend.isAccessibleByReflection)
+ .toList());
+
+ // Compute needed classes.
+ Set<ClassElement> instantiatedClasses =
+ compiler.codegenWorld.directlyInstantiatedClasses
+ .where(computeClassFilter()).toSet();
+
+ void addClassWithSuperclasses(ClassElement cls) {
+ neededClasses.add(cls);
+ for (ClassElement superclass = cls.superclass;
+ superclass != null;
+ superclass = superclass.superclass) {
+ neededClasses.add(superclass);
+ }
+ }
+
+ void addClassesWithSuperclasses(Iterable<ClassElement> classes) {
+ for (ClassElement cls in classes) {
+ addClassWithSuperclasses(cls);
+ }
+ }
+
+ // 1. We need to generate all classes that are instantiated.
+ addClassesWithSuperclasses(instantiatedClasses);
+
+ // 2. Add all classes used as mixins.
+ Set<ClassElement> mixinClasses = neededClasses
+ .where((ClassElement element) => element.isMixinApplication)
+ .map(computeMixinClass)
+ .toSet();
+ neededClasses.addAll(mixinClasses);
+
+ // 3. Find all classes needed for rti.
+ // It is important that this is the penultimate step, at this point,
+ // neededClasses must only contain classes that have been resolved and
+ // codegen'd. The rtiNeededClasses may contain additional classes, but
+ // these are thought to not have been instantiated, so we neeed to be able
+ // to identify them later and make sure we only emit "empty shells" without
+ // fields, etc.
+ classesOnlyNeededForRti = rtiNeededClasses.difference(neededClasses);
+
+ neededClasses.addAll(classesOnlyNeededForRti);
+
+ // TODO(18175, floitsch): remove once issue 18175 is fixed.
+ if (neededClasses.contains(backend.jsIntClass)) {
+ neededClasses.add(compiler.intClass);
+ }
+ if (neededClasses.contains(backend.jsDoubleClass)) {
+ neededClasses.add(compiler.doubleClass);
+ }
+ if (neededClasses.contains(backend.jsNumberClass)) {
+ neededClasses.add(compiler.numClass);
+ }
+ if (neededClasses.contains(backend.jsStringClass)) {
+ neededClasses.add(compiler.stringClass);
+ }
+ if (neededClasses.contains(backend.jsBoolClass)) {
+ neededClasses.add(compiler.boolClass);
+ }
+ if (neededClasses.contains(backend.jsArrayClass)) {
+ neededClasses.add(compiler.listClass);
+ }
+
+ // 4. Finally, sort the classes.
+ List<ClassElement> sortedClasses = Elements.sortedByPosition(neededClasses);
+
+ for (ClassElement element in sortedClasses) {
+ if (Elements.isNativeOrExtendsNative(element) &&
+ !classesOnlyNeededForRti.contains(element)) {
+ // For now, native classes and related classes cannot be deferred.
+ nativeClassesAndSubclasses.add(element);
+ assert(invariant(element,
+ !compiler.deferredLoadTask.isDeferred(element)));
+ outputClassLists.putIfAbsent(compiler.deferredLoadTask.mainOutputUnit,
+ () => new List<ClassElement>()).add(element);
+ } else {
+ outputClassLists.putIfAbsent(
+ compiler.deferredLoadTask.outputUnitForElement(element),
+ () => new List<ClassElement>())
+ .add(element);
+ }
+ }
+ }
+
+ void computeNeededStatics() {
+ bool isStaticFunction(Element element) =>
+ !element.isInstanceMember && !element.isField;
+
+ Iterable<Element> elements =
+ backend.generatedCode.keys.where(isStaticFunction);
+
+ for (Element element in Elements.sortedByPosition(elements)) {
+ List<Element> list = outputStaticLists.putIfAbsent(
+ compiler.deferredLoadTask.outputUnitForElement(element),
+ () => new List<Element>());
+ list.add(element);
+ }
+ }
+
+ void computeNeededStaticNonFinalFields() {
+ JavaScriptConstantCompiler handler = backend.constants;
+ addToOutputUnit(Element element) {
+ List<VariableElement> list = outputStaticNonFinalFieldLists.putIfAbsent(
+ compiler.deferredLoadTask.outputUnitForElement(element),
+ () => new List<VariableElement>());
+ list.add(element);
+ }
+
+ Iterable<VariableElement> staticNonFinalFields = handler
+ .getStaticNonFinalFieldsForEmission()
+ .where(compiler.codegenWorld.allReferencedStaticFields.contains);
+
+ Elements.sortedByPosition(staticNonFinalFields).forEach(addToOutputUnit);
+
+ // We also need to emit static const fields if they are available for
+ // reflection.
+ compiler.codegenWorld.allReferencedStaticFields
+ .where((FieldElement field) => field.isConst)
+ .where(backend.isAccessibleByReflection)
+ .forEach(addToOutputUnit);
+ }
+
+ void computeNeededLibraries() {
+ void addSurroundingLibraryToSet(Element element) {
+ OutputUnit unit = compiler.deferredLoadTask.outputUnitForElement(element);
+ LibraryElement library = element.library;
+ outputLibraryLists.putIfAbsent(unit, () => new Set<LibraryElement>())
+ .add(library);
+ }
+
+ backend.generatedCode.keys.forEach(addSurroundingLibraryToSet);
+ neededClasses.forEach(addSurroundingLibraryToSet);
+ }
+
+ void collect() {
+ computeNeededDeclarations();
+ computeNeededConstants();
+ computeNeededStatics();
+ computeNeededStaticNonFinalFields();
+ computeNeededLibraries();
+ }
+}
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart b/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
new file mode 100644
index 0000000..0388bc9
--- /dev/null
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
@@ -0,0 +1,170 @@
+// 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 dart2js.js_emitter.program_builder;
+
+/**
+ * [member] is a field (instance, static, or top level).
+ *
+ * [name] is the field name that the [Namer] has picked for this field's
+ * storage, that is, the JavaScript property name.
+ *
+ * [accessorName] is the name of the accessor. For instance fields this is
+ * mostly the same as [name] except when [member] is shadowing a field in its
+ * superclass. For other fields, they are rarely the same.
+ *
+ * [needsGetter] and [needsSetter] represent if a getter or a setter
+ * respectively is needed. There are many factors in this, for example, if the
+ * accessor can be inlined.
+ *
+ * [needsCheckedSetter] indicates that a checked getter is needed, and in this
+ * case, [needsSetter] is always false. [needsCheckedSetter] is only true when
+ * type assertions are enabled (checked mode).
+ */
+typedef void AcceptField(VariableElement member,
+ js.Name name,
+ js.Name accessorName,
+ bool needsGetter,
+ bool needsSetter,
+ bool needsCheckedSetter);
+
+
+class FieldVisitor {
+ final Compiler compiler;
+ final Namer namer;
+
+ JavaScriptBackend get backend => compiler.backend;
+
+ FieldVisitor(this.compiler, this.namer);
+
+ /**
+ * Invokes [f] for each of the fields of [element].
+ *
+ * [element] must be a [ClassElement] or a [LibraryElement].
+ *
+ * If [element] is a [ClassElement], the static fields of the class are
+ * visited if [visitStatics] is true and the instance fields are visited if
+ * [visitStatics] is false.
+ *
+ * If [element] is a [LibraryElement], [visitStatics] must be true.
+ *
+ * When visiting the instance fields of a class, the fields of its superclass
+ * are also visited if the class is instantiated.
+ *
+ * Invariant: [element] must be a declaration element.
+ */
+ void visitFields(Element element, bool visitStatics, AcceptField f) {
+ assert(invariant(element, element.isDeclaration));
+
+ bool isClass = false;
+ bool isLibrary = false;
+ if (element.isClass) {
+ isClass = true;
+ } else if (element.isLibrary) {
+ isLibrary = true;
+ assert(invariant(element, visitStatics));
+ } else {
+ throw new SpannableAssertionFailure(
+ element, 'Expected a ClassElement or a LibraryElement.');
+ }
+
+ // If the class is never instantiated we still need to set it up for
+ // inheritance purposes, but we can simplify its JavaScript constructor.
+ bool isInstantiated =
+ compiler.codegenWorld.directlyInstantiatedClasses.contains(element);
+
+ void visitField(Element holder, FieldElement field) {
+ assert(invariant(element, field.isDeclaration));
+
+ // Keep track of whether or not we're dealing with a field mixin
+ // into a native class.
+ bool isMixinNativeField =
+ isClass && element.isNative && holder.isMixinApplication;
+
+ // See if we can dynamically create getters and setters.
+ // We can only generate getters and setters for [element] since
+ // the fields of super classes could be overwritten with getters or
+ // setters.
+ bool needsGetter = false;
+ bool needsSetter = false;
+ if (isLibrary || isMixinNativeField || holder == element) {
+ needsGetter = fieldNeedsGetter(field);
+ needsSetter = fieldNeedsSetter(field);
+ }
+
+ if ((isInstantiated && !holder.isNative)
+ || needsGetter
+ || needsSetter) {
+ js.Name accessorName = namer.fieldAccessorName(field);
+ js.Name fieldName = namer.fieldPropertyName(field);
+ bool needsCheckedSetter = false;
+ if (compiler.enableTypeAssertions
+ && needsSetter
+ && !canAvoidGeneratedCheckedSetter(field)) {
+ needsCheckedSetter = true;
+ needsSetter = false;
+ }
+ // Getters and setters with suffixes will be generated dynamically.
+ f(field, fieldName, accessorName, needsGetter, needsSetter,
+ needsCheckedSetter);
+ }
+ }
+
+ if (isLibrary) {
+ LibraryElement library = element;
+ library.implementation.forEachLocalMember((Element member) {
+ if (member.isField) visitField(library, member);
+ });
+ } else if (visitStatics) {
+ ClassElement cls = element;
+ cls.implementation.forEachStaticField(visitField);
+ } else {
+ ClassElement cls = element;
+ // TODO(kasperl): We should make sure to only emit one version of
+ // overridden fields. Right now, we rely on the ordering so the
+ // fields pulled in from mixins are replaced with the fields from
+ // the class definition.
+
+ // If a class is not instantiated then we add the field just so we can
+ // generate the field getter/setter dynamically. Since this is only
+ // allowed on fields that are in [element] we don't need to visit
+ // superclasses for non-instantiated classes.
+ cls.implementation.forEachInstanceField(
+ visitField, includeSuperAndInjectedMembers: isInstantiated);
+ }
+ }
+
+ bool fieldNeedsGetter(VariableElement field) {
+ assert(field.isField);
+ if (fieldAccessNeverThrows(field)) return false;
+ if (backend.shouldRetainGetter(field)) return true;
+ return field.isClassMember &&
+ compiler.codegenWorld.hasInvokedGetter(field, compiler.world);
+ }
+
+ bool fieldNeedsSetter(VariableElement field) {
+ assert(field.isField);
+ if (fieldAccessNeverThrows(field)) return false;
+ if (field.isFinal || field.isConst) return false;
+ if (backend.shouldRetainSetter(field)) return true;
+ return field.isClassMember &&
+ compiler.codegenWorld.hasInvokedSetter(field, compiler.world);
+ }
+
+ static bool fieldAccessNeverThrows(VariableElement field) {
+ return
+ // We never access a field in a closure (a captured variable) without
+ // knowing that it is there. Therefore we don't need to use a getter
+ // (that will throw if the getter method is missing), but can always
+ // access the field directly.
+ field is ClosureFieldElement;
+ }
+
+ bool canAvoidGeneratedCheckedSetter(VariableElement member) {
+ // We never generate accessors for top-level/static fields.
+ if (!member.isInstanceMember) return true;
+ DartType type = member.type;
+ return type.treatAsDynamic || (type.element == compiler.objectClass);
+ }
+}
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index b4a9c37..deadcb7 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -4,10 +4,11 @@
library dart2js.js_emitter.program_builder;
-import '../js_emitter.dart' show computeMixinClass;
+import '../js_emitter.dart' show computeMixinClass, Emitter;
import '../model.dart';
import '../../common.dart';
+import '../../closure.dart' show ClosureFieldElement;
import '../../js/js.dart' as js;
import '../../js_backend/js_backend.dart' show
@@ -24,12 +25,17 @@
RuntimeTypeGenerator,
TypeTestProperties;
-import '../../elements/elements.dart' show ParameterElement, MethodElement;
+import '../../elements/elements.dart' show
+ FieldElement,
+ MethodElement,
+ ParameterElement;
import '../../universe/universe.dart' show Universe, TypeMaskSet;
import '../../deferred_load.dart' show DeferredLoadTask, OutputUnit;
+part 'collector.dart';
part 'registry.dart';
+part 'field_visitor.dart';
/// Builds a self-contained representation of the program that can then be
/// emitted more easily by the individual emitters.
@@ -38,15 +44,27 @@
final Namer namer;
final CodeEmitterTask _task;
+ /// Contains the collected information the program builder used to build
+ /// the model.
+ // The collector will be filled on the first call to `buildProgram`.
+ // It is stored and publicly exposed for backwards compatibility. New code
+ // (and in particular new emitters) should not use it.
+ final Collector collector;
+
final Registry _registry;
/// True if the program should store function types in the metadata.
bool _storeFunctionTypesInMetadata = false;
ProgramBuilder(Compiler compiler,
- this.namer,
- this._task)
+ Namer namer,
+ this._task,
+ Emitter emitter,
+ Set<ClassElement> rtiNeededClasses)
: this._compiler = compiler,
+ this.namer = namer,
+ this.collector =
+ new Collector(compiler, namer, rtiNeededClasses, emitter),
this._registry = new Registry(compiler);
JavaScriptBackend get backend => _compiler.backend;
@@ -67,25 +85,28 @@
Set<Class> _unneededNativeClasses;
Program buildProgram({bool storeFunctionTypesInMetadata: false}) {
+ collector.collect();
+
this._storeFunctionTypesInMetadata = storeFunctionTypesInMetadata;
// Note: In rare cases (mostly tests) output units can be empty. This
// happens when the deferred code is dead-code eliminated but we still need
// to check that the library has been loaded.
_compiler.deferredLoadTask.allOutputUnits.forEach(
_registry.registerOutputUnit);
- _task.outputClassLists.forEach(_registry.registerElements);
- _task.outputStaticLists.forEach(_registry.registerElements);
- _task.outputConstantLists.forEach(_registerConstants);
- _task.outputStaticNonFinalFieldLists.forEach(_registry.registerElements);
+ collector.outputClassLists.forEach(_registry.registerElements);
+ collector.outputStaticLists.forEach(_registry.registerElements);
+ collector.outputConstantLists.forEach(_registerConstants);
+ collector.outputStaticNonFinalFieldLists.forEach(
+ _registry.registerElements);
- // TODO(kasperl): There's code that implicitly needs access to the special
- // $ holder so we have to register that. Can we track if we have to?
- _registry.registerHolder(r'$');
+ // We always add the current isolate holder.
+ _registry.registerHolder(
+ namer.staticStateHolder, isStaticStateHolder: true);
// We need to run the native-preparation before we build the output. The
// preparation code, in turn needs the classes to be set up.
// We thus build the classes before building their containers.
- _task.outputClassLists.forEach((OutputUnit _, List<ClassElement> classes) {
+ collector.outputClassLists.forEach((OutputUnit _, List<ClassElement> classes) {
classes.forEach(_buildClass);
});
@@ -101,12 +122,19 @@
}
});
- List<Class> nativeClasses = _task.nativeClassesAndSubclasses
+ List<Class> nativeClasses = collector.nativeClassesAndSubclasses
.map((ClassElement classElement) => _classes[classElement])
.toList();
- _unneededNativeClasses =
- _task.nativeEmitter.prepareNativeClasses(nativeClasses);
+ Set<ClassElement> interceptorClassesNeededByConstants =
+ collector.computeInterceptorsReferencedFromConstants();
+ Set<ClassElement> classesModifiedByEmitRTISupport =
+ _task.typeTestRegistry.computeClassesModifiedByEmitRuntimeTypeSupport();
+
+
+ _unneededNativeClasses = _task.nativeEmitter.prepareNativeClasses(
+ nativeClasses, interceptorClassesNeededByConstants,
+ classesModifiedByEmitRTISupport);
MainFragment mainFragment = _buildMainFragment(_registry.mainLibrariesMap);
Iterable<Fragment> deferredFragments =
@@ -139,7 +167,7 @@
_task.metadataCollector,
finalizers,
needsNativeSupport: needsNativeSupport,
- outputContainsConstantList: _task.outputContainsConstantList,
+ outputContainsConstantList: collector.outputContainsConstantList,
hasIsolateSupport: _compiler.hasIsolateSupport);
}
@@ -200,7 +228,7 @@
List<Constant> _buildConstants(LibrariesMap librariesMap) {
List<ConstantValue> constantValues =
- _task.outputConstantLists[librariesMap.outputUnit];
+ collector.outputConstantLists[librariesMap.outputUnit];
if (constantValues == null) return const <Constant>[];
return constantValues.map((ConstantValue value) => _constants[value])
.toList(growable: false);
@@ -208,7 +236,7 @@
List<StaticField> _buildStaticNonFinalFields(LibrariesMap librariesMap) {
List<VariableElement> staticNonFinalFields =
- _task.outputStaticNonFinalFieldLists[librariesMap.outputUnit];
+ collector.outputStaticNonFinalFieldLists[librariesMap.outputUnit];
if (staticNonFinalFields == null) return const <StaticField>[];
return staticNonFinalFields
@@ -325,7 +353,7 @@
}
Class _buildClass(ClassElement element) {
- bool onlyForRti = _task.classesOnlyNeededForRti.contains(element);
+ bool onlyForRti = collector.classesOnlyNeededForRti.contains(element);
List<Method> methods = [];
List<StubMethod> callStubs = <StubMethod>[];
@@ -638,7 +666,7 @@
List<Field> _buildFields(Element holder, bool visitStatics) {
List<Field> fields = <Field>[];
- _task.oldEmitter.classEmitter.visitFields(
+ new FieldVisitor(_compiler, namer).visitFields(
holder, visitStatics, (VariableElement field,
js.Name name,
js.Name accessorName,
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/registry.dart b/pkg/compiler/lib/src/js_emitter/program_builder/registry.dart
index ab7aa52..2fe3e12 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/registry.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/registry.dart
@@ -113,9 +113,10 @@
// Ignore for now.
}
- Holder registerHolder(String name) {
- return _holdersMap.putIfAbsent(
- name,
- () => new Holder(name, _holdersMap.length));
+ Holder registerHolder(String name, {bool isStaticStateHolder: false}) {
+ return _holdersMap.putIfAbsent(name, () {
+ return new Holder(name, _holdersMap.length,
+ isStaticStateHolder: isStaticStateHolder);
+ });
}
}
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 52c4352..b5e1a57 100644
--- a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
@@ -4,6 +4,12 @@
part of dart2js.js_emitter;
+// Function signatures used in the generation of runtime type information.
+typedef void FunctionTypeSignatureEmitter(Element method,
+ FunctionType methodType);
+
+typedef void SubstitutionEmitter(Element element, {bool emitNull});
+
class TypeTestProperties {
/// The index of the function type into the metadata.
///
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index 9719345..96961f3 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -46,7 +46,12 @@
Scope scope;
ClassElement currentClass;
ExpressionStatement currentExpressionStatement;
+
+ /// `true` if a [Send] or [SendSet] is visited as the prefix of member access.
+ /// For instance `Class` in `Class.staticField` or `prefix.Class` in
+ /// `prefix.Class.staticMethod()`.
bool sendIsMemberAccess = false;
+
StatementScope statementScope;
int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION
| ElementCategory.IMPLIES_TYPE;
@@ -1332,7 +1337,7 @@
if (leftResult.isConstant && rightResult.isConstant) {
bool isValidConstant;
ConstantExpression leftConstant = leftResult.constant;
- ConstantExpression rightConstant = leftResult.constant;
+ ConstantExpression rightConstant = rightResult.constant;
DartType knownLeftType = leftConstant.getKnownType(coreTypes);
DartType knownRightType = rightConstant.getKnownType(coreTypes);
switch (operator.kind) {
@@ -1770,16 +1775,197 @@
}
}
+ /// Handle access to a type literal of type variable [element]. Like `T` or
+ /// `T()` where 'T' is type variable.
+ // TODO(johnniwinther): Remove [name] when [Selector] is not required for the
+ // the [GetStructure].
+ // TODO(johnniwinther): Remove [element] when it is no longer needed for
+ // evaluating constants.
+ ResolutionResult handleTypeVariableTypeLiteralAccess(
+ Send node,
+ Name name,
+ TypeVariableElement element) {
+ if (!Elements.hasAccessToTypeVariables(enclosingElement)) {
+ compiler.reportError(node,
+ MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER,
+ {'typeVariableName': node.selector});
+ // TODO(johnniwinther): Add another access semantics for this.
+ }
+ registry.registerClassUsingVariableExpression(element.enclosingClass);
+ registry.registerTypeVariableExpression();
+
+ AccessSemantics semantics =
+ new StaticAccess.typeParameterTypeLiteral(element);
+ registry.useElement(node, element);
+ registry.registerTypeLiteral(node, element.type);
+
+ if (node.isCall) {
+ CallStructure callStructure =
+ resolveArguments(node.argumentsNode).callStructure;
+ Selector selector = callStructure.callSelector;
+ // TODO(johnniwinther): Remove this when all information goes through
+ // the [SendStructure].
+ registry.setSelector(node, selector);
+
+ registry.registerSendStructure(node,
+ new InvokeStructure(semantics, selector));
+ } else {
+ // TODO(johnniwinther): Avoid the need for a [Selector] here.
+ registry.registerSendStructure(node,
+ new GetStructure(semantics,
+ new Selector(SelectorKind.GETTER, name, CallStructure.NO_ARGS)));
+ }
+ return const NoneResult();
+ }
+
+ /// Handle access to a constant type literal of [type].
+ // TODO(johnniwinther): Remove [name] when [Selector] is not required for the
+ // the [GetStructure].
+ // TODO(johnniwinther): Remove [element] when it is no longer needed for
+ // evaluating constants.
+ ResolutionResult handleConstantTypeLiteralAccess(
+ Send node,
+ Name name,
+ TypeDeclarationElement element,
+ DartType type,
+ ConstantAccess semantics) {
+ registry.useElement(node, element);
+ registry.registerTypeLiteral(node, type);
+
+ if (node.isCall) {
+ CallStructure callStructure =
+ resolveArguments(node.argumentsNode).callStructure;
+ Selector selector = callStructure.callSelector;
+ // TODO(johnniwinther): Remove this when all information goes through
+ // the [SendStructure].
+ registry.setSelector(node, selector);
+
+ // The node itself is not a constant but we register the selector (the
+ // identifier that refers to the class/typedef) as a constant.
+ registry.useElement(node.selector, element);
+ analyzeConstantDeferred(node.selector, enforceConst: false);
+
+ registry.registerSendStructure(node,
+ new InvokeStructure(semantics, selector));
+ return const NoneResult();
+ } else {
+ analyzeConstantDeferred(node, enforceConst: false);
+
+ // TODO(johnniwinther): Avoid the need for a [Selector] here.
+ registry.registerSendStructure(node,
+ new GetStructure(semantics,
+ new Selector(SelectorKind.GETTER, name, CallStructure.NO_ARGS)));
+ return new ConstantResult(node, semantics.constant);
+ }
+ }
+
+ /// Handle access to a type literal of a typedef. Like `F` or
+ /// `F()` where 'F' is typedef.
+ ResolutionResult handleTypedefTypeLiteralAccess(
+ Send node,
+ Name name,
+ TypedefElement typdef) {
+ typdef.ensureResolved(compiler);
+ DartType type = typdef.rawType;
+ ConstantExpression constant = new TypeConstantExpression(type);
+ AccessSemantics semantics = new ConstantAccess.typedefTypeLiteral(constant);
+ return handleConstantTypeLiteralAccess(node, name, typdef, type, semantics);
+ }
+
+ /// Handle access to a type literal of the type 'dynamic'. Like `dynamic` or
+ /// `dynamic()`.
+ ResolutionResult handleDynamicTypeLiteralAccess(Send node) {
+ DartType type = const DynamicType();
+ ConstantExpression constant = new TypeConstantExpression(
+ // TODO(johnniwinther): Use [type] when evaluation of constants is done
+ // directly on the constant expressions.
+ node.isCall ? coreTypes.typeType : type);
+ AccessSemantics semantics = new ConstantAccess.dynamicTypeLiteral(constant);
+ return handleConstantTypeLiteralAccess(
+ node, const PublicName('dynamic'), compiler.typeClass, type, semantics);
+ }
+
+ /// Handle access to a type literal of a class. Like `C` or
+ /// `C()` where 'C' is class.
+ ResolutionResult handleClassTypeLiteralAccess(
+ Send node,
+ Name name,
+ ClassElement cls) {
+ DartType type = cls.rawType;
+ ConstantExpression constant = new TypeConstantExpression(type);
+ AccessSemantics semantics = new ConstantAccess.classTypeLiteral(constant);
+ return handleConstantTypeLiteralAccess(node, name, cls, type, semantics);
+ }
+
+ /// Handle a [Send] that resolves to a [prefix]. Like `prefix` in
+ /// `prefix.Class` or `prefix` in `prefix()`, the latter being a compile time
+ /// error.
+ ResolutionResult handleClassSend(
+ Send node,
+ Name name,
+ ClassElement cls) {
+ cls.ensureResolved(compiler);
+ if (sendIsMemberAccess) {
+ registry.useElement(node, cls);
+ return new ElementResult(cls);
+ } else {
+ // `C` or `C()` where 'C' is a class.
+ return handleClassTypeLiteralAccess(node, name, cls);
+ }
+ }
+
+ /// Handle qualified [Send] where the receiver resolves to a [prefix],
+ /// like `prefix.toplevelFunction()` or `prefix.Class.staticField` where
+ /// `prefix` is a library prefix.
+ ResolutionResult handleLibraryPrefixSend(
+ Send node, PrefixElement prefix, Name name) {
+ Element member = prefix.lookupLocalMember(name.text);
+ if (member == null) {
+ registry.registerThrowNoSuchMethod();
+ Element error = reportAndCreateErroneousElement(
+ node, name.text, MessageKind.NO_SUCH_LIBRARY_MEMBER,
+ {'libraryName': prefix.name, 'memberName': name});
+ registry.useElement(node, error);
+ return new ElementResult(error);
+ } else {
+ return handleResolvedSend(node, name, member);
+ }
+ }
+
+ /// Handle a [Send] that resolves to a [prefix]. Like `prefix` in
+ /// `prefix.Class` or `prefix` in `prefix()`, the latter being a compile time
+ /// error.
+ ResolutionResult handleLibraryPrefix(
+ Send node,
+ Name name,
+ PrefixElement prefix) {
+ if ((ElementCategory.PREFIX & allowedCategory) == 0) {
+ compiler.reportError(
+ node,
+ MessageKind.PREFIX_AS_EXPRESSION,
+ {'prefix': name});
+ return const NoneResult();
+ }
+ if (prefix.isDeferred) {
+ // TODO(johnniwinther): Remove this when deferred access is detected
+ // through a [SendStructure].
+ registry.useElement(node.selector, prefix);
+ }
+ registry.useElement(node, prefix);
+ return new ElementResult(prefix);
+ }
+
/// Handle qualified [Send] where the receiver resolves to an [Element], like
/// `a.b` where `a` is a local, field, class, or prefix, etc.
ResolutionResult handleResolvedQualifiedSend(
Send node, Name name, Element element) {
if (element.isPrefix) {
- return oldVisitSend(node);
+ return handleLibraryPrefixSend(node, element, name);
} else if (element.isClass) {
return handleStaticMemberAccess(node, name, element);
}
- return oldVisitSend(node);
+ // TODO(johnniwinther): Use the [element].
+ return handleDynamicPropertyAccess(node, name);
}
/// Handle dynamic access of [semantics].
@@ -1909,15 +2095,13 @@
Name name,
AmbiguousElement element) {
- compiler.reportError(
- node, element.messageKind, element.messageArguments);
- element.diagnose(enclosingElement, compiler);
-
- ErroneousElement error = new ErroneousElementX(
- element.messageKind,
- element.messageArguments,
+ ErroneousElement error = reportAndCreateErroneousElement(
+ node,
name.text,
- enclosingElement);
+ element.messageKind,
+ element.messageArguments);
+ element.diagnose(enclosingElement, compiler);
+ registry.registerThrowNoSuchMethod();
// TODO(johnniwinther): Support ambiguous access as an [AccessSemantics].
AccessSemantics accessSemantics = new StaticAccess.unresolved(error);
@@ -2055,6 +2239,15 @@
// of parse errors to make [element] erroneous. Fix this!
member.computeType(compiler);
+
+ if (member == compiler.mirrorSystemGetNameFunction &&
+ !compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) {
+ compiler.reportHint(
+ node.selector, MessageKind.STATIC_FUNCTION_BLOAT,
+ {'class': compiler.mirrorSystemClass.name,
+ 'name': compiler.mirrorSystemGetNameFunction.name});
+ }
+
Selector selector;
AccessSemantics semantics =
computeStaticOrTopLevelAccessSemantics(node, member);
@@ -2187,12 +2380,16 @@
return handleStaticInstanceSend(node, name, element);
}
}
- if (element.isClass || element.isTypedef) {
- return oldVisitSend(node);
+ if (element.isClass) {
+ // `C`, `C()`, or 'C.b` where 'C' is a class.
+ return handleClassSend(node, name, element);
+ } else if (element.isTypedef) {
+ // `F` or `F()` where 'F' is a typedef.
+ return handleTypedefTypeLiteralAccess(node, name, element);
} else if (element.isTypeVariable) {
- return oldVisitSend(node);
+ return handleTypeVariableTypeLiteralAccess(node, name, element);
} else if (element.isPrefix) {
- return oldVisitSend(node);
+ return handleLibraryPrefix(node, name, element);
} else if (element.isLocal) {
return handleLocalAccess(node, name, element);
} else if (element.isStatic || element.isTopLevel) {
@@ -2216,16 +2413,16 @@
} else if (text == 'this') {
// `this()`.
return handleThisAccess(node);
- } else if (text == 'dynamic') {
- // `dynamic` || `dynamic()`.
- // TODO(johnniwinther): Handle dynamic type literal access.
- return oldVisitSend(node);
}
// `name` or `name()`
Name name = new Name(text, enclosingElement.library);
Element element = lookupInScope(compiler, node, scope, text);
if (element == null) {
- if (inInstanceContext) {
+ if (text == 'dynamic') {
+ // `dynamic` or `dynamic()` where 'dynamic' is not declared in the
+ // current scope.
+ return handleDynamicTypeLiteralAccess(node);
+ } else if (inInstanceContext) {
// Implicitly `this.name`.
return handleThisPropertyAccess(node, name);
} else {
@@ -2262,101 +2459,6 @@
}
}
- ResolutionResult oldVisitSend(Send node) {
- bool oldSendIsMemberAccess = sendIsMemberAccess;
- sendIsMemberAccess = node.isPropertyAccess || node.isCall;
-
- ResolutionResult result = resolveSend(node);
- sendIsMemberAccess = oldSendIsMemberAccess;
-
- Element target = result.element;
-
- if (target != null
- && target == compiler.mirrorSystemGetNameFunction
- && !compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) {
- compiler.reportHint(
- node.selector, MessageKind.STATIC_FUNCTION_BLOAT,
- {'class': compiler.mirrorSystemClass.name,
- 'name': compiler.mirrorSystemGetNameFunction.name});
- }
-
- if (target != null) {
- if (target.isErroneous) {
- registry.registerThrowNoSuchMethod();
- } else if (target.isAbstractField) {
- AbstractFieldElement field = target;
- target = field.getter;
- if (target == null) {
- if (!inInstanceContext || field.isTopLevel || field.isStatic) {
- registry.registerThrowNoSuchMethod();
- target = reportAndCreateErroneousElement(node.selector, field.name,
- MessageKind.CANNOT_RESOLVE_GETTER, const {});
- }
- }
- } else if (target.isTypeVariable) {
- ClassElement cls = target.enclosingClass;
- assert(enclosingElement.enclosingClass == cls);
- if (!Elements.hasAccessToTypeVariables(enclosingElement)) {
- compiler.reportError(node,
- MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER,
- {'typeVariableName': node.selector});
- }
- registry.registerClassUsingVariableExpression(cls);
- registry.registerTypeVariableExpression();
- registerTypeLiteralAccess(node, target);
- } else if (target.impliesType && (!sendIsMemberAccess || node.isCall)) {
- registerTypeLiteralAccess(node, target);
- }
- registerPotentialAccessInClosure(node, target);
- }
-
- resolveArguments(node.argumentsNode);
-
- // If the selector is null, it means that we will not be generating
- // code for this as a send.
- Selector selector = registry.getSelector(node);
- if (selector == null) return const NoneResult();
-
- if (node.isCall) {
- if (Elements.isUnresolved(target) ||
- target.isGetter ||
- target.isField ||
- Elements.isClosureSend(node, target)) {
- // If we don't know what we're calling or if we are calling a getter,
- // we need to register that fact that we may be calling a closure
- // with the same arguments.
- Selector call = new Selector.callClosureFrom(selector);
- registry.registerDynamicInvocation(
- new UniverseSelector(selector, null));
- } else if (target.impliesType) {
- // We call 'call()' on a Type instance returned from the reference to a
- // class or typedef literal. We do not need to register this call as a
- // dynamic invocation, because we statically know what the target is.
- } else {
- if (target is FunctionElement) {
- FunctionElement function = target;
- function.computeType(compiler);
- }
- if (!selector.applies(target, compiler.world)) {
- registry.registerThrowNoSuchMethod();
- if (node.isSuperCall) {
- internalError(node, "Unexpected super call $node");
- }
- }
- }
-
- handleForeignCall(node, target, selector);
- }
-
- registry.useElement(node, target);
- registerSend(selector, target);
- if (node.isPropertyAccess && Elements.isStaticOrTopLevelFunction(target)) {
- registry.registerGetOfStaticFunction(target.declaration);
- }
- return node.isPropertyAccess
- ? new ResolutionResult.forElement(target) : const NoneResult();
- }
-
// TODO(johnniwinther): Move this to the backend resolution callbacks.
void handleForeignCall(Send node, Element target, Selector selector) {
if (target != null && compiler.backend.isForeign(target)) {
diff --git a/pkg/compiler/lib/src/scanner/array_based_scanner.dart b/pkg/compiler/lib/src/scanner/array_based_scanner.dart
index 85e3a3c..457be84 100644
--- a/pkg/compiler/lib/src/scanner/array_based_scanner.dart
+++ b/pkg/compiler/lib/src/scanner/array_based_scanner.dart
@@ -5,9 +5,8 @@
part of scanner;
abstract class ArrayBasedScanner extends AbstractScanner {
- ArrayBasedScanner(SourceFile file, bool includeComments,
- bool enableNullAwareOperators)
- : super(file, includeComments, enableNullAwareOperators);
+ ArrayBasedScanner(SourceFile file, bool includeComments)
+ : super(file, includeComments);
/**
* The stack of open groups, e.g [: { ... ( .. :]
diff --git a/pkg/compiler/lib/src/scanner/listener.dart b/pkg/compiler/lib/src/scanner/listener.dart
index b6c356a..ef9b651 100644
--- a/pkg/compiler/lib/src/scanner/listener.dart
+++ b/pkg/compiler/lib/src/scanner/listener.dart
@@ -746,9 +746,6 @@
break;
}
reportError(token, kind, arguments);
- } else if (token is UnsupportedNullAwareToken) {
- reportError(token, MessageKind.NULL_AWARE_OPERATORS_DISABLED,
- {'operator' : token.operator});
} else if (token is UnmatchedToken) {
String begin = token.begin.value;
String end = closeBraceFor(begin);
diff --git a/pkg/compiler/lib/src/scanner/scanner.dart b/pkg/compiler/lib/src/scanner/scanner.dart
index 65db47e..d9ab312 100644
--- a/pkg/compiler/lib/src/scanner/scanner.dart
+++ b/pkg/compiler/lib/src/scanner/scanner.dart
@@ -8,13 +8,11 @@
Token tokenize();
factory Scanner(SourceFile file,
- {bool includeComments: false, bool enableNullAwareOperators: false}) {
+ {bool includeComments: false}) {
if (file is Utf8BytesSourceFile) {
- return new Utf8BytesScanner(file, includeComments: includeComments,
- enableNullAwareOperators: enableNullAwareOperators);
+ return new Utf8BytesScanner(file, includeComments: includeComments);
} else {
- return new StringScanner(file, includeComments: includeComments,
- enableNullAwareOperators: enableNullAwareOperators);
+ return new StringScanner(file, includeComments: includeComments);
}
}
}
@@ -23,7 +21,6 @@
// TODO(ahe): Move this class to implementation.
final bool includeComments;
- final bool enableNullAwareOperators;
/**
* The string offset for the next token that will be created.
@@ -58,7 +55,7 @@
final List<int> lineStarts = <int>[0];
AbstractScanner(
- this.file, this.includeComments, this.enableNullAwareOperators) {
+ this.file, this.includeComments) {
this.tail = this.tokens;
}
@@ -458,27 +455,9 @@
// ? ?. ?? ??=
next = advance();
if (identical(next, $QUESTION)) {
- if (enableNullAwareOperators) {
- return select($EQ, QUESTION_QUESTION_EQ_INFO, QUESTION_QUESTION_INFO);
- } else {
- next = advance();
- PrecedenceInfo info;
- if (identical(next, $EQ)) {
- info = QUESTION_QUESTION_EQ_INFO;
- next = advance();
- } else {
- info = QUESTION_QUESTION_INFO;
- }
- appendErrorToken(new UnsupportedNullAwareToken(info.value, tokenStart));
- return next;
- }
+ return select($EQ, QUESTION_QUESTION_EQ_INFO, QUESTION_QUESTION_INFO);
} else if (identical(next, $PERIOD)) {
- if (enableNullAwareOperators) {
- appendPrecedenceToken(QUESTION_PERIOD_INFO);
- } else {
- appendErrorToken(new UnsupportedNullAwareToken(
- QUESTION_PERIOD_INFO.value, tokenStart));
- }
+ appendPrecedenceToken(QUESTION_PERIOD_INFO);
return advance();
} else {
appendPrecedenceToken(QUESTION_INFO);
diff --git a/pkg/compiler/lib/src/scanner/scanner_task.dart b/pkg/compiler/lib/src/scanner/scanner_task.dart
index e239026..636ee34 100644
--- a/pkg/compiler/lib/src/scanner/scanner_task.dart
+++ b/pkg/compiler/lib/src/scanner/scanner_task.dart
@@ -29,8 +29,7 @@
void scanElements(CompilationUnitElement compilationUnit) {
Script script = compilationUnit.script;
Token tokens = new Scanner(script.file,
- includeComments: compiler.preserveComments,
- enableNullAwareOperators: compiler.enableNullAwareOperators).tokenize();
+ includeComments: compiler.preserveComments).tokenize();
if (compiler.preserveComments) {
tokens = compiler.processAndStripComments(tokens);
}
diff --git a/pkg/compiler/lib/src/scanner/string_scanner.dart b/pkg/compiler/lib/src/scanner/string_scanner.dart
index 8eb736f..5a30e43 100644
--- a/pkg/compiler/lib/src/scanner/string_scanner.dart
+++ b/pkg/compiler/lib/src/scanner/string_scanner.dart
@@ -15,16 +15,14 @@
/** The current offset in [string]. */
int scanOffset = -1;
- StringScanner(SourceFile file, {bool includeComments: false,
- bool enableNullAwareOperators: false})
+ StringScanner(SourceFile file, {bool includeComments: false})
: string = file.slowText(),
- super(file, includeComments, enableNullAwareOperators) {
+ super(file, includeComments) {
ensureZeroTermination();
}
- StringScanner.fromString(this.string, {bool includeComments: false,
- bool enableNullAwareOperators: false})
- : super(null, includeComments, enableNullAwareOperators) {
+ StringScanner.fromString(this.string, {bool includeComments: false})
+ : super(null, includeComments) {
ensureZeroTermination();
}
diff --git a/pkg/compiler/lib/src/scanner/token.dart b/pkg/compiler/lib/src/scanner/token.dart
index c1a502b..c7c74d1 100644
--- a/pkg/compiler/lib/src/scanner/token.dart
+++ b/pkg/compiler/lib/src/scanner/token.dart
@@ -262,21 +262,6 @@
}
}
-// TODO(sigmund): delete once we enable null-aware-operators by default.
-class UnsupportedNullAwareToken extends ErrorToken {
- final String operator;
-
- UnsupportedNullAwareToken(this.operator, int charOffset)
- : super(charOffset);
-
- String toString() => "UnsupportedNullAwareToken($operator)";
-
- String get assertionMessage => "'$operator' isn't supported without "
- "the --enable-null-aware-operators flag.";
-
- int get charCount => operator.length;
-}
-
class UnterminatedToken extends ErrorToken {
final String start;
final int endOffset;
diff --git a/pkg/compiler/lib/src/scanner/utf8_bytes_scanner.dart b/pkg/compiler/lib/src/scanner/utf8_bytes_scanner.dart
index f242f57..d919596 100644
--- a/pkg/compiler/lib/src/scanner/utf8_bytes_scanner.dart
+++ b/pkg/compiler/lib/src/scanner/utf8_bytes_scanner.dart
@@ -69,10 +69,9 @@
* array whose last element is '0' to signal the end of the file. If this
* is not the case, the entire array is copied before scanning.
*/
- Utf8BytesScanner(SourceFile file, {bool includeComments: false,
- bool enableNullAwareOperators: false})
+ Utf8BytesScanner(SourceFile file, {bool includeComments: false})
: bytes = file.slowUtf8ZeroTerminatedBytes(),
- super(file, includeComments, enableNullAwareOperators) {
+ super(file, includeComments) {
assert(bytes.last == 0);
// Skip a leading BOM.
if (_containsBomAt(0)) byteOffset += 3;
@@ -86,10 +85,9 @@
* scanning.
*/
Utf8BytesScanner.fromBytes(List<int> zeroTerminatedBytes,
- {bool includeComments: false,
- bool enableNullAwareOperators: false})
+ {bool includeComments: false})
: this.bytes = zeroTerminatedBytes,
- super(null, includeComments, enableNullAwareOperators) {
+ super(null, includeComments) {
assert(bytes.last == 0);
}
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index f866a0f..1335674 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -2191,8 +2191,10 @@
constructorArguments,
instantiatedTypes);
if (function != null) {
+ // TODO(johnniwinther): Provide source information for creation
+ // through synthetic constructors.
newObject.sourceInformation =
- sourceInformationBuilder.buildGeneric(function);
+ sourceInformationBuilder.buildCreate(function);
}
add(newObject);
} else {
@@ -3147,7 +3149,7 @@
TypeMask type =
new TypeMask.nonNullExact(compiler.functionClass, compiler.world);
push(new HForeignNew(closureClassElement, type, capturedVariables)
- ..sourceInformation = sourceInformationBuilder.buildGeneric(node));
+ ..sourceInformation = sourceInformationBuilder.buildCreate(node));
Element methodElement = nestedClosureData.closureElement;
registry.registerInstantiatedClosure(methodElement);
@@ -4064,8 +4066,8 @@
if (!compiler.hasIsolateSupport) {
// If the isolate library is not used, we just generate code
- // to fetch the current isolate.
- String name = backend.namer.currentIsolate;
+ // to fetch the static state.
+ String name = backend.namer.staticStateHolder;
push(new HForeignCode(js.js.parseForeignJS(name),
backend.dynamicType,
<HInstruction>[]));
@@ -4331,13 +4333,13 @@
handleForeignRawFunctionRef(node, name);
}
- void handleForeignSetCurrentIsolate(ast.Send node) {
+ void handleForeignJsSetStaticState(ast.Send node) {
if (node.arguments.isEmpty || !node.arguments.tail.isEmpty) {
compiler.internalError(node.argumentsNode,
'Exactly one argument required.');
}
visit(node.arguments.head);
- String isolateName = backend.namer.currentIsolate;
+ String isolateName = backend.namer.staticStateHolder;
SideEffects sideEffects = new SideEffects.empty();
sideEffects.setAllSideEffects();
push(new HForeignCode(
@@ -4348,11 +4350,11 @@
effects: sideEffects));
}
- void handleForeignJsCurrentIsolate(ast.Send node) {
+ void handleForeignJsGetStaticState(ast.Send node) {
if (!node.arguments.isEmpty) {
compiler.internalError(node.argumentsNode, 'Too many arguments.');
}
- push(new HForeignCode(js.js.parseForeignJS(backend.namer.currentIsolate),
+ push(new HForeignCode(js.js.parseForeignJS(backend.namer.staticStateHolder),
backend.dynamicType,
<HInstruction>[]));
}
@@ -4369,10 +4371,10 @@
handleForeignDartClosureToJs(node, 'DART_CLOSURE_TO_JS');
} else if (name == 'RAW_DART_FUNCTION_REF') {
handleForeignRawFunctionRef(node, 'RAW_DART_FUNCTION_REF');
- } else if (name == 'JS_SET_CURRENT_ISOLATE') {
- handleForeignSetCurrentIsolate(node);
- } else if (name == 'JS_CURRENT_ISOLATE') {
- handleForeignJsCurrentIsolate(node);
+ } else if (name == 'JS_SET_STATIC_STATE') {
+ handleForeignJsSetStaticState(node);
+ } else if (name == 'JS_GET_STATIC_STATE') {
+ handleForeignJsGetStaticState(node);
} else if (name == 'JS_GET_NAME') {
handleForeignJsGetName(node);
} else if (name == 'JS_EMBEDDED_GLOBAL') {
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart b/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
index a6acceb..1820f1d 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
@@ -315,6 +315,24 @@
return node;
}
+ Expression visitGetLength(GetLength node) {
+ super.visitGetLength(node);
+ ++impureCounter;
+ return node;
+ }
+
+ Expression visitGetIndex(GetIndex node) {
+ super.visitGetIndex(node);
+ ++impureCounter;
+ return node;
+ }
+
+ Expression visitSetIndex(SetIndex node) {
+ super.visitSetIndex(node);
+ ++impureCounter;
+ return node;
+ }
+
void visitInnerFunction(FunctionDefinition node) {
new PullIntoInitializers().rewrite(node);
}
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
index be59dc9..6fda009 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
@@ -6,6 +6,7 @@
import 'optimization.dart' show Pass;
import '../tree_ir_nodes.dart';
+import '../../io/source_information.dart';
/**
* Translates to direct-style.
@@ -350,6 +351,7 @@
return exp is Constant ||
exp is This ||
exp is CreateInvocationMirror ||
+ exp is GetStatic && exp.element.isFunction ||
exp is Interceptor ||
exp is ApplyBuiltinOperator ||
exp is VariableUse && constantEnvironment.containsKey(exp.variable);
@@ -583,17 +585,15 @@
}
Statement visitIf(If node) {
- node.condition = visitExpression(node.condition);
-
- // Do not propagate assignments into branches. Doing so will lead to code
- // duplication.
- // TODO(kmillikin): Rethink this. Propagating some assignments
- // (e.g. variables) is benign. If they can occur here, they should
- // be handled well.
+ // Do not propagate assignments into branches.
inEmptyEnvironment(() {
node.thenStatement = visitStatement(node.thenStatement);
node.elseStatement = visitStatement(node.elseStatement);
+ });
+ node.condition = visitExpression(node.condition);
+
+ inEmptyEnvironment(() {
tryCollapseIf(node);
});
@@ -717,6 +717,24 @@
return node;
}
+ Expression visitGetLength(GetLength node) {
+ node.object = visitExpression(node.object);
+ return node;
+ }
+
+ Expression visitGetIndex(GetIndex node) {
+ node.index = visitExpression(node.index);
+ node.object = visitExpression(node.object);
+ return node;
+ }
+
+ Expression visitSetIndex(SetIndex node) {
+ node.value = visitExpression(node.value);
+ node.index = visitExpression(node.index);
+ node.object = visitExpression(node.object);
+ return node;
+ }
+
/// True if [operator] is a binary operator that always has the same value
/// if its arguments are swapped.
bool isSymmetricOperator(BuiltinOperator operator) {
@@ -907,7 +925,11 @@
if (s is Return && t is Return) {
CombinedExpressions values = combineExpressions(s.value, t.value);
if (values != null) {
- return new Return(values.combined);
+ // TODO(johnniwinther): Handle multiple source informations.
+ SourceInformation sourceInformation = s.sourceInformation != null
+ ? s.sourceInformation : t.sourceInformation;
+ return new Return(values.combined,
+ sourceInformation: sourceInformation);
}
}
if (s is ExpressionStatement && t is ExpressionStatement) {
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
index 6ca4430..47d7898 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
@@ -274,7 +274,8 @@
return new CreateInstance(
node.classElement,
translateArguments(node.arguments),
- translateArguments(node.typeInformation));
+ translateArguments(node.typeInformation),
+ node.sourceInformation);
}
Expression visitGetField(cps_ir.GetField node) {
@@ -355,10 +356,12 @@
}
Statement visitInvokeMethod(cps_ir.InvokeMethod node) {
- InvokeMethod invoke = new InvokeMethod(getVariableUse(node.receiver),
- node.selector,
- node.mask,
- translateArguments(node.arguments));
+ InvokeMethod invoke = new InvokeMethod(
+ getVariableUse(node.receiver),
+ node.selector,
+ node.mask,
+ translateArguments(node.arguments),
+ node.sourceInformation);
invoke.receiverIsNotNull = node.receiverIsNotNull;
return continueWithExpression(node.continuation, invoke);
}
@@ -367,7 +370,7 @@
Expression receiver = getVariableUse(node.receiver);
List<Expression> arguments = translateArguments(node.arguments);
Expression invoke = new InvokeMethodDirectly(receiver, node.target,
- node.selector, arguments);
+ node.selector, arguments, node.sourceInformation);
return continueWithExpression(node.continuation, invoke);
}
@@ -439,7 +442,8 @@
node.type,
node.target,
node.selector,
- arguments);
+ arguments,
+ node.sourceInformation);
return continueWithExpression(node.continuation, invoke);
}
@@ -452,7 +456,8 @@
cps_ir.Continuation cont = node.continuation.definition;
if (cont == returnContinuation) {
assert(node.arguments.length == 1);
- return new Return(getVariableUse(node.arguments.single));
+ return new Return(getVariableUse(node.arguments.single),
+ sourceInformation: node.sourceInformation);
} else {
List<Expression> arguments = translateArguments(node.arguments);
return buildPhiAssignments(cont.parameters, arguments,
@@ -500,7 +505,7 @@
}
Expression visitConstant(cps_ir.Constant node) {
- return new Constant(node.value);
+ return new Constant(node.value, sourceInformation: node.sourceInformation);
}
Expression visitLiteralList(cps_ir.LiteralList node) {
@@ -552,11 +557,15 @@
}
Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) {
- return new ReifyRuntimeType(getVariableUse(node.value));
+ return new ReifyRuntimeType(
+ getVariableUse(node.value), node.sourceInformation);
}
Expression visitReadTypeVariable(cps_ir.ReadTypeVariable node) {
- return new ReadTypeVariable(node.variable, getVariableUse(node.target));
+ return new ReadTypeVariable(
+ node.variable,
+ getVariableUse(node.target),
+ node.sourceInformation);
}
@override
@@ -612,5 +621,20 @@
node.dependency);
}
}
+
+ Expression visitGetLength(cps_ir.GetLength node) {
+ return new GetLength(getVariableUse(node.object));
+ }
+
+ Expression visitGetIndex(cps_ir.GetIndex node) {
+ return new GetIndex(getVariableUse(node.object),
+ getVariableUse(node.index));
+ }
+
+ Expression visitSetIndex(cps_ir.SetIndex node) {
+ return new SetIndex(getVariableUse(node.object),
+ getVariableUse(node.index),
+ getVariableUse(node.value));
+ }
}
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 b30c368..d922d09 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
@@ -201,11 +201,16 @@
final Selector selector;
final TypeMask mask;
final List<Expression> arguments;
+ final SourceInformation sourceInformation;
/// If true, it is known that the receiver cannot be `null`.
bool receiverIsNotNull = false;
- InvokeMethod(this.receiver, this.selector, this.mask, this.arguments) {
+ InvokeMethod(this.receiver,
+ this.selector,
+ this.mask,
+ this.arguments,
+ this.sourceInformation) {
assert(receiver != null);
}
@@ -224,9 +229,10 @@
final Element target;
final Selector selector;
final List<Expression> arguments;
+ final SourceInformation sourceInformation;
InvokeMethodDirectly(this.receiver, this.target, this.selector,
- this.arguments);
+ this.arguments, this.sourceInformation);
accept(ExpressionVisitor visitor) => visitor.visitInvokeMethodDirectly(this);
accept1(ExpressionVisitor1 visitor, arg) {
@@ -242,12 +248,13 @@
final FunctionElement target;
final List<Expression> arguments;
final Selector selector;
+ final SourceInformation sourceInformation;
/// TODO(karlklose): get rid of this field. Instead use the constant's
/// expression to find the constructor to be called in dart2dart.
final values.ConstantValue constant;
InvokeConstructor(this.type, this.target, this.selector, this.arguments,
- [this.constant]);
+ this.sourceInformation, [this.constant]);
ClassElement get targetClass => target.enclosingElement;
@@ -265,14 +272,18 @@
*/
class Constant extends Expression {
final values.ConstantValue value;
+ final SourceInformation sourceInformation;
- Constant(this.value);
+ Constant(this.value, {this.sourceInformation});
Constant.bool(values.BoolConstantValue constantValue)
- : value = constantValue;
+ : value = constantValue,
+ sourceInformation = null;
accept(ExpressionVisitor visitor) => visitor.visitConstant(this);
accept1(ExpressionVisitor1 visitor, arg) => visitor.visitConstant(this, arg);
+
+ String toString() => 'Constant(value=${value.toStructuredString()})';
}
class This extends Expression {
@@ -364,6 +375,9 @@
accept1(ExpressionVisitor1 visitor, arg) {
return visitor.visitConditional(this, arg);
}
+
+ String toString() => 'Conditional(condition=$condition,thenExpression='
+ '$thenExpression,elseExpression=$elseExpression)';
}
/// An && or || expression. The operator is internally represented as a boolean
@@ -383,6 +397,8 @@
accept1(ExpressionVisitor1 visitor, arg) {
return visitor.visitLogicalOperator(this, arg);
}
+
+ String toString() => 'LogicalOperator(left=$left,right=$right,isAnd=$isAnd)';
}
/// Logical negation.
@@ -541,11 +557,12 @@
/// Even in constructors this holds true. Take special care when translating
/// back to dart, where `return null;` in a constructor is an error.
Expression value;
+ SourceInformation sourceInformation;
Statement get next => null;
void set next(Statement s) => throw 'UNREACHABLE';
- Return(this.value);
+ Return(this.value, {this.sourceInformation});
accept(StatementVisitor visitor) => visitor.visitReturn(this);
accept1(StatementVisitor1 visitor, arg) => visitor.visitReturn(this, arg);
@@ -664,8 +681,10 @@
ClassElement classElement;
List<Expression> arguments;
List<Expression> typeInformation;
+ SourceInformation sourceInformation;
- CreateInstance(this.classElement, this.arguments, this.typeInformation);
+ CreateInstance(this.classElement, this.arguments,
+ this.typeInformation, this.sourceInformation);
accept(ExpressionVisitor visitor) => visitor.visitCreateInstance(this);
accept1(ExpressionVisitor1 visitor, arg) {
@@ -717,10 +736,41 @@
accept1(ExpressionVisitor1 visitor, arg) => visitor.visitSetStatic(this, arg);
}
-class ReifyRuntimeType extends Expression {
+class GetLength extends Expression {
+ Expression object;
+
+ GetLength(this.object);
+
+ accept(ExpressionVisitor v) => v.visitGetLength(this);
+ accept1(ExpressionVisitor1 v, arg) => v.visitGetLength(this, arg);
+}
+
+class GetIndex extends Expression {
+ Expression object;
+ Expression index;
+
+ GetIndex(this.object, this.index);
+
+ accept(ExpressionVisitor v) => v.visitGetIndex(this);
+ accept1(ExpressionVisitor1 v, arg) => v.visitGetIndex(this, arg);
+}
+
+class SetIndex extends Expression {
+ Expression object;
+ Expression index;
Expression value;
- ReifyRuntimeType(this.value);
+ SetIndex(this.object, this.index, this.value);
+
+ accept(ExpressionVisitor v) => v.visitSetIndex(this);
+ accept1(ExpressionVisitor1 v, arg) => v.visitSetIndex(this, arg);
+}
+
+class ReifyRuntimeType extends Expression {
+ Expression value;
+ SourceInformation sourceInformation;
+
+ ReifyRuntimeType(this.value, this.sourceInformation);
accept(ExpressionVisitor visitor) {
return visitor.visitReifyRuntimeType(this);
@@ -734,8 +784,9 @@
class ReadTypeVariable extends Expression {
final TypeVariableType variable;
Expression target;
+ final SourceInformation sourceInformation;
- ReadTypeVariable(this.variable, this.target);
+ ReadTypeVariable(this.variable, this.target, this.sourceInformation);
accept(ExpressionVisitor visitor) {
return visitor.visitReadTypeVariable(this);
@@ -873,6 +924,9 @@
E visitInterceptor(Interceptor node);
E visitApplyBuiltinOperator(ApplyBuiltinOperator node);
E visitForeignExpression(ForeignExpression node);
+ E visitGetLength(GetLength node);
+ E visitGetIndex(GetIndex node);
+ E visitSetIndex(SetIndex node);
}
abstract class ExpressionVisitor1<E, A> {
@@ -905,6 +959,9 @@
E visitInterceptor(Interceptor node, A arg);
E visitApplyBuiltinOperator(ApplyBuiltinOperator node, A arg);
E visitForeignExpression(ForeignExpression node, A arg);
+ E visitGetLength(GetLength node, A arg);
+ E visitGetIndex(GetIndex node, A arg);
+ E visitSetIndex(SetIndex node, A arg);
}
abstract class StatementVisitor<S> {
@@ -1117,6 +1174,21 @@
visitForeignExpression(ForeignExpression node) => visitForeignCode(node);
visitForeignStatement(ForeignStatement node) => visitForeignCode(node);
+
+ visitGetLength(GetLength node) {
+ visitExpression(node.object);
+ }
+
+ visitGetIndex(GetIndex node) {
+ visitExpression(node.object);
+ visitExpression(node.index);
+ }
+
+ visitSetIndex(SetIndex node) {
+ visitExpression(node.object);
+ visitExpression(node.index);
+ visitExpression(node.value);
+ }
}
abstract class Transformer implements ExpressionVisitor<Expression>,
@@ -1332,6 +1404,24 @@
node.input = visitExpression(node.input);
return node;
}
+
+ visitGetLength(GetLength node) {
+ node.object = visitExpression(node.object);
+ return node;
+ }
+
+ visitGetIndex(GetIndex node) {
+ node.object = visitExpression(node.object);
+ node.index = visitExpression(node.index);
+ return node;
+ }
+
+ visitSetIndex(SetIndex node) {
+ node.object = visitExpression(node.object);
+ node.index = visitExpression(node.index);
+ node.value = visitExpression(node.value);
+ return node;
+ }
}
class FallthroughTarget {
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
index caffb4a..63d1a05 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
@@ -530,6 +530,27 @@
String args = node.arguments.map(visitExpression).join(', ');
return 'ApplyBuiltinOperator ${node.operator} ($args)';
}
+
+ @override
+ String visitGetLength(GetLength node) {
+ String object = visitExpression(node.object);
+ return 'GetLength($object)';
+ }
+
+ @override
+ String visitGetIndex(GetIndex node) {
+ String object = visitExpression(node.object);
+ String index = visitExpression(node.index);
+ return 'GetIndex($object, $index)';
+ }
+
+ @override
+ String visitSetIndex(SetIndex node) {
+ String object = visitExpression(node.object);
+ String index = visitExpression(node.index);
+ String value = visitExpression(node.value);
+ return 'SetIndex($object, $index, $value)';
+ }
}
/**
diff --git a/pkg/compiler/lib/src/types/flat_type_mask.dart b/pkg/compiler/lib/src/types/flat_type_mask.dart
index 17d0fc5..ce19f17 100644
--- a/pkg/compiler/lib/src/types/flat_type_mask.dart
+++ b/pkg/compiler/lib/src/types/flat_type_mask.dart
@@ -50,11 +50,11 @@
return new FlatTypeMask.internal(base, flags);
}
if ((flags >> 1) == SUBTYPE) {
- if (!world.hasAnySubtype(base) || world.hasOnlySubclasses(base)) {
+ if (!world.hasAnyStrictSubtype(base) || world.hasOnlySubclasses(base)) {
flags = (flags & 0x1) | (SUBCLASS << 1);
}
}
- if (((flags >> 1) == SUBCLASS) && !world.hasAnySubclass(base)) {
+ if (((flags >> 1) == SUBCLASS) && !world.hasAnyStrictSubclass(base)) {
flags = (flags & 0x1) | (EXACT << 1);
}
Map<ClassElement, TypeMask> cachedMasks =
@@ -631,10 +631,10 @@
Iterable<ClassElement> subclassesToCheck;
if (isSubtype) {
- subclassesToCheck = classWorld.subtypesOf(base);
+ subclassesToCheck = classWorld.strictSubtypesOf(base);
} else {
assert(isSubclass);
- subclassesToCheck = classWorld.subclassesOf(base);
+ subclassesToCheck = classWorld.strictSubclassesOf(base);
}
return subclassesToCheck != null &&
@@ -704,10 +704,10 @@
if (x.isExact) {
return null;
} else if (x.isSubclass) {
- return classWorld.subclassesOf(element);
+ return classWorld.strictSubclassesOf(element);
} else {
assert(x.isSubtype);
- return classWorld.subtypesOf(element);
+ return classWorld.strictSubtypesOf(element);
}
}
}
diff --git a/pkg/compiler/lib/src/types/type_mask.dart b/pkg/compiler/lib/src/types/type_mask.dart
index 8e4e2d2..bf095b8 100644
--- a/pkg/compiler/lib/src/types/type_mask.dart
+++ b/pkg/compiler/lib/src/types/type_mask.dart
@@ -33,7 +33,7 @@
}
factory TypeMask.subclass(ClassElement base, ClassWorld classWorld) {
- if (classWorld.hasAnySubclass(base)) {
+ if (classWorld.hasAnyStrictSubclass(base)) {
return new FlatTypeMask.subclass(base);
} else {
return new TypeMask.exactOrEmpty(base, classWorld);
@@ -44,7 +44,7 @@
if (classWorld.hasOnlySubclasses(base)) {
return new TypeMask.subclass(base, classWorld);
}
- if (classWorld.hasAnySubtype(base)) {
+ if (classWorld.hasAnyStrictSubtype(base)) {
return new FlatTypeMask.subtype(base);
} else {
return new TypeMask.exactOrEmpty(base, classWorld);
@@ -69,7 +69,7 @@
}
factory TypeMask.nonNullSubclass(ClassElement base, ClassWorld classWorld) {
- if (classWorld.hasAnySubclass(base)) {
+ if (classWorld.hasAnyStrictSubclass(base)) {
return new FlatTypeMask.nonNullSubclass(base);
} else {
return new TypeMask.nonNullExactOrEmpty(base, classWorld);
@@ -80,7 +80,7 @@
if (classWorld.hasOnlySubclasses(base)) {
return new TypeMask.nonNullSubclass(base, classWorld);
}
- if (classWorld.hasAnySubtype(base)) {
+ if (classWorld.hasAnyStrictSubtype(base)) {
return new FlatTypeMask.nonNullSubtype(base);
} else {
return new TypeMask.nonNullExactOrEmpty(base, classWorld);
@@ -126,13 +126,13 @@
return null;
}
if (mask.isSubclass) {
- if (!classWorld.hasAnySubclass(mask.base)) {
+ if (!classWorld.hasAnyStrictSubclass(mask.base)) {
return 'Subclass ${mask.base} does not have any subclasses.';
}
return null;
}
assert(mask.isSubtype);
- if (!classWorld.hasAnySubtype(mask.base)) {
+ if (!classWorld.hasAnyStrictSubtype(mask.base)) {
return 'Subtype ${mask.base} does not have any subclasses.';
}
if (classWorld.hasOnlySubclasses(mask.base)) {
diff --git a/pkg/compiler/lib/src/types/union_type_mask.dart b/pkg/compiler/lib/src/types/union_type_mask.dart
index f4c45e7..63a421d 100644
--- a/pkg/compiler/lib/src/types/union_type_mask.dart
+++ b/pkg/compiler/lib/src/types/union_type_mask.dart
@@ -103,7 +103,7 @@
int bestSize;
for (ClassElement candidate in candidates) {
Iterable<ClassElement> subclasses = useSubclass
- ? classWorld.subclassesOf(candidate)
+ ? classWorld.strictSubclassesOf(candidate)
: const <ClassElement>[];
int size;
int kind;
@@ -114,10 +114,10 @@
// subtype type mask.
kind = FlatTypeMask.SUBCLASS;
size = subclasses.length;
- assert(size <= classWorld.subtypesOf(candidate).length);
+ assert(size <= classWorld.strictSubtypesOf(candidate).length);
} else {
kind = FlatTypeMask.SUBTYPE;
- size = classWorld.subtypesOf(candidate).length;
+ size = classWorld.strictSubtypesOf(candidate).length;
}
// Update the best candidate if the new one is better.
if (bestElement == null || size < bestSize) {
@@ -212,10 +212,10 @@
// Check for other members.
Iterable<ClassElement> members;
if (flat.isSubclass) {
- members = classWorld.subclassesOf(flat.base);
+ members = classWorld.strictSubclassesOf(flat.base);
} else {
assert(flat.isSubtype);
- members = classWorld.subtypesOf(flat.base);
+ members = classWorld.strictSubtypesOf(flat.base);
}
return members.every((ClassElement cls) => this.contains(cls, classWorld));
}
diff --git a/pkg/compiler/lib/src/universe/function_set.dart b/pkg/compiler/lib/src/universe/function_set.dart
index db99578..7260c6d 100644
--- a/pkg/compiler/lib/src/universe/function_set.dart
+++ b/pkg/compiler/lib/src/universe/function_set.dart
@@ -243,7 +243,7 @@
* Compute the type of all potential receivers of this function set.
*/
TypeMask computeMask(ClassWorld classWorld) {
- assert(classWorld.hasAnySubclass(classWorld.objectClass));
+ assert(classWorld.hasAnyStrictSubclass(classWorld.objectClass));
if (_mask != null) return _mask;
return _mask = new TypeMask.unionOf(functions
.expand((element) {
diff --git a/pkg/compiler/lib/src/use_unused_api.dart b/pkg/compiler/lib/src/use_unused_api.dart
index 3e90be4..ffbcb5e 100644
--- a/pkg/compiler/lib/src/use_unused_api.dart
+++ b/pkg/compiler/lib/src/use_unused_api.dart
@@ -31,6 +31,7 @@
import 'js/js.dart' as js;
import 'js_backend/js_backend.dart' as js_backend;
import 'js_emitter/js_emitter.dart' as js_emitter;
+import 'js_emitter/full_emitter/emitter.dart' as full;
import 'js_emitter/program_builder/program_builder.dart' as program_builder;
import 'resolution/semantic_visitor.dart' as semantic_visitor;
import 'resolution/operators.dart' as operators;
@@ -301,9 +302,9 @@
}
useCodeEmitterTask(js_emitter.CodeEmitterTask codeEmitterTask) {
- codeEmitterTask.oldEmitter.clearCspPrecompiledNodes();
- codeEmitterTask.oldEmitter.
- buildLazilyInitializedStaticField(null, isolateProperties: null);
+ full.Emitter fullEmitter = codeEmitterTask.emitter;
+ fullEmitter.clearCspPrecompiledNodes();
+ fullEmitter.buildLazilyInitializedStaticField(null, isolateProperties: null);
}
useScript(dart2jslib.Script script) {
diff --git a/pkg/compiler/lib/src/warnings.dart b/pkg/compiler/lib/src/warnings.dart
index f144262..350af41 100644
--- a/pkg/compiler/lib/src/warnings.dart
+++ b/pkg/compiler/lib/src/warnings.dart
@@ -401,6 +401,9 @@
static const MessageKind NOT_A_PREFIX = const MessageKind(
"'#{node}' is not a prefix.");
+ static const MessageKind PREFIX_AS_EXPRESSION = const MessageKind(
+ "Library prefix '#{prefix}' is not a valid expression.");
+
static const MessageKind CANNOT_FIND_CONSTRUCTOR = const MessageKind(
"Cannot find constructor '#{constructorName}'.");
@@ -1202,7 +1205,6 @@
"Cannot assign a value to a type. Note that types are never null, "
"so this ??= assignment has no effect.",
howToFix: "Try removing the '??=' assignment.",
- options: const ['--enable-null-aware-operators'],
examples: const [
"class A {} main() { print(A ??= 3);}",
]);
@@ -2022,10 +2024,6 @@
// This is a fall-back message that shouldn't happen.
"Incomplete token.");
- static const MessageKind NULL_AWARE_OPERATORS_DISABLED = const MessageKind(
- "Null-aware operators like '#{operator}' are currently experimental. "
- "You can enable them using the --enable-null-aware-operators flag.");
-
static const MessageKind EXPONENT_MISSING = const MessageKind(
"Numbers in exponential notation should always contain an exponent"
" (an integer number with an optional sign).",
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index 21dc96e..b4d78dd 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -46,31 +46,17 @@
/// instance of [y].
bool isSubtypeOf(ClassElement x, ClassElement y);
- /// Returns an iterable over the live classes that extend [cls] including
- /// [cls] itself.
- Iterable<ClassElement> subclassesOf(ClassElement cls);
-
/// Returns an iterable over the live classes that extend [cls] _not_
/// including [cls] itself.
Iterable<ClassElement> strictSubclassesOf(ClassElement cls);
- /// Returns an iterable over the live classes that implement [cls] including
- /// [cls] 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);
- /// Returns `true` if any live class extends [cls].
- bool hasAnySubclass(ClassElement cls);
-
/// Returns `true` if any live class other than [cls] extends [cls].
bool hasAnyStrictSubclass(ClassElement cls);
- /// Returns `true` if any live class implements [cls].
- bool hasAnySubtype(ClassElement cls);
-
/// Returns `true` if any live class other than [cls] implements [cls].
bool hasAnyStrictSubtype(ClassElement cls);
@@ -159,9 +145,9 @@
return compiler.resolverWorld.isInstantiated(cls);
}
- /// Returns an iterable over the live classes that extend [cls] including
- /// [cls] itself.
- Iterable<ClassElement> subclassesOf(ClassElement cls) {
+ /// Returns an iterable over the live classes that extend [cls] _not_
+ /// including [cls] itself.
+ Iterable<ClassElement> strictSubclassesOf(ClassElement cls) {
Set<ClassElement> subclasses = _subclasses[cls.declaration];
if (subclasses == null) return const <ClassElement>[];
assert(invariant(cls, isInstantiated(cls.declaration),
@@ -169,28 +155,11 @@
return subclasses;
}
- /// Returns an iterable over the live classes that extend [cls] _not_
- /// including [cls] itself.
- Iterable<ClassElement> strictSubclassesOf(ClassElement cls) {
- return subclassesOf(cls).where((c) => c != cls);
- }
-
- /// Returns an iterable over the live classes that implement [cls] including
- /// [cls] if it is live.
- Iterable<ClassElement> subtypesOf(ClassElement cls) {
- Set<ClassElement> subtypes = _subtypes[cls.declaration];
- return subtypes != null ? subtypes : const <ClassElement>[];
- }
-
/// Returns an iterable over the live classes that implement [cls] _not_
/// including [cls] if it is live.
Iterable<ClassElement> strictSubtypesOf(ClassElement cls) {
- return subtypesOf(cls).where((c) => c != cls);
- }
-
- /// Returns `true` if any live class extends [cls].
- bool hasAnySubclass(ClassElement cls) {
- return !subclassesOf(cls).isEmpty;
+ Set<ClassElement> subtypes = _subtypes[cls.declaration];
+ return subtypes != null ? subtypes : const <ClassElement>[];
}
/// Returns `true` if any live class other than [cls] extends [cls].
@@ -198,11 +167,6 @@
return !strictSubclassesOf(cls).isEmpty;
}
- /// Returns `true` if any live class implements [cls].
- bool hasAnySubtype(ClassElement cls) {
- return !subtypesOf(cls).isEmpty;
- }
-
/// Returns `true` if any live class other than [cls] implements [cls].
bool hasAnyStrictSubtype(ClassElement cls) {
return !strictSubtypesOf(cls).isEmpty;
@@ -210,9 +174,9 @@
/// Returns `true` if all live classes that implement [cls] extend it.
bool hasOnlySubclasses(ClassElement cls) {
- Iterable<ClassElement> subtypes = subtypesOf(cls);
+ Iterable<ClassElement> subtypes = strictSubtypesOf(cls);
if (subtypes == null) return true;
- Iterable<ClassElement> subclasses = subclassesOf(cls);
+ Iterable<ClassElement> subclasses = strictSubclassesOf(cls);
return subclasses != null && (subclasses.length == subtypes.length);
}
diff --git a/pkg/dart2js_incremental/lib/caching_compiler.dart b/pkg/dart2js_incremental/lib/caching_compiler.dart
index 0050ab0..aeab05a 100644
--- a/pkg/dart2js_incremental/lib/caching_compiler.dart
+++ b/pkg/dart2js_incremental/lib/caching_compiler.dart
@@ -65,9 +65,11 @@
null);
JavaScriptBackend backend = compiler.backend;
+ full.Emitter emitter = backend.emitter.emitter;
+
// Much like a scout, an incremental compiler is always prepared. For
// mixins, classes, and lazy statics, at least.
- backend.emitter.oldEmitter
+ emitter
..needsClassSupport = true
..needsMixinSupport = true
..needsLazyInitializer = true
@@ -100,19 +102,20 @@
..enqueuer.codegen.hasEnqueuedReflectiveStaticFields = false
..compilationFailed = false;
JavaScriptBackend backend = compiler.backend;
+ full.Emitter emitter = backend.emitter.emitter;
// TODO(ahe): Seems this cache only serves to tell
- // [OldEmitter.invalidateCaches] if it was invoked on a full compile (in
+ // [emitter.invalidateCaches] if it was invoked on a full compile (in
// which case nothing should be invalidated), or if it is an incremental
// compilation (in which case, holders/owners of newly compiled methods
// must be invalidated).
- backend.emitter.oldEmitter.cachedElements.add(null);
+ emitter.cachedElements.add(null);
compiler.enqueuer.codegen
..newlyEnqueuedElements.clear()
..newlySeenSelectors.clear();
- backend.emitter.oldEmitter.nsmEmitter
+ emitter.nsmEmitter
..trivialNsmHandlers.clear();
backend.emitter.typeTestRegistry
@@ -121,7 +124,7 @@
..rtiNeededClasses.clear()
..cachedClassesUsingTypeVariableTests = null;
- backend.emitter.oldEmitter.interceptorEmitter
+ emitter.interceptorEmitter
..interceptorInvocationNames.clear();
backend.emitter.nativeEmitter
@@ -130,7 +133,7 @@
backend.emitter.readTypeVariables.clear();
- backend.emitter.oldEmitter
+ emitter
..outputBuffers.clear()
..classesCollector = null
..mangledFieldNames.clear()
@@ -139,16 +142,6 @@
..clearCspPrecompiledNodes()
..elementDescriptors.clear();
- backend.emitter
- ..nativeClassesAndSubclasses.clear()
- ..outputContainsConstantList = false
- ..neededClasses.clear()
- ..outputClassLists.clear()
- ..outputConstantLists.clear()
- ..outputStaticLists.clear()
- ..outputStaticNonFinalFieldLists.clear()
- ..outputLibraryLists.clear();
-
backend
..preMirrorsMethodCount = 0;
diff --git a/pkg/dart2js_incremental/lib/dart2js_incremental.dart b/pkg/dart2js_incremental/lib/dart2js_incremental.dart
index 2adb61f..ee04336 100644
--- a/pkg/dart2js_incremental/lib/dart2js_incremental.dart
+++ b/pkg/dart2js_incremental/lib/dart2js_incremental.dart
@@ -26,6 +26,9 @@
import 'package:compiler/src/js_backend/js_backend.dart' show
JavaScriptBackend;
+import 'package:compiler/src/js_emitter/full_emitter/emitter.dart'
+ as full show Emitter;
+
import 'package:compiler/src/elements/elements.dart' show
LibraryElement;
diff --git a/pkg/dart2js_incremental/lib/library_updater.dart b/pkg/dart2js_incremental/lib/library_updater.dart
index f111d4a..bd2188b 100644
--- a/pkg/dart2js_incremental/lib/library_updater.dart
+++ b/pkg/dart2js_incremental/lib/library_updater.dart
@@ -66,6 +66,9 @@
MemberInfo,
computeMixinClass;
+import 'package:compiler/src/js_emitter/full_emitter/emitter.dart'
+ as full show Emitter;
+
import 'package:compiler/src/js_emitter/model.dart' show
Class,
Method;
@@ -155,14 +158,18 @@
void _captureState(Compiler compiler) {
JavaScriptBackend backend = compiler.backend;
- _emittedClasses = new Set.from(backend.emitter.neededClasses);
+ Set neededClasses = backend.emitter.neededClasses;
+ if (neededClasses == null) {
+ neededClasses = new Set();
+ }
+ _emittedClasses = new Set.from(neededClasses);
_directlyInstantiatedClasses =
new Set.from(compiler.codegenWorld.directlyInstantiatedClasses);
- List<ConstantValue> constants =
- backend.emitter.outputConstantLists[
- compiler.deferredLoadTask.mainOutputUnit];
+ // This breaks constant tracking of the incremental compiler. It would need
+ // to capture the emitted constants.
+ List<ConstantValue> constants = null;
if (constants == null) constants = <ConstantValue>[];
_compiledConstants = new Set<ConstantValue>.identity()..addAll(constants);
}
@@ -897,9 +904,9 @@
if (constants != null) {
for (ConstantValue constant in constants) {
if (!_compiledConstants.contains(constant)) {
+ full.Emitter fullEmitter = emitter.emitter;
jsAst.Statement constantInitializer =
- emitter.oldEmitter.buildConstantInitializer(constant)
- .toStatement();
+ fullEmitter.buildConstantInitializer(constant).toStatement();
updates.add(constantInitializer);
}
}
@@ -976,9 +983,10 @@
}
// A static (or top-level) field.
if (backend.constants.lazyStatics.contains(element)) {
+ full.Emitter fullEmitter = emitter.emitter;
jsAst.Expression init =
- emitter.oldEmitter.buildLazilyInitializedStaticField(
- element, isolateProperties: namer.currentIsolate);
+ fullEmitter.buildLazilyInitializedStaticField(
+ element, isolateProperties: namer.staticStateHolder);
if (init == null) {
throw new StateError("Initializer optimized away for $element");
}
@@ -1470,7 +1478,10 @@
CodeEmitterTask get emitter => backend.emitter;
- ContainerBuilder get containerBuilder => emitter.oldEmitter.containerBuilder;
+ ContainerBuilder get containerBuilder {
+ full.Emitter fullEmitter = emitter.emitter;
+ return fullEmitter.containerBuilder;
+ }
EnqueueTask get enqueuer => compiler.enqueuer;
}
@@ -1480,7 +1491,10 @@
EmitterHelper(this.compiler);
- ClassEmitter get classEmitter => backend.emitter.oldEmitter.classEmitter;
+ ClassEmitter get classEmitter {
+ full.Emitter fullEmitter = emitter.emitter;
+ return fullEmitter.classEmitter;
+ }
List<String> computeFields(ClassElement classElement) {
Class cls = new ProgramBuilder(compiler, namer, emitter)
diff --git a/pkg/pkg.status b/pkg/pkg.status
index f105670..bc0d302 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -89,6 +89,7 @@
analyzer/test/generated/utilities_test: Pass, Slow # Issue 21628
analyzer/test/generated/parser_test: Pass, Slow # Issue 21628
analyzer/test/src/task/dart_test: Pass, Slow # Issue 21628
+analyzer/test/src/task/driver_test: Pass, Slow # Issue 21628
[ $runtime == jsshell ]
async/test/stream_zip_test: RuntimeError, OK # Timers are not supported.
@@ -161,7 +162,7 @@
analyzer/test/generated/element_test: Crash # The null object does not have a getter '_element'.
analyzer/test/generated/incremental_resolver_test: Crash # The null object does not have a getter '_element'.
analyzer/test/generated/incremental_scanner_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/generated/java_core_test: RuntimeError # receiver.get$_nums is not a function
+analyzer/test/generated/java_core_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
analyzer/test/generated/non_error_resolver_test: Crash # The null object does not have a getter '_element'.
analyzer/test/generated/parser_test: Crash # The null object does not have a getter '_element'.
analyzer/test/generated/resolver_test: Crash # The null object does not have a getter '_element'.
@@ -189,7 +190,7 @@
analyzer/test/src/task/model_test: Crash # The null object does not have a getter '_element'.
analyzer/test/src/util/asserts_test: Crash # The null object does not have a getter '_element'.
analyzer/test/src/util/lru_map_test: Crash # The null object does not have a getter '_element'.
-fixnum/test/int_32_test: RuntimeError # receiver.get$_nums is not a function
-fixnum/test/int_64_test: RuntimeError # receiver.get$_nums is not a function
-typed_data/test/typed_buffers_test/none: RuntimeError # receiver.get$_nums is not a function
-typed_mock/test/typed_mock_test: RuntimeError # receiver.get$_nums is not a function
+fixnum/test/int_32_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+fixnum/test/int_64_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+typed_data/test/typed_buffers_test/none: RuntimeError # receiver._addHashTableEntry$2 is not a function
+typed_mock/test/typed_mock_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc
index 8ba4a30..54cd64d 100644
--- a/runtime/bin/file_win.cc
+++ b/runtime/bin/file_win.cc
@@ -196,6 +196,7 @@
default:
UNREACHABLE();
}
+ _setmode(fd, _O_BINARY);
return new File(new FileHandle(fd));
}
diff --git a/runtime/bin/thread.h b/runtime/bin/thread.h
index eb99e10..60dc75f2 100644
--- a/runtime/bin/thread.h
+++ b/runtime/bin/thread.h
@@ -7,6 +7,14 @@
#include "platform/globals.h"
+namespace dart {
+namespace bin {
+class Thread;
+class Mutex;
+class Monitor;
+}
+}
+
// Declare the OS-specific types ahead of defining the generic classes.
#if defined(TARGET_OS_ANDROID)
#include "bin/thread_android.h"
diff --git a/runtime/bin/vmservice/loader.dart b/runtime/bin/vmservice/loader.dart
index ce3c9cc..a95df08 100644
--- a/runtime/bin/vmservice/loader.dart
+++ b/runtime/bin/vmservice/loader.dart
@@ -101,6 +101,6 @@
} else if ((uri.scheme == 'data')) {
_loadDataUri(sp, id, uri);
} else {
- sp.send('Unknown scheme (${uri.scheme}) for $uri');
+ sp.send([id, 'Unknown scheme (${uri.scheme}) for $uri']);
}
}
diff --git a/runtime/lib/errors_patch.dart b/runtime/lib/errors_patch.dart
index 01920ed..59a61ec 100644
--- a/runtime/lib/errors_patch.dart
+++ b/runtime/lib/errors_patch.dart
@@ -57,6 +57,18 @@
String error_msg)
native "TypeError_throwNew";
+ static _throwNewIfNotLoaded(_LibraryPrefix prefix,
+ int location,
+ Object src_value,
+ String dst_type_name,
+ String dst_name,
+ String error_msg) {
+ if (!prefix.isLoaded()) {
+ _throwNew(location, src_value, dst_type_name, dst_name, error_msg);
+ }
+ }
+
+
String toString() {
String str = (_errorMsg != null) ? _errorMsg : "";
if ((_dstName != null) && (_dstName.length > 0)) {
@@ -181,6 +193,19 @@
existingArgumentNames);
}
+ static void _throwNewIfNotLoaded(_LibraryPrefix prefix,
+ Object receiver,
+ String memberName,
+ int invocation_type,
+ List arguments,
+ List argumentNames,
+ List existingArgumentNames) {
+ if (!prefix.isLoaded()) {
+ _throwNew(receiver, memberName, invocation_type, arguments,
+ argumentNames, existingArgumentNames);
+ }
+ }
+
// Remember the type from the invocation mirror or static compilation
// analysis when thrown directly with _throwNew. A negative value means
// that no information is available.
diff --git a/runtime/lib/lib_prefix.dart b/runtime/lib/lib_prefix.dart
index f74dcb1..fb9fe81 100644
--- a/runtime/lib/lib_prefix.dart
+++ b/runtime/lib/lib_prefix.dart
@@ -10,6 +10,7 @@
bool _load() native "LibraryPrefix_load";
Error _loadError() native "LibraryPrefix_loadError";
+ bool isLoaded() native "LibraryPrefix_isLoaded";
bool _invalidateDependentCode()
native "LibraryPrefix_invalidateDependentCode";
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 2c43d96..d8693a1 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -378,6 +378,13 @@
}
+DEFINE_NATIVE_ENTRY(LibraryPrefix_isLoaded, 1) {
+ const LibraryPrefix& prefix =
+ LibraryPrefix::CheckedHandle(arguments->NativeArgAt(0));
+ return Bool::Get(prefix.is_loaded()).raw();
+}
+
+
DEFINE_NATIVE_ENTRY(Internal_inquireIs64Bit, 0) {
#if defined(ARCH_IS_64_BIT)
return Bool::True().raw();
diff --git a/runtime/observatory/lib/service_common.dart b/runtime/observatory/lib/service_common.dart
index 790efe1..0580f5c 100644
--- a/runtime/observatory/lib/service_common.dart
+++ b/runtime/observatory/lib/service_common.dart
@@ -208,7 +208,8 @@
return;
}
var event = map['event'];
- postServiceEvent(event, data);
+ var streamId = map['streamId'];
+ postServiceEvent(streamId, event, data);
});
}
@@ -219,7 +220,8 @@
}
var event = map['event'];
if (event != null) {
- postServiceEvent(event, null);
+ var streamId = map['streamId'];
+ postServiceEvent(streamId, event, null);
return;
}
diff --git a/runtime/observatory/lib/src/app/application.dart b/runtime/observatory/lib/src/app/application.dart
index ef565f5..3dc046d 100644
--- a/runtime/observatory/lib/src/app/application.dart
+++ b/runtime/observatory/lib/src/app/application.dart
@@ -23,6 +23,7 @@
@observable Page currentPage;
VM _vm;
VM get vm => _vm;
+
set vm(VM vm) {
if (_vm == vm) {
// Do nothing.
@@ -53,7 +54,8 @@
new ServiceEvent.connectionClosed(reason)));
});
- vm.events.stream.listen(_onEvent);
+ vm.listenEventStream(VM.kIsolateStream, _onEvent);
+ vm.listenEventStream(VM.kDebugStream, _onEvent);
}
_vm = vm;
}
@@ -88,11 +90,9 @@
switch(event.kind) {
case ServiceEvent.kIsolateStart:
case ServiceEvent.kIsolateUpdate:
- case ServiceEvent.kGraph:
case ServiceEvent.kBreakpointAdded:
case ServiceEvent.kBreakpointResolved:
case ServiceEvent.kBreakpointRemoved:
- case ServiceEvent.kGC:
case ServiceEvent.kDebuggerSettingsUpdate:
// Ignore for now.
break;
diff --git a/runtime/observatory/lib/src/app/page.dart b/runtime/observatory/lib/src/app/page.dart
index d678926..3a96752 100644
--- a/runtime/observatory/lib/src/app/page.dart
+++ b/runtime/observatory/lib/src/app/page.dart
@@ -191,7 +191,6 @@
if (element != null) {
/// Update the page.
DebuggerPageElement page = element;
- page.app = app;
page.isolate = isolate;
}
});
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index 2fc89da..31f064a 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'dart:html';
import 'observatory_element.dart';
-import 'package:observatory/app.dart';
import 'package:observatory/cli.dart';
import 'package:observatory/debugger.dart';
import 'package:observatory/service.dart';
@@ -921,9 +920,6 @@
}
}
Future.wait(pending).then((_) {
- if (_subscription == null) {
- _subscription = vm.events.stream.listen(_onEvent);
- }
_refreshStack(isolate.pauseEvent).then((_) {
reportStatus();
});
@@ -948,7 +944,6 @@
}
Isolate get isolate => _isolate;
Isolate _isolate;
- var _subscription;
void init() {
console.newline();
@@ -1080,7 +1075,7 @@
});
}
- void _onEvent(ServiceEvent event) {
+ void onEvent(ServiceEvent event) {
switch(event.kind) {
case ServiceEvent.kIsolateStart:
{
@@ -1226,7 +1221,6 @@
@CustomTag('debugger-page')
class DebuggerPageElement extends ObservatoryElement {
- @published ObservatoryApplication app;
@published Isolate isolate;
isolateChanged(oldValue) {
@@ -1240,6 +1234,9 @@
debugger.page = this;
}
+ Future<StreamSubscription> _isolateSubscriptionFuture;
+ Future<StreamSubscription> _debugSubscriptionFuture;
+
@override
void attached() {
super.attached();
@@ -1267,6 +1264,20 @@
debugger.input = $['commandline'];
debugger.input.debugger = debugger;
debugger.init();
+
+ _isolateSubscriptionFuture =
+ app.vm.listenEventStream(VM.kIsolateStream, debugger.onEvent);
+ _debugSubscriptionFuture =
+ app.vm.listenEventStream(VM.kDebugStream, debugger.onEvent);
+ }
+
+ @override
+ void detached() {
+ cancelFutureSubscription(_isolateSubscriptionFuture);
+ _isolateSubscriptionFuture = null;
+ cancelFutureSubscription(_debugSubscriptionFuture);
+ _debugSubscriptionFuture = null;
+ super.detached();
}
}
diff --git a/runtime/observatory/lib/src/elements/heap_profile.dart b/runtime/observatory/lib/src/elements/heap_profile.dart
index 243be472..c5dbc76 100644
--- a/runtime/observatory/lib/src/elements/heap_profile.dart
+++ b/runtime/observatory/lib/src/elements/heap_profile.dart
@@ -43,7 +43,7 @@
var _classTableBody;
@published bool autoRefresh = false;
- var _subscription;
+ var _subscriptionFuture;
@published Isolate isolate;
@observable ServiceMap profile;
@@ -93,13 +93,14 @@
_oldPieChart = new Chart('PieChart',
shadowRoot.querySelector('#oldPieChart'));
_classTableBody = shadowRoot.querySelector('#classTableBody');
- _subscription = app.vm.events.stream.where(
- (event) => event.isolate == isolate).listen(_onEvent);
+ _subscriptionFuture =
+ app.vm.listenEventStream(VM.kGCStream, _onEvent);
}
@override
void detached() {
- _subscription.cancel();
+ cancelFutureSubscription(_subscriptionFuture);
+ _subscriptionFuture = null;
super.detached();
}
@@ -108,7 +109,8 @@
bool refreshAutoQueued = false;
void _onEvent(ServiceEvent event) {
- if (autoRefresh && event.kind == 'GC') {
+ assert(event.kind == 'GC');
+ if (autoRefresh) {
if (!refreshAutoPending) {
refreshAuto();
} else {
diff --git a/runtime/observatory/lib/src/elements/ports.dart b/runtime/observatory/lib/src/elements/ports.dart
index dbe230e..8f9cb39 100644
--- a/runtime/observatory/lib/src/elements/ports.dart
+++ b/runtime/observatory/lib/src/elements/ports.dart
@@ -5,9 +5,7 @@
library ports;
import 'dart:async';
-import 'dart:html';
import 'observatory_element.dart';
-import 'package:observatory/app.dart';
import 'package:observatory/service.dart';
import 'package:polymer/polymer.dart';
@@ -16,7 +14,7 @@
PortsPageElement.created() : super.created();
@observable Isolate isolate;
- @observable /*ObservableList | ServiceObject*/ ports;
+ @observable var /*ObservableList | ServiceObject*/ ports;
void isolateChanged(oldValue) {
if (isolate != null) {
diff --git a/runtime/observatory/lib/src/elements/service_view.dart b/runtime/observatory/lib/src/elements/service_view.dart
index f0c2062..19554d6 100644
--- a/runtime/observatory/lib/src/elements/service_view.dart
+++ b/runtime/observatory/lib/src/elements/service_view.dart
@@ -97,6 +97,7 @@
element.object = object;
return element;
}
+ break;
case 'SocketList':
IOSocketListViewElement element =
new Element.tag('io-socket-list-view');
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index f3ebd19..0eee58f 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -4,6 +4,17 @@
part of service;
+/// Helper function for canceling a Future<StreamSubscription>.
+Future cancelFutureSubscription(
+ Future<StreamSubscription> subscriptionFuture) async {
+ if (subscriptionFuture != null) {
+ var subscription = await subscriptionFuture;
+ return subscription.cancel();
+ } else {
+ return null;
+ }
+}
+
/// An RpcException represents an exceptional event that happened
/// while invoking an rpc.
abstract class RpcException implements Exception {
@@ -426,6 +437,62 @@
}
}
+class _EventStreamState {
+ VM _vm;
+ String streamId;
+
+ Function _onDone;
+
+ // A list of all subscribed controllers for this stream.
+ List _controllers = [];
+
+ // Completes when the listen rpc is finished.
+ Future _listenFuture;
+
+ // Completes when then cancel rpc is finished.
+ Future _cancelFuture;
+
+ _EventStreamState(this._vm, this.streamId, this._onDone);
+
+ Future _cancelController(StreamController controller) {
+ _controllers.remove(controller);
+ if (_controllers.isEmpty) {
+ assert(_listenFuture != null);
+ _listenFuture = null;
+ _cancelFuture = _vm._streamCancel(streamId);
+ _cancelFuture.then((_) {
+ if (_controllers.isEmpty) {
+ // No new listeners showed up during cancelation.
+ _onDone();
+ }
+ });
+ }
+ // No need to wait for _cancelFuture here.
+ return new Future.value(null);
+ }
+
+ Future<Stream> addStream() async {
+ var controller;
+ controller = new StreamController(
+ onCancel:() => _cancelController(controller));
+ _controllers.add(controller);
+ if (_cancelFuture != null) {
+ await _cancelFuture;
+ }
+ if (_listenFuture == null) {
+ _listenFuture = _vm._streamListen(streamId);
+ }
+ await _listenFuture;
+ return controller.stream;
+ }
+
+ void addEvent(ServiceEvent event) {
+ for (var controller in _controllers) {
+ controller.add(event);
+ }
+ }
+}
+
/// State for a VM being inspected.
abstract class VM extends ServiceObjectOwner {
@reflectable VM get vm => this;
@@ -459,10 +526,7 @@
update(toObservable({'id':'vm', 'type':'@VM'}));
}
- final StreamController<ServiceEvent> events =
- new StreamController.broadcast();
-
- void postServiceEvent(Map response, ByteData data) {
+ void postServiceEvent(String streamId, Map response, ByteData data) {
var map = toObservable(response);
assert(!map.containsKey('_data'));
if (data != null) {
@@ -475,18 +539,22 @@
}
var eventIsolate = map['isolate'];
+ var event;
if (eventIsolate == null) {
- var event = new ServiceObject._fromMap(vm, map);
- events.add(event);
+ event = new ServiceObject._fromMap(vm, map);
} else {
// getFromMap creates the Isolate if it hasn't been seen already.
var isolate = getFromMap(map['isolate']);
- var event = new ServiceObject._fromMap(isolate, map);
+ event = new ServiceObject._fromMap(isolate, map);
if (event.kind == ServiceEvent.kIsolateExit) {
_removeIsolate(isolate.id);
}
- isolate._onEvent(event);
- events.add(event);
+ }
+ var eventStream = _eventStreams[streamId];
+ if (eventStream != null) {
+ eventStream.addEvent(event);
+ } else {
+ Logger.root.warning("Ignoring unexpected event on stream '${streamId}'");
}
}
@@ -586,16 +654,20 @@
});
}
+ void _dispatchEventToIsolate(ServiceEvent event) {
+ var isolate = event.isolate;
+ if (isolate != null) {
+ isolate._onEvent(event);
+ }
+ }
+
Future<ObservableMap> _fetchDirect() async {
if (!loaded) {
- // TODO(turnidge): Instead of always listening to all streams,
- // implement a stream abstraction in the service library so
- // that we only subscribe to the streams we want.
- await _streamListen('Isolate');
- await _streamListen('Debug');
- await _streamListen('GC');
- await _streamListen('_Echo');
- await _streamListen('_Graph');
+ // The vm service relies on these events to keep the VM and
+ // Isolate types up to date.
+ await listenEventStream(kIsolateStream, _dispatchEventToIsolate);
+ await listenEventStream(kDebugStream, _dispatchEventToIsolate);
+ await listenEventStream(_kGraphStream, _dispatchEventToIsolate);
}
return await invokeRpcNoUpgrade('getVM', {});
}
@@ -611,6 +683,37 @@
return invokeRpc('streamListen', params);
}
+ Future<ServiceObject> _streamCancel(String streamId) {
+ Map params = {
+ 'streamId': streamId,
+ };
+ return invokeRpc('streamCancel', params);
+ }
+
+ // A map from stream id to event stream state.
+ Map<String,_EventStreamState> _eventStreams = {};
+
+ // Well-known stream ids.
+ static const kIsolateStream = 'Isolate';
+ static const kDebugStream = 'Debug';
+ static const kGCStream = 'GC';
+ static const _kGraphStream = '_Graph';
+
+ /// Returns a single-subscription Stream object for a VM event stream.
+ Future<Stream> getEventStream(String streamId) async {
+ var eventStream = _eventStreams.putIfAbsent(
+ streamId, () => new _EventStreamState(
+ this, streamId, () => _eventStreams.remove(streamId)));
+ return eventStream.addStream();
+ }
+
+ /// Helper function for listening to an event stream.
+ Future<StreamSubscription> listenEventStream(String streamId,
+ Function function) async {
+ var stream = await getEventStream(streamId);
+ return stream.listen(function);
+ }
+
/// Force the VM to disconnect.
void disconnect();
/// Completes when the VM first connects.
diff --git a/runtime/observatory/tests/service/allocations_test.dart b/runtime/observatory/tests/service/allocations_test.dart
index 0882edc..4708811 100644
--- a/runtime/observatory/tests/service/allocations_test.dart
+++ b/runtime/observatory/tests/service/allocations_test.dart
@@ -1,7 +1,7 @@
// 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.
-// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
library allocations_test;
diff --git a/runtime/observatory/tests/service/async_generator_breakpoint_test.dart b/runtime/observatory/tests/service/async_generator_breakpoint_test.dart
index c8a33e3..474b54b 100644
--- a/runtime/observatory/tests/service/async_generator_breakpoint_test.dart
+++ b/runtime/observatory/tests/service/async_generator_breakpoint_test.dart
@@ -1,7 +1,7 @@
// 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 --verbose-debug
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override --verbose-debug
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
@@ -69,7 +69,8 @@
expect(result.valueAsString, equals('true'));
});
- await for (ServiceEvent event in isolate.vm.events.stream) {
+ var stream = await isolate.vm.getEventStream(VM.kDebugStream);
+ await for (ServiceEvent event in stream) {
if (event.kind == ServiceEvent.kPauseBreakpoint) {
var bp = event.breakpoint;
print('Hit $bp');
diff --git a/runtime/observatory/tests/service/bad_web_socket_address_test.dart b/runtime/observatory/tests/service/bad_web_socket_address_test.dart
index d328312..946a596 100644
--- a/runtime/observatory/tests/service/bad_web_socket_address_test.dart
+++ b/runtime/observatory/tests/service/bad_web_socket_address_test.dart
@@ -1,7 +1,7 @@
// 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.
-// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:logging/logging.dart';
import "package:observatory/service_io.dart";
diff --git a/runtime/observatory/tests/service/break_on_activation_test.dart b/runtime/observatory/tests/service/break_on_activation_test.dart
index b266954..7de3d76 100644
--- a/runtime/observatory/tests/service/break_on_activation_test.dart
+++ b/runtime/observatory/tests/service/break_on_activation_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
@@ -54,14 +54,14 @@
var breaksHit = 0;
- var subscription;
- subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
- if (event.kind == ServiceEvent.kPauseBreakpoint) {
- print("Hit breakpoint ${event.breakpoint}");
- breaksHit++;
- isolate.resume();
- }
- });
+ var subscriptionFuture = isolate.vm.listenEventStream(
+ VM.kDebugStream, (ServiceEvent event) {
+ if (event.kind == ServiceEvent.kPauseBreakpoint) {
+ print("Hit breakpoint ${event.breakpoint}");
+ breaksHit++;
+ isolate.resume();
+ }
+ });
valueOfField(String name) async {
var field = rootLib.variables.singleWhere((v) => v.name == name);
@@ -91,7 +91,7 @@
expect(res is Instance, isTrue); // Not error.
expect(breaksHit, equals(1));
- await subscription.cancel();
+ await cancelFutureSubscription(subscriptionFuture);
},
(Isolate isolate) async {
@@ -99,14 +99,14 @@
var breaksHit = 0;
- var subscription;
- subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
- if (event.kind == ServiceEvent.kPauseBreakpoint) {
- print("Hit breakpoint ${event.breakpoint}");
- breaksHit++;
- isolate.resume();
- }
- });
+ var subscriptionFuture = isolate.vm.listenEventStream(
+ VM.kDebugStream, (ServiceEvent event) {
+ if (event.kind == ServiceEvent.kPauseBreakpoint) {
+ print("Hit breakpoint ${event.breakpoint}");
+ breaksHit++;
+ isolate.resume();
+ }
+ });
valueOfField(String name) async {
var field = rootLib.variables.singleWhere((v) => v.name == name);
@@ -135,7 +135,7 @@
expect(res is Instance, isTrue); // Not error.
expect(breaksHit, equals(1));
- await subscription.cancel();
+ await cancelFutureSubscription(subscriptionFuture);
},
(Isolate isolate) async {
@@ -143,14 +143,14 @@
var breaksHit = 0;
- var subscription;
- subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
- if (event.kind == ServiceEvent.kPauseBreakpoint) {
- print("Hit breakpoint ${event.breakpoint}");
- breaksHit++;
- isolate.resume();
- }
- });
+ var subscriptionFuture = isolate.vm.listenEventStream(
+ VM.kDebugStream, (ServiceEvent event) {
+ if (event.kind == ServiceEvent.kPauseBreakpoint) {
+ print("Hit breakpoint ${event.breakpoint}");
+ breaksHit++;
+ isolate.resume();
+ }
+ });
valueOfField(String name) async {
var field = rootLib.variables.singleWhere((v) => v.name == name);
@@ -200,7 +200,7 @@
expect(res is Instance, isTrue); // Not error.
expect(breaksHit, equals(4));
- await subscription.cancel();
+ await cancelFutureSubscription(subscriptionFuture);
},
];
diff --git a/runtime/observatory/tests/service/caching_test.dart b/runtime/observatory/tests/service/caching_test.dart
index aafc7ef..196bab4 100644
--- a/runtime/observatory/tests/service/caching_test.dart
+++ b/runtime/observatory/tests/service/caching_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
// If caching is working properly, the coverage data will go into the same
// Script object from which we requested coverage data, instead of a new
diff --git a/runtime/observatory/tests/service/code_test.dart b/runtime/observatory/tests/service/code_test.dart
index 28e2f86..bffbb79 100644
--- a/runtime/observatory/tests/service/code_test.dart
+++ b/runtime/observatory/tests/service/code_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
@@ -34,11 +34,15 @@
return isolate.rootLibrary.load().then((_) {
// Set up a listener to wait for breakpoint events.
Completer completer = new Completer();
- isolate.vm.events.stream.listen((ServiceEvent event) {
- if (event.kind == ServiceEvent.kPauseBreakpoint) {
- print('Breakpoint reached');
- completer.complete();
- }
+ isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
+ var subscription;
+ subscription = stream.listen((ServiceEvent event) {
+ if (event.kind == ServiceEvent.kPauseBreakpoint) {
+ print('Breakpoint reached');
+ subscription.cancel();
+ completer.complete();
+ }
+ });
});
// Add the breakpoint.
diff --git a/runtime/observatory/tests/service/command_test.dart b/runtime/observatory/tests/service/command_test.dart
index 8e57723..9403662 100644
--- a/runtime/observatory/tests/service/command_test.dart
+++ b/runtime/observatory/tests/service/command_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'dart:async';
diff --git a/runtime/observatory/tests/service/contexts_test.dart b/runtime/observatory/tests/service/contexts_test.dart
index bf593f4..2a34ba0 100644
--- a/runtime/observatory/tests/service/contexts_test.dart
+++ b/runtime/observatory/tests/service/contexts_test.dart
@@ -1,7 +1,7 @@
// 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.
-// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
library inbound_references_test;
diff --git a/runtime/observatory/tests/service/coverage_test.dart b/runtime/observatory/tests/service/coverage_test.dart
index 45a60a8..9ae233f 100644
--- a/runtime/observatory/tests/service/coverage_test.dart
+++ b/runtime/observatory/tests/service/coverage_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
@@ -57,11 +57,15 @@
return isolate.rootLibrary.load().then((_) {
// Set up a listener to wait for breakpoint events.
Completer completer = new Completer();
- isolate.vm.events.stream.listen((ServiceEvent event) {
- if (event.kind == ServiceEvent.kPauseBreakpoint) {
- print('Breakpoint reached');
- completer.complete();
- }
+ isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
+ var subscription;
+ subscription = stream.listen((ServiceEvent event) {
+ if (event.kind == ServiceEvent.kPauseBreakpoint) {
+ print('Breakpoint reached');
+ completer.complete();
+ subscription.cancel();
+ }
+ });
});
// Create a timer to set a breakpoint with a short delay.
diff --git a/runtime/observatory/tests/service/debugger_inspect_test.dart b/runtime/observatory/tests/service/debugger_inspect_test.dart
index e6b8e9e..3037abe 100644
--- a/runtime/observatory/tests/service/debugger_inspect_test.dart
+++ b/runtime/observatory/tests/service/debugger_inspect_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
@@ -22,12 +22,11 @@
(Isolate isolate) async {
Completer completer = new Completer();
+ var stream = await isolate.vm.getEventStream(VM.kDebugStream);
var subscription;
- subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
- print(event);
+ subscription = stream.listen((ServiceEvent event) {
if (event.kind == ServiceEvent.kInspect) {
expect((event.inspectee as Instance).clazz.name, equals('Point'));
-
subscription.cancel();
completer.complete();
}
diff --git a/runtime/observatory/tests/service/debugger_location_test.dart b/runtime/observatory/tests/service/debugger_location_test.dart
index 7c4de5b..0672907 100644
--- a/runtime/observatory/tests/service/debugger_location_test.dart
+++ b/runtime/observatory/tests/service/debugger_location_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:observatory/debugger.dart';
@@ -56,10 +56,14 @@
return isolate.rootLibrary.load().then((_) {
// Listen for breakpoint event.
Completer completer = new Completer();
- isolate.vm.events.stream.listen((ServiceEvent event) {
- if (event.kind == ServiceEvent.kPauseBreakpoint) {
- completer.complete();
- }
+ isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
+ var subscription;
+ subscription = stream.listen((ServiceEvent event) {
+ if (event.kind == ServiceEvent.kPauseBreakpoint) {
+ subscription.cancel();
+ completer.complete();
+ }
+ });
});
// Add the breakpoint.
diff --git a/runtime/observatory/tests/service/debugging_inlined_finally_test.dart b/runtime/observatory/tests/service/debugging_inlined_finally_test.dart
index 85d910b..886b368 100644
--- a/runtime/observatory/tests/service/debugging_inlined_finally_test.dart
+++ b/runtime/observatory/tests/service/debugging_inlined_finally_test.dart
@@ -1,12 +1,11 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
import 'test_helper.dart';
-import 'dart:async';
import 'dart:developer';
testFunction() {
@@ -17,13 +16,13 @@
try {
for (int i = 0; i < 10; i++) {
var x = () => i + a + b;
- return x; // line 20
+ return x; // line 19
}
} finally {
- b = 10; // line 23
+ b = 10; // line 22
}
} finally {
- a = 1; // line 26
+ a = 1; // line 25
}
}
@@ -45,32 +44,32 @@
// Add 3 breakpoints.
{
- var result = await isolate.addBreakpoint(script, 20);
+ var result = await isolate.addBreakpoint(script, 19);
expect(result is Breakpoint, isTrue);
Breakpoint bpt = result;
expect(bpt.type, equals('Breakpoint'));
expect(bpt.location.script.id, equals(script.id));
- expect(bpt.location.script.tokenToLine(bpt.location.tokenPos), equals(20));
+ expect(bpt.location.script.tokenToLine(bpt.location.tokenPos), equals(19));
expect(isolate.breakpoints.length, equals(1));
}
{
- var result = await isolate.addBreakpoint(script, 23);
+ var result = await isolate.addBreakpoint(script, 22);
expect(result is Breakpoint, isTrue);
Breakpoint bpt = result;
expect(bpt.type, equals('Breakpoint'));
expect(bpt.location.script.id, equals(script.id));
- expect(bpt.location.script.tokenToLine(bpt.location.tokenPos), equals(23));
+ expect(bpt.location.script.tokenToLine(bpt.location.tokenPos), equals(22));
expect(isolate.breakpoints.length, equals(2));
}
{
- var result = await isolate.addBreakpoint(script, 26);
+ var result = await isolate.addBreakpoint(script, 25);
expect(result is Breakpoint, isTrue);
Breakpoint bpt = result;
expect(bpt.type, equals('Breakpoint'));
expect(bpt.location.script.id, equals(script.id));
- expect(bpt.location.script.tokenToLine(bpt.location.tokenPos), equals(26));
+ expect(bpt.location.script.tokenToLine(bpt.location.tokenPos), equals(25));
expect(isolate.breakpoints.length, equals(3));
}
@@ -81,42 +80,42 @@
hasStoppedAtBreakpoint,
-// We are at the breakpoint on line 20.
+// We are at the breakpoint on line 19.
(Isolate isolate) async {
ServiceMap stack = await isolate.getStack();
expect(stack.type, equals('Stack'));
expect(stack['frames'].length, greaterThanOrEqualTo(1));
Script script = stack['frames'][0].location.script;
- expect(script.tokenToLine(stack['frames'][0].location.tokenPos), equals(20));
+ expect(script.tokenToLine(stack['frames'][0].location.tokenPos), equals(19));
},
resumeIsolate,
hasStoppedAtBreakpoint,
-// We are at the breakpoint on line 23.
+// We are at the breakpoint on line 22.
(Isolate isolate) async {
ServiceMap stack = await isolate.getStack();
expect(stack.type, equals('Stack'));
expect(stack['frames'].length, greaterThanOrEqualTo(1));
Script script = stack['frames'][0].location.script;
- expect(script.tokenToLine(stack['frames'][0].location.tokenPos), equals(23));
+ expect(script.tokenToLine(stack['frames'][0].location.tokenPos), equals(22));
},
resumeIsolate,
hasStoppedAtBreakpoint,
-// We are at the breakpoint on line 26.
+// We are at the breakpoint on line 25.
(Isolate isolate) async {
ServiceMap stack = await isolate.getStack();
expect(stack.type, equals('Stack'));
expect(stack['frames'].length, greaterThanOrEqualTo(1));
Script script = stack['frames'][0].location.script;
- expect(script.tokenToLine(stack['frames'][0].location.tokenPos), equals(26));
+ expect(script.tokenToLine(stack['frames'][0].location.tokenPos), equals(25));
},
resumeIsolate,
diff --git a/runtime/observatory/tests/service/debugging_test.dart b/runtime/observatory/tests/service/debugging_test.dart
index e9e2c11..e20e203 100644
--- a/runtime/observatory/tests/service/debugging_test.dart
+++ b/runtime/observatory/tests/service/debugging_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
@@ -28,8 +28,9 @@
// Pause
(Isolate isolate) async {
Completer completer = new Completer();
+ var stream = await isolate.vm.getEventStream(VM.kDebugStream);
var subscription;
- subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
+ subscription = stream.listen((ServiceEvent event) {
if (event.kind == ServiceEvent.kPauseInterrupted) {
subscription.cancel();
completer.complete();
@@ -42,8 +43,9 @@
// Resume
(Isolate isolate) async {
Completer completer = new Completer();
+ var stream = await isolate.vm.getEventStream(VM.kDebugStream);
var subscription;
- subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
+ subscription = stream.listen((ServiceEvent event) {
if (event.kind == ServiceEvent.kResume) {
subscription.cancel();
completer.complete();
@@ -59,8 +61,9 @@
// Set up a listener to wait for breakpoint events.
Completer completer = new Completer();
+ var stream = await isolate.vm.getEventStream(VM.kDebugStream);
var subscription;
- subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
+ subscription = stream.listen((ServiceEvent event) {
if (event.kind == ServiceEvent.kPauseBreakpoint) {
print('Breakpoint reached');
subscription.cancel();
@@ -98,8 +101,9 @@
(Isolate isolate) async {
// Set up a listener to wait for breakpoint events.
Completer completer = new Completer();
+ var stream = await isolate.vm.getEventStream(VM.kDebugStream);
var subscription;
- subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
+ subscription = stream.listen((ServiceEvent event) {
if (event.kind == ServiceEvent.kPauseBreakpoint) {
print('Breakpoint reached');
subscription.cancel();
@@ -126,8 +130,9 @@
(Isolate isolate) async {
// Set up a listener to wait for breakpoint events.
Completer completer = new Completer();
+ var stream = await isolate.vm.getEventStream(VM.kDebugStream);
var subscription;
- subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
+ subscription = stream.listen((ServiceEvent event) {
if (event.kind == ServiceEvent.kBreakpointRemoved) {
print('Breakpoint removed');
expect(isolate.breakpoints.length, equals(0));
@@ -145,8 +150,9 @@
// Resume
(Isolate isolate) async {
Completer completer = new Completer();
+ var stream = await isolate.vm.getEventStream(VM.kDebugStream);
var subscription;
- subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
+ subscription = stream.listen((ServiceEvent event) {
if (event.kind == ServiceEvent.kResume) {
subscription.cancel();
completer.complete();
@@ -160,8 +166,9 @@
(Isolate isolate) async {
// Set up a listener to wait for breakpoint events.
Completer completer = new Completer();
+ var stream = await isolate.vm.getEventStream(VM.kDebugStream);
var subscription;
- subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
+ subscription = stream.listen((ServiceEvent event) {
if (event.kind == ServiceEvent.kPauseBreakpoint) {
print('Breakpoint reached');
subscription.cancel();
diff --git a/runtime/observatory/tests/service/dominator_tree_test.dart b/runtime/observatory/tests/service/dominator_tree_test.dart
index c5f62e8..ef4fcd8 100644
--- a/runtime/observatory/tests/service/dominator_tree_test.dart
+++ b/runtime/observatory/tests/service/dominator_tree_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/tests/service/echo_test.dart b/runtime/observatory/tests/service/echo_test.dart
index eab5888..b64b177 100644
--- a/runtime/observatory/tests/service/echo_test.dart
+++ b/runtime/observatory/tests/service/echo_test.dart
@@ -1,7 +1,7 @@
// 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.
-// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'dart:async';
import 'package:observatory/service_io.dart';
@@ -22,19 +22,22 @@
expect(result['text'], equals('hello'));
}),
-(Isolate isolate) {
+(Isolate isolate) async {
Completer completer = new Completer();
- isolate.vm.events.stream.listen((ServiceEvent event) {
- if (event.kind == '_Echo') {
- expect(event.data.lengthInBytes, equals(3));
- expect(event.data.getUint8(0), equals(0));
- expect(event.data.getUint8(1), equals(128));
- expect(event.data.getUint8(2), equals(255));
- completer.complete();
- }
+ var stream = await isolate.vm.getEventStream('_Echo');
+ var subscription;
+ subscription = stream.listen((ServiceEvent event) {
+ assert(event.kind == '_Echo');
+ expect(event.data.lengthInBytes, equals(3));
+ expect(event.data.getUint8(0), equals(0));
+ expect(event.data.getUint8(1), equals(128));
+ expect(event.data.getUint8(2), equals(255));
+ subscription.cancel();
+ completer.complete();
});
- isolate.invokeRpc('_triggerEchoEvent', { 'text': 'hello' });
- return completer.future;
+
+ await isolate.invokeRpc('_triggerEchoEvent', { 'text': 'hello' });
+ await completer.future;
},
];
diff --git a/runtime/observatory/tests/service/eval_test.dart b/runtime/observatory/tests/service/eval_test.dart
index aac5d3f..8414aa7 100644
--- a/runtime/observatory/tests/service/eval_test.dart
+++ b/runtime/observatory/tests/service/eval_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
@@ -34,11 +34,15 @@
return isolate.rootLibrary.load().then((_) {
// Set up a listener to wait for breakpoint events.
Completer completer = new Completer();
- isolate.vm.events.stream.listen((ServiceEvent event) {
- if (event.kind == ServiceEvent.kPauseBreakpoint) {
- print('Breakpoint reached');
- completer.complete();
- }
+ isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
+ var subscription;
+ subscription = stream.listen((ServiceEvent event) {
+ if (event.kind == ServiceEvent.kPauseBreakpoint) {
+ print('Breakpoint reached');
+ subscription.cancel();
+ completer.complete();
+ }
+ });
});
// Add the breakpoint.
diff --git a/runtime/observatory/tests/service/evaluate_activation_test.dart b/runtime/observatory/tests/service/evaluate_activation_test.dart
index 7862026..cffc6fa 100644
--- a/runtime/observatory/tests/service/evaluate_activation_test.dart
+++ b/runtime/observatory/tests/service/evaluate_activation_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
@@ -78,8 +78,9 @@
expect(bpt is Breakpoint, isTrue); // I.e, not null.
bool hitBreakpoint = false;
+ var stream = await isolate.vm.getEventStream(VM.kDebugStream);
var sub;
- sub = isolate.vm.events.stream.listen((ServiceEvent event) async {
+ sub = stream.listen((ServiceEvent event) async {
print("Event $event");
if (event.kind == ServiceEvent.kPauseBreakpoint) {
var frameNumber = 1, r;
@@ -126,8 +127,9 @@
expect(bpt is Breakpoint, isTrue); // I.e, not null.
bool hitBreakpoint = false;
+ var stream = await isolate.vm.getEventStream(VM.kDebugStream);
var sub;
- sub = isolate.vm.events.stream.listen((ServiceEvent event) async {
+ sub = stream.listen((ServiceEvent event) async {
print("Event $event");
if (event.kind == ServiceEvent.kPauseBreakpoint) {
var frameNumber = 1, r;
@@ -174,8 +176,9 @@
expect(bpt is Breakpoint, isTrue); // I.e, not null.
bool hitBreakpoint = false;
+ var stream = await isolate.vm.getEventStream(VM.kDebugStream);
var sub;
- sub = isolate.vm.events.stream.listen((ServiceEvent event) async {
+ sub = stream.listen((ServiceEvent event) async {
print("Event $event");
if (event.kind == ServiceEvent.kPauseBreakpoint) {
var frameNumber = 1, r;
@@ -215,8 +218,9 @@
expect(bpt is Breakpoint, isTrue); // I.e, not null.
bool hitBreakpoint = false;
+ var stream = await isolate.vm.getEventStream(VM.kDebugStream);
var sub;
- sub = isolate.vm.events.stream.listen((ServiceEvent event) async {
+ sub = stream.listen((ServiceEvent event) async {
print("Event $event");
if (event.kind == ServiceEvent.kPauseBreakpoint) {
var frameNumber = 1, r;
diff --git a/runtime/observatory/tests/service/gc_test.dart b/runtime/observatory/tests/service/gc_test.dart
index 9d93b0a..fba9ebd 100644
--- a/runtime/observatory/tests/service/gc_test.dart
+++ b/runtime/observatory/tests/service/gc_test.dart
@@ -1,7 +1,7 @@
// 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.
-// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'test_helper.dart';
@@ -26,13 +26,16 @@
Completer completer = new Completer();
// Expect at least this many GC events.
int gcCountdown = 3;
- isolate.vm.events.stream.listen((ServiceEvent event) {
- if (event.kind == ServiceEvent.kGC) {
+ isolate.vm.getEventStream(VM.kGCStream).then((stream) {
+ var subscription;
+ subscription = stream.listen((ServiceEvent event) {
+ assert(event.kind == ServiceEvent.kGC);
print('Received GC event');
if (--gcCountdown == 0) {
+ subscription.cancel();
completer.complete();
}
- }
+ });
});
return completer.future;
},
diff --git a/runtime/observatory/tests/service/get_allocation_profile_rpc_test.dart b/runtime/observatory/tests/service/get_allocation_profile_rpc_test.dart
index 0217fa5..10ffc2c 100644
--- a/runtime/observatory/tests/service/get_allocation_profile_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_allocation_profile_rpc_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/tests/service/get_flag_list_rpc_test.dart b/runtime/observatory/tests/service/get_flag_list_rpc_test.dart
index f05def6..db3040c 100644
--- a/runtime/observatory/tests/service/get_flag_list_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_flag_list_rpc_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/tests/service/get_heap_map_rpc_test.dart b/runtime/observatory/tests/service/get_heap_map_rpc_test.dart
index 5247ca9..9999ce6 100644
--- a/runtime/observatory/tests/service/get_heap_map_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_heap_map_rpc_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/tests/service/get_instances_rpc_test.dart b/runtime/observatory/tests/service/get_instances_rpc_test.dart
index ee2df7f..da26013 100644
--- a/runtime/observatory/tests/service/get_instances_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_instances_rpc_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/tests/service/get_isolate_rpc_test.dart b/runtime/observatory/tests/service/get_isolate_rpc_test.dart
index bbdeabe..153cbb6 100644
--- a/runtime/observatory/tests/service/get_isolate_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_isolate_rpc_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/tests/service/get_object_rpc_test.dart b/runtime/observatory/tests/service/get_object_rpc_test.dart
index b1df709..18d984d 100644
--- a/runtime/observatory/tests/service/get_object_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_object_rpc_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
library get_object_rpc_test;
diff --git a/runtime/observatory/tests/service/get_ports_rpc_test.dart b/runtime/observatory/tests/service/get_ports_rpc_test.dart
index 58081a0..1c08a16 100644
--- a/runtime/observatory/tests/service/get_ports_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_ports_rpc_test.dart
@@ -1,11 +1,10 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
library get_ports_rpc_test;
-import 'dart:async';
import 'dart:isolate' hide Isolate;
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/tests/service/get_retained_size_rpc_test.dart b/runtime/observatory/tests/service/get_retained_size_rpc_test.dart
index 93740f3..1ead7cf 100644
--- a/runtime/observatory/tests/service/get_retained_size_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_retained_size_rpc_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart b/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart
index 1e92dfd..dbb43c7 100644
--- a/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/tests/service/get_stack_rpc_test.dart b/runtime/observatory/tests/service/get_stack_rpc_test.dart
index 45b3112..f3736e6 100644
--- a/runtime/observatory/tests/service/get_stack_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_stack_rpc_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart
index 92b8c06..cb03444 100644
--- a/runtime/observatory/tests/service/get_version_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_version_rpc_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/tests/service/get_vm_rpc_test.dart b/runtime/observatory/tests/service/get_vm_rpc_test.dart
index 5b03dde..95481c5 100644
--- a/runtime/observatory/tests/service/get_vm_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_vm_rpc_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/tests/service/graph_test.dart b/runtime/observatory/tests/service/graph_test.dart
index c3de708..feac00c 100644
--- a/runtime/observatory/tests/service/graph_test.dart
+++ b/runtime/observatory/tests/service/graph_test.dart
@@ -1,7 +1,7 @@
// 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.
-// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/object_graph.dart';
import 'package:observatory/service_io.dart';
diff --git a/runtime/observatory/tests/service/inbound_references_test.dart b/runtime/observatory/tests/service/inbound_references_test.dart
index 5807c4c..ba97490 100644
--- a/runtime/observatory/tests/service/inbound_references_test.dart
+++ b/runtime/observatory/tests/service/inbound_references_test.dart
@@ -1,7 +1,7 @@
// 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.
-// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
library inbound_references_test;
diff --git a/runtime/observatory/tests/service/isolate_lifecycle_test.dart b/runtime/observatory/tests/service/isolate_lifecycle_test.dart
index 3180137..dbacef8 100644
--- a/runtime/observatory/tests/service/isolate_lifecycle_test.dart
+++ b/runtime/observatory/tests/service/isolate_lifecycle_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'dart:async';
import 'dart:isolate' as I;
@@ -54,7 +54,8 @@
(VM vm) async {
// Wait for the testee to start all of the isolates.
if (vm.isolates.length != spawnCount + 1) {
- await processServiceEvents(vm, (event, sub, completer) {
+ await processServiceEvents(vm, VM.kIsolateStream,
+ (event, sub, completer) {
if (event.kind == ServiceEvent.kIsolateStart) {
if (vm.isolates.length == spawnCount + 1) {
sub.cancel();
@@ -76,7 +77,8 @@
(VM vm) async {
// Wait for all spawned isolates to hit pause-at-exit.
if (numPaused(vm) != spawnCount) {
- await processServiceEvents(vm, (event, sub, completer) {
+ await processServiceEvents(vm, VM.kDebugStream,
+ (event, sub, completer) {
if (event.kind == ServiceEvent.kPauseExit) {
if (numPaused(vm) == spawnCount) {
sub.cancel();
@@ -92,7 +94,8 @@
(VM vm) async {
var resumedReceived = 0;
- var eventsDone = processServiceEvents(vm, (event, sub, completer) {
+ var eventsDone = processServiceEvents(vm, VM.kIsolateStream,
+ (event, sub, completer) {
if (event.kind == ServiceEvent.kIsolateExit) {
resumedReceived++;
if (resumedReceived == resumeCount) {
diff --git a/runtime/observatory/tests/service/library_dependency_test.dart b/runtime/observatory/tests/service/library_dependency_test.dart
index 4547e96..b198f01 100644
--- a/runtime/observatory/tests/service/library_dependency_test.dart
+++ b/runtime/observatory/tests/service/library_dependency_test.dart
@@ -1,13 +1,11 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
-import 'package:observatory/debugger.dart';
import 'package:unittest/unittest.dart';
import 'test_helper.dart';
-import 'dart:async';
export 'dart:collection';
import 'dart:mirrors' as mirrors;
diff --git a/runtime/observatory/tests/service/malformed_test.dart b/runtime/observatory/tests/service/malformed_test.dart
index 3d224719..6cf5302 100644
--- a/runtime/observatory/tests/service/malformed_test.dart
+++ b/runtime/observatory/tests/service/malformed_test.dart
@@ -1,7 +1,7 @@
// 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.
-// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/tests/service/metrics_test.dart b/runtime/observatory/tests/service/metrics_test.dart
index 2d3272f..0708d8e 100644
--- a/runtime/observatory/tests/service/metrics_test.dart
+++ b/runtime/observatory/tests/service/metrics_test.dart
@@ -1,7 +1,7 @@
// 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.
-// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/tests/service/mirror_references_test.dart b/runtime/observatory/tests/service/mirror_references_test.dart
index 28a15c0f..dacb412 100644
--- a/runtime/observatory/tests/service/mirror_references_test.dart
+++ b/runtime/observatory/tests/service/mirror_references_test.dart
@@ -1,7 +1,7 @@
// 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.
-// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
library vm_references_test;
diff --git a/runtime/observatory/tests/service/native_metrics_test.dart b/runtime/observatory/tests/service/native_metrics_test.dart
index 4a7182e..39f2c37 100644
--- a/runtime/observatory/tests/service/native_metrics_test.dart
+++ b/runtime/observatory/tests/service/native_metrics_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/tests/service/pause_on_exceptions_test.dart b/runtime/observatory/tests/service/pause_on_exceptions_test.dart
index d8926fe..e5528bc 100644
--- a/runtime/observatory/tests/service/pause_on_exceptions_test.dart
+++ b/runtime/observatory/tests/service/pause_on_exceptions_test.dart
@@ -34,8 +34,9 @@
var onPaused = null;
var onResume = null;
+ var stream = await isolate.vm.getEventStream(VM.kDebugStream);
var subscription;
- subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
+ subscription = stream.listen((ServiceEvent event) {
print("Event $event");
if (event.kind == ServiceEvent.kPauseException) {
if (onPaused == null) throw "Unexpected pause event $event";
diff --git a/runtime/observatory/tests/service/set_library_debuggable_rpc_test.dart b/runtime/observatory/tests/service/set_library_debuggable_rpc_test.dart
index 0f9aa40..fea9fed 100644
--- a/runtime/observatory/tests/service/set_library_debuggable_rpc_test.dart
+++ b/runtime/observatory/tests/service/set_library_debuggable_rpc_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
library set_library_debuggable_rpc_test;
diff --git a/runtime/observatory/tests/service/steal_breakpoint_test.dart b/runtime/observatory/tests/service/steal_breakpoint_test.dart
index bbe25d9..95a4191 100644
--- a/runtime/observatory/tests/service/steal_breakpoint_test.dart
+++ b/runtime/observatory/tests/service/steal_breakpoint_test.dart
@@ -1,7 +1,7 @@
// 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 --steal-breakpoints
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override --steal-breakpoints
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
@@ -29,8 +29,9 @@
// Set up a listener to wait for breakpoint events.
Completer completer = new Completer();
+ var stream = await isolate.vm.getEventStream(VM.kDebugStream);
var subscription;
- subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
+ subscription = stream.listen((ServiceEvent event) {
if (event.kind == ServiceEvent.kPauseBreakpoint) {
print('Isolate paused at breakpoint');
subscription.cancel();
@@ -61,8 +62,9 @@
// Resume
(Isolate isolate) async {
Completer completer = new Completer();
+ var stream = await isolate.vm.getEventStream(VM.kDebugStream);
var subscription;
- subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
+ subscription = stream.listen((ServiceEvent event) {
if (event.kind == ServiceEvent.kResume) {
print('Isolate resumed');
subscription.cancel();
diff --git a/runtime/observatory/tests/service/string_escaping_test.dart b/runtime/observatory/tests/service/string_escaping_test.dart
index d3420db..0fd3c6a 100644
--- a/runtime/observatory/tests/service/string_escaping_test.dart
+++ b/runtime/observatory/tests/service/string_escaping_test.dart
@@ -1,7 +1,7 @@
// 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.
-// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
library string_escaping_test;
diff --git a/runtime/observatory/tests/service/test_helper.dart b/runtime/observatory/tests/service/test_helper.dart
index e69a257..f47f1cd 100644
--- a/runtime/observatory/tests/service/test_helper.dart
+++ b/runtime/observatory/tests/service/test_helper.dart
@@ -1,7 +1,7 @@
// 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.
-// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override --checked
library test_helper;
@@ -141,11 +141,15 @@
StreamSubscription subscription,
Completer completer);
-Future processServiceEvents(VM vm, ServiceEventHandler handler) {
+Future processServiceEvents(VM vm,
+ String streamId,
+ ServiceEventHandler handler) {
Completer completer = new Completer();
- var subscription;
- subscription = vm.events.stream.listen((ServiceEvent event) {
- handler(event, subscription, completer);
+ vm.getEventStream(streamId).then((stream) {
+ var subscription;
+ subscription = stream.listen((ServiceEvent event) {
+ handler(event, subscription, completer);
+ });
});
return completer.future;
}
@@ -161,13 +165,15 @@
// Set up a listener to wait for breakpoint events.
Completer completer = new Completer();
- var subscription;
- subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
- if (event.kind == ServiceEvent.kPauseBreakpoint) {
- print('Breakpoint reached');
- subscription.cancel();
- completer.complete(isolate);
- }
+ isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
+ var subscription;
+ subscription = stream.listen((ServiceEvent event) {
+ if (event.kind == ServiceEvent.kPauseBreakpoint) {
+ print('Breakpoint reached');
+ subscription.cancel();
+ completer.complete();
+ }
+ });
});
return completer.future; // Will complete when breakpoint hit.
@@ -176,12 +182,14 @@
Future<Isolate> resumeIsolate(Isolate isolate) {
Completer completer = new Completer();
- var subscription;
- subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
- if (event.kind == ServiceEvent.kResume) {
- subscription.cancel();
- completer.complete();
- }
+ isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
+ var subscription;
+ subscription = stream.listen((ServiceEvent event) {
+ if (event.kind == ServiceEvent.kResume) {
+ subscription.cancel();
+ completer.complete();
+ }
+ });
});
isolate.resume();
return completer.future;
diff --git a/runtime/observatory/tests/service/type_arguments_test.dart b/runtime/observatory/tests/service/type_arguments_test.dart
index aa06ade..6741520 100644
--- a/runtime/observatory/tests/service/type_arguments_test.dart
+++ b/runtime/observatory/tests/service/type_arguments_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/tests/service/typed_data_test.dart b/runtime/observatory/tests/service/typed_data_test.dart
index f0070a0..83be522 100644
--- a/runtime/observatory/tests/service/typed_data_test.dart
+++ b/runtime/observatory/tests/service/typed_data_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
library typed_data_test;
diff --git a/runtime/observatory/tests/service/vm_test.dart b/runtime/observatory/tests/service/vm_test.dart
index 1e58d9b..bbce87b 100644
--- a/runtime/observatory/tests/service/vm_test.dart
+++ b/runtime/observatory/tests/service/vm_test.dart
@@ -1,7 +1,7 @@
// 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
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/tests/service/weak_properties_test.dart b/runtime/observatory/tests/service/weak_properties_test.dart
index 30ae2a0..7de95c1 100644
--- a/runtime/observatory/tests/service/weak_properties_test.dart
+++ b/runtime/observatory/tests/service/weak_properties_test.dart
@@ -1,7 +1,7 @@
// 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.
-// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
library vm_references_test;
diff --git a/runtime/third_party/double-conversion/src/strtod.cc b/runtime/third_party/double-conversion/src/strtod.cc
index 3471756..17abcbb 100644
--- a/runtime/third_party/double-conversion/src/strtod.cc
+++ b/runtime/third_party/double-conversion/src/strtod.cc
@@ -286,7 +286,7 @@
const int kDenominator = 1 << kDenominatorLog;
// Move the remaining decimals into the exponent.
exponent += remaining_decimals;
- int error = (remaining_decimals == 0 ? 0 : kDenominator / 2);
+ uint64_t error = (remaining_decimals == 0 ? 0 : kDenominator / 2);
int old_e = input.e();
input.Normalize();
diff --git a/runtime/vm/allocation.cc b/runtime/vm/allocation.cc
index b8f9cb1..b6ca73e 100644
--- a/runtime/vm/allocation.cc
+++ b/runtime/vm/allocation.cc
@@ -20,12 +20,12 @@
void* ZoneAllocated::operator new(uword size) {
- return Allocate(size, Isolate::Current()->current_zone());
+ return Allocate(size, Thread::Current()->zone());
}
void* ZoneAllocated::operator new(uword size, Zone* zone) {
- ASSERT(zone == Isolate::Current()->current_zone());
+ ASSERT(zone == Thread::Current()->zone());
return Allocate(size, zone);
}
diff --git a/runtime/vm/allocation.h b/runtime/vm/allocation.h
index 579ed77..f6b74b8 100644
--- a/runtime/vm/allocation.h
+++ b/runtime/vm/allocation.h
@@ -8,6 +8,7 @@
#include "platform/assert.h"
#include "vm/base_isolate.h"
#include "vm/globals.h"
+#include "vm/thread.h"
namespace dart {
@@ -36,42 +37,62 @@
// to a stack frame above the frame where these objects were allocated.
class StackResource {
public:
- explicit StackResource(Isolate* isolate)
- : isolate_(reinterpret_cast<BaseIsolate*>(isolate)), previous_(NULL) {
- // We can only have longjumps and exceptions when there is a current
- // isolate. If there is no current isolate, we don't need to
- // protect this case.
- if (isolate_ != NULL) {
- previous_ = isolate_->top_resource();
- isolate_->set_top_resource(this);
- }
+ // DEPRECATED: Use Thread-based interface. During migration, this defaults
+ // to using the mutator thread (which must also be the current thread).
+ explicit StackResource(Isolate* isolate) : thread_(NULL), previous_(NULL) {
+ Init((isolate == NULL) ?
+ NULL : reinterpret_cast<BaseIsolate*>(isolate)->mutator_thread_);
+ }
+
+ explicit StackResource(Thread* thread) : thread_(NULL), previous_(NULL) {
+ Init(thread);
}
virtual ~StackResource() {
- if (isolate_ != NULL) {
- StackResource* top = isolate_->top_resource();
+ if (thread_ != NULL) {
+ StackResource* top = thread_->top_resource();
ASSERT(top == this);
- isolate_->set_top_resource(previous_);
+ thread_->set_top_resource(previous_);
}
#if defined(DEBUG)
- if (isolate_ != NULL) {
- BaseIsolate::AssertCurrent(isolate_);
+ if (thread_ != NULL) {
+ ASSERT(Thread::Current() == thread_);
+ BaseIsolate::AssertCurrent(reinterpret_cast<BaseIsolate*>(isolate()));
}
#endif
}
- // We can only create StackResources with Isolates, so provide the original
- // isolate to the subclasses. The only reason we have a BaseIsolate in the
- // StackResource is to break the header include cycles.
- Isolate* isolate() const { return reinterpret_cast<Isolate*>(isolate_); }
+ // Convenient access to the isolate of the thread of this resource.
+ Isolate* isolate() const {
+ return thread_ == NULL ? NULL : thread_->isolate();
+ }
+
+ // The thread that owns this resource.
+ Thread* thread() const { return thread_; }
// Destroy stack resources of isolate until top exit frame.
+ // TODO(koda): Migrate to Thread.
static void Unwind(Isolate* isolate) { UnwindAbove(isolate, NULL); }
+ // TODO(koda): Migrate to Thread.
// Destroy stack resources of isolate above new_top, exclusive.
static void UnwindAbove(Isolate* isolate, StackResource* new_top);
private:
- BaseIsolate* const isolate_; // Current isolate for this stack resource.
+ 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);
+ }
+ }
+
+ Thread* thread_;
StackResource* previous_;
DISALLOW_ALLOCATION();
diff --git a/runtime/vm/assembler.cc b/runtime/vm/assembler.cc
index cefafb8..3f3e61a 100644
--- a/runtime/vm/assembler.cc
+++ b/runtime/vm/assembler.cc
@@ -24,7 +24,7 @@
DECLARE_FLAG(bool, disassemble_optimized);
static uword NewContents(intptr_t capacity) {
- Zone* zone = Isolate::Current()->current_zone();
+ Zone* zone = Thread::Current()->zone();
uword result = zone->AllocUnsafe(capacity);
#if defined(DEBUG)
// Initialize the buffer with kBreakPointInstruction to force a break
@@ -254,8 +254,6 @@
intptr_t ObjectPoolWrapper::AddObject(ObjectPool::Entry entry,
Patchability patchable) {
- // The object pool cannot be used in the vm isolate.
- ASSERT(Isolate::Current() != Dart::vm_isolate());
object_pool_.Add(entry);
if (patchable == kNotPatchable) {
// The object isn't patchable. Record the index for fast lookup.
@@ -268,7 +266,6 @@
intptr_t ObjectPoolWrapper::AddExternalLabel(const ExternalLabel* label,
Patchability patchable) {
- ASSERT(Isolate::Current() != Dart::vm_isolate());
return AddObject(ObjectPool::Entry(label->address(),
ObjectPool::kImmediate),
patchable);
@@ -277,9 +274,6 @@
intptr_t ObjectPoolWrapper::FindObject(ObjectPool::Entry entry,
Patchability patchable) {
- // The object pool cannot be used in the vm isolate.
- ASSERT(Isolate::Current() != Dart::vm_isolate());
-
// If the object is not patchable, check if we've already got it in the
// object pool.
if (patchable == kNotPatchable) {
@@ -306,8 +300,6 @@
intptr_t ObjectPoolWrapper::FindExternalLabel(const ExternalLabel* label,
Patchability patchable) {
- // The object pool cannot be used in the vm isolate.
- ASSERT(Isolate::Current() != Dart::vm_isolate());
return FindObject(ObjectPool::Entry(label->address(),
ObjectPool::kImmediate),
patchable);
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index 28d2c56..a354940 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -1567,6 +1567,12 @@
const Object& object,
Condition cond,
bool is_unique) {
+ // Load common VM constants from the thread. This works also in places where
+ // no constant pool is set up (e.g. intrinsic code).
+ if (Thread::CanLoadFromThread(object)) {
+ ldr(rd, Address(THR, Thread::OffsetFromThread(object)), cond);
+ return;
+ }
// Smis and VM heap objects are never relocated; do not use object pool.
if (object.IsSmi()) {
LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw()), cond);
@@ -1808,8 +1814,8 @@
if (object != R0) {
mov(R0, Operand(object));
}
- StubCode* stub_code = Isolate::Current()->stub_code();
- BranchLink(&stub_code->UpdateStoreBufferLabel());
+ ldr(LR, Address(THR, Thread::update_store_buffer_entry_point_offset()));
+ blx(LR);
PopList(regs);
Bind(&done);
}
@@ -1961,8 +1967,10 @@
void Assembler::LoadClassById(Register result, Register class_id) {
ASSERT(result != class_id);
- LoadImmediate(result, Isolate::Current()->class_table()->TableAddress());
- LoadFromOffset(kWord, result, result, 0);
+ LoadIsolate(result);
+ const intptr_t offset =
+ Isolate::class_table_offset() + ClassTable::table_offset();
+ LoadFromOffset(kWord, result, result, offset);
ldr(result, Address(result, class_id, LSL, 2));
}
@@ -3337,8 +3345,7 @@
void Assembler::LoadAllocationStatsAddress(Register dest,
- intptr_t cid,
- Heap::Space space) {
+ intptr_t cid) {
ASSERT(dest != kNoRegister);
ASSERT(dest != TMP);
ASSERT(cid > 0);
@@ -3358,6 +3365,18 @@
}
+void Assembler::MaybeTraceAllocation(intptr_t cid,
+ Register temp_reg,
+ Label* trace) {
+ LoadAllocationStatsAddress(temp_reg, cid);
+ const uword state_offset = ClassHeapStats::state_offset();
+ const Address& state_address = Address(temp_reg, state_offset);
+ ldr(temp_reg, state_address);
+ tst(temp_reg, Operand(ClassHeapStats::TraceAllocationMask()));
+ b(trace, NE);
+}
+
+
void Assembler::IncrementAllocationStats(Register stats_addr_reg,
intptr_t cid,
Heap::Space space) {
@@ -3408,6 +3427,10 @@
ASSERT(temp_reg != IP);
const intptr_t instance_size = cls.instance_size();
ASSERT(instance_size != 0);
+ // If this allocation is traced, program will jump to failure path
+ // (i.e. the allocation stub) which will allocate the object and trace the
+ // allocation call site.
+ MaybeTraceAllocation(cls.id(), temp_reg, failure);
Heap* heap = Isolate::Current()->heap();
Heap::Space space = heap->SpaceForAllocation(cls.id());
const uword top_address = heap->TopAddress(space);
@@ -3429,7 +3452,7 @@
// next object start and store the class in the class field of object.
str(instance_reg, Address(temp_reg));
- LoadAllocationStatsAddress(temp_reg, cls.id(), space);
+ LoadAllocationStatsAddress(temp_reg, cls.id());
ASSERT(instance_size >= kHeapObjectTag);
AddImmediate(instance_reg, -instance_size + kHeapObjectTag);
@@ -3456,6 +3479,10 @@
Register temp1,
Register temp2) {
if (FLAG_inline_alloc) {
+ // If this allocation is traced, program will jump to failure path
+ // (i.e. the allocation stub) which will allocate the object and trace the
+ // allocation call site.
+ MaybeTraceAllocation(cid, temp1, failure);
Isolate* isolate = Isolate::Current();
Heap* heap = isolate->heap();
Heap::Space space = heap->SpaceForAllocation(cid);
@@ -3472,7 +3499,7 @@
cmp(end_address, Operand(temp2));
b(failure, CS);
- LoadAllocationStatsAddress(temp2, cid, space);
+ LoadAllocationStatsAddress(temp2, cid);
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index f3d9583..4301677 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -910,8 +910,7 @@
// allocation stats. These are separate assembler macros so we can
// avoid a dependent load too nearby the load of the table address.
void LoadAllocationStatsAddress(Register dest,
- intptr_t cid,
- Heap::Space space);
+ intptr_t cid);
void IncrementAllocationStats(Register stats_addr,
intptr_t cid,
Heap::Space space);
@@ -935,6 +934,12 @@
Register array,
Register index);
+ // If allocation tracing for |cid| is enabled, will jump to |trace| label,
+ // which will allocate in the runtime where tracing occurs.
+ void MaybeTraceAllocation(intptr_t cid,
+ Register temp_reg,
+ Label* trace);
+
// Inlined allocation of an instance of class 'cls', code has no runtime
// calls. Jump to 'failure' if the instance cannot be allocated here.
// Allocated instance is returned in 'instance_reg'.
diff --git a/runtime/vm/assembler_arm64.cc b/runtime/vm/assembler_arm64.cc
index 4e39862..6d315e6 100644
--- a/runtime/vm/assembler_arm64.cc
+++ b/runtime/vm/assembler_arm64.cc
@@ -31,28 +31,6 @@
use_far_branches_(use_far_branches),
comments_(),
allow_constant_pool_(true) {
- if (Isolate::Current() != Dart::vm_isolate()) {
- // These objects and labels need to be accessible through every pool-pointer
- // at the same index.
- intptr_t index =
- object_pool_wrapper_.AddObject(Object::null_object());
- ASSERT(index == 0);
-
- index = object_pool_wrapper_.AddObject(Bool::True());
- ASSERT(index == 1);
-
- index = object_pool_wrapper_.AddObject(Bool::False());
- ASSERT(index == 2);
-
- const Smi& vacant = Smi::Handle(Smi::New(0xfa >> kSmiTagShift));
- StubCode* stub_code = Isolate::Current()->stub_code();
- if (stub_code->UpdateStoreBuffer_entry() != NULL) {
- object_pool_wrapper_.AddExternalLabel(
- &stub_code->UpdateStoreBufferLabel(), kNotPatchable);
- } else {
- object_pool_wrapper_.AddObject(vacant);
- }
- }
}
@@ -382,23 +360,14 @@
intptr_t Assembler::FindImmediate(int64_t imm) {
- ASSERT(Isolate::Current() != Dart::vm_isolate());
return object_pool_wrapper_.FindImmediate(imm);
}
-// A set of VM objects that are present in every constant pool.
-static bool IsAlwaysInConstantPool(const Object& object) {
- // TODO(zra): Evaluate putting all VM heap objects into the pool.
- return (object.raw() == Object::null())
- || (object.raw() == Bool::True().raw())
- || (object.raw() == Bool::False().raw());
-}
-
-
-bool Assembler::CanLoadObjectFromPool(const Object& object) {
+bool Assembler::CanLoadFromObjectPool(const Object& object) const {
+ ASSERT(!Thread::CanLoadFromThread(object));
if (!allow_constant_pool()) {
- return IsAlwaysInConstantPool(object);
+ return false;
}
// TODO(zra, kmillikin): Also load other large immediates from the object
@@ -410,7 +379,7 @@
}
ASSERT(object.IsNotTemporaryScopedHandle());
ASSERT(object.IsOld());
- return (Isolate::Current() != Dart::vm_isolate());
+ return true;
}
@@ -418,12 +387,7 @@
if (!allow_constant_pool()) {
return false;
}
- return !Utils::IsInt(32, imm) &&
- (pp != kNoPP) &&
- // We *could* put constants in the pool in a VM isolate, but it is
- // simpler to maintain the invariant that the object pool is not used
- // in the VM isolate.
- (Isolate::Current() != Dart::vm_isolate());
+ return !Utils::IsInt(32, imm) && (pp != kNoPP);
}
@@ -452,7 +416,7 @@
}
-void Assembler::LoadIsolate(Register dst, Register pp) {
+void Assembler::LoadIsolate(Register dst) {
ldr(dst, Address(THR, Thread::isolate_offset()));
}
@@ -461,15 +425,15 @@
const Object& object,
Register pp,
bool is_unique) {
- if (CanLoadObjectFromPool(object)) {
+ if (Thread::CanLoadFromThread(object)) {
+ ldr(dst, Address(THR, Thread::OffsetFromThread(object)));
+ } else if (CanLoadFromObjectPool(object)) {
const int32_t offset = ObjectPool::element_offset(
is_unique ? object_pool_wrapper_.AddObject(object)
: object_pool_wrapper_.FindObject(object));
LoadWordFromPoolOffset(dst, pp, offset);
} else {
- ASSERT((Isolate::Current() == Dart::vm_isolate()) ||
- object.IsSmi() ||
- object.InVMHeap());
+ ASSERT(object.IsSmi() || object.InVMHeap());
LoadDecodableImmediate(dst, reinterpret_cast<int64_t>(object.raw()), pp);
}
}
@@ -488,7 +452,10 @@
void Assembler::CompareObject(Register reg, const Object& object, Register pp) {
- if (CanLoadObjectFromPool(object)) {
+ if (Thread::CanLoadFromThread(object)) {
+ ldr(TMP, Address(THR, Thread::OffsetFromThread(object)));
+ CompareRegisters(reg, TMP);
+ } else if (CanLoadFromObjectPool(object)) {
LoadObject(TMP, object, pp);
CompareRegisters(reg, TMP);
} else {
@@ -498,17 +465,9 @@
void Assembler::LoadDecodableImmediate(Register reg, int64_t imm, Register pp) {
- if ((pp != kNoPP) &&
- (Isolate::Current() != Dart::vm_isolate()) &&
- allow_constant_pool()) {
- int64_t val_smi_tag = imm & kSmiTagMask;
- imm &= ~kSmiTagMask; // Mask off the tag bits.
+ if ((pp != kNoPP) && allow_constant_pool()) {
const int32_t offset = ObjectPool::element_offset(FindImmediate(imm));
LoadWordFromPoolOffset(reg, pp, offset);
- if (val_smi_tag != 0) {
- // Add back the tag bits.
- orri(reg, reg, Immediate(val_smi_tag));
- }
} else {
// TODO(zra): Since this sequence only needs to be decodable, it can be
// of variable length.
@@ -931,8 +890,8 @@
if (object != R0) {
mov(R0, object);
}
- StubCode* stub_code = Isolate::Current()->stub_code();
- BranchLink(&stub_code->UpdateStoreBufferLabel(), PP);
+ ldr(TMP, Address(THR, Thread::update_store_buffer_entry_point_offset()));
+ blr(TMP);
Pop(LR);
if (value != R0) {
// Restore R0.
@@ -1005,8 +964,10 @@
void Assembler::LoadClassById(Register result, Register class_id, Register pp) {
ASSERT(result != class_id);
- LoadImmediate(result, Isolate::Current()->class_table()->TableAddress(), pp);
- LoadFromOffset(result, result, 0, pp);
+ LoadIsolate(result);
+ const intptr_t offset =
+ Isolate::class_table_offset() + ClassTable::table_offset();
+ LoadFromOffset(result, result, offset, pp);
ldr(result, Address(result, class_id, UXTX, Address::Scaled));
}
@@ -1347,6 +1308,31 @@
}
+void Assembler::MaybeTraceAllocation(intptr_t cid,
+ Register temp_reg,
+ Register pp,
+ Label* trace) {
+ ASSERT(cid > 0);
+ Isolate* isolate = Isolate::Current();
+ ClassTable* class_table = isolate->class_table();
+ const uword class_offset = cid * sizeof(ClassHeapStats); // NOLINT
+ if (cid < kNumPredefinedCids) {
+ const uword class_heap_stats_table_address =
+ class_table->PredefinedClassHeapStatsTableAddress();
+ LoadImmediate(temp_reg, class_heap_stats_table_address + class_offset, pp);
+ } else {
+ LoadImmediate(temp_reg, class_table->ClassStatsTableAddress(), pp);
+ ldr(temp_reg, Address(temp_reg, 0));
+ AddImmediate(temp_reg, temp_reg, class_offset, pp);
+ }
+ const uword state_offset = ClassHeapStats::state_offset();
+ const Address& state_address = Address(temp_reg, state_offset);
+ ldr(temp_reg, state_address);
+ tsti(temp_reg, Immediate(ClassHeapStats::TraceAllocationMask()));
+ b(trace, NE);
+}
+
+
void Assembler::TryAllocate(const Class& cls,
Label* failure,
Register instance_reg,
@@ -1354,6 +1340,10 @@
Register pp) {
ASSERT(failure != NULL);
if (FLAG_inline_alloc) {
+ // If this allocation is traced, program will jump to failure path
+ // (i.e. the allocation stub) which will allocate the object and trace the
+ // allocation call site.
+ MaybeTraceAllocation(cls.id(), temp_reg, pp, failure);
const intptr_t instance_size = cls.instance_size();
Heap* heap = Isolate::Current()->heap();
Heap::Space space = heap->SpaceForAllocation(cls.id());
@@ -1401,6 +1391,10 @@
Register temp1,
Register temp2) {
if (FLAG_inline_alloc) {
+ // If this allocation is traced, program will jump to failure path
+ // (i.e. the allocation stub) which will allocate the object and trace the
+ // allocation call site.
+ MaybeTraceAllocation(cid, temp1, PP, failure);
Isolate* isolate = Isolate::Current();
Heap* heap = isolate->heap();
Heap::Space space = heap->SpaceForAllocation(cid);
diff --git a/runtime/vm/assembler_arm64.h b/runtime/vm/assembler_arm64.h
index 1da9605..1468547 100644
--- a/runtime/vm/assembler_arm64.h
+++ b/runtime/vm/assembler_arm64.h
@@ -1311,7 +1311,7 @@
void LoadWordFromPoolOffset(Register dst, Register pp, uint32_t offset);
void LoadWordFromPoolOffsetFixed(Register dst, Register pp, uint32_t offset);
intptr_t FindImmediate(int64_t imm);
- bool CanLoadObjectFromPool(const Object& object);
+ bool CanLoadFromObjectPool(const Object& object) const;
bool CanLoadImmediateFromPool(int64_t imm, Register pp);
void LoadExternalLabel(Register dst, const ExternalLabel* label,
Patchability patchable, Register pp);
@@ -1319,7 +1319,7 @@
const ExternalLabel* label,
Patchability patchable,
Register pp);
- void LoadIsolate(Register dst, Register pp);
+ void LoadIsolate(Register dst);
void LoadObject(Register dst, const Object& obj, Register pp);
void LoadUniqueObject(Register dst, const Object& obj, Register pp);
void LoadDecodableImmediate(Register reg, int64_t imm, Register pp);
@@ -1387,6 +1387,13 @@
Register pp,
Heap::Space space);
+ // If allocation tracing for |cid| is enabled, will jump to |trace| label,
+ // which will allocate in the runtime where tracing occurs.
+ void MaybeTraceAllocation(intptr_t cid,
+ Register temp_reg,
+ Register pp,
+ Label* trace);
+
// Inlined allocation of an instance of class 'cls', code has no runtime
// calls. Jump to 'failure' if the instance cannot be allocated here.
// Allocated instance is returned in 'instance_reg'.
diff --git a/runtime/vm/assembler_arm64_test.cc b/runtime/vm/assembler_arm64_test.cc
index 621c03c..28749b3 100644
--- a/runtime/vm/assembler_arm64_test.cc
+++ b/runtime/vm/assembler_arm64_test.cc
@@ -1693,58 +1693,78 @@
}
+#if defined(USING_SIMULATOR)
+#define ASSEMBLER_TEST_RUN_WITH_THREAD(var_name) \
+ Thread* thread = Thread::Current(); \
+ int64_t var_name = Simulator::Current()->Call( \
+ bit_cast<intptr_t, uword>(test->entry()), \
+ reinterpret_cast<intptr_t>(thread), 0, 0, 0)
+#else
+#define ASSEMBER_TEST_RUN_WITH_THREAD(var_name) \
+ typedef int64_t (*Int64Return)(Thread* thread); \
+ Int64Return test_code = reinterpret_cast<Int64Return>(test->entry()); \
+ int64_t var_name = test_code(thread)
+#endif
+
+
// LoadObject null.
ASSEMBLER_TEST_GENERATE(LoadObjectNull, assembler) {
__ SetupDartSP(kTestStackSpace);
+ __ Push(THR);
+ __ mov(THR, R0);
__ TagAndPushPP(); // Save caller's pool pointer and load a new one here.
__ LoadPoolPointer(PP);
__ LoadObject(R0, Object::null_object(), PP);
__ PopAndUntagPP();
+ __ Pop(THR);
__ mov(CSP, SP);
__ ret();
}
ASSEMBLER_TEST_RUN(LoadObjectNull, test) {
- typedef int64_t (*Int64Return)() DART_UNUSED;
- EXPECT_EQ(reinterpret_cast<int64_t>(Object::null()),
- EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
+ ASSEMBLER_TEST_RUN_WITH_THREAD(result);
+ EXPECT_EQ(reinterpret_cast<int64_t>(Object::null()), result);
}
ASSEMBLER_TEST_GENERATE(LoadObjectTrue, assembler) {
__ SetupDartSP(kTestStackSpace);
+ __ Push(THR);
+ __ mov(THR, R0);
__ TagAndPushPP(); // Save caller's pool pointer and load a new one here.
__ LoadPoolPointer(PP);
__ LoadObject(R0, Bool::True(), PP);
__ PopAndUntagPP();
+ __ Pop(THR);
__ mov(CSP, SP);
__ ret();
}
ASSEMBLER_TEST_RUN(LoadObjectTrue, test) {
- typedef int64_t (*Int64Return)() DART_UNUSED;
- EXPECT_EQ(reinterpret_cast<int64_t>(Bool::True().raw()),
- EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
+ ASSEMBLER_TEST_RUN_WITH_THREAD(result);
+ EXPECT_EQ(reinterpret_cast<int64_t>(Bool::True().raw()), result);
}
ASSEMBLER_TEST_GENERATE(LoadObjectFalse, assembler) {
__ SetupDartSP(kTestStackSpace);
+ __ Push(THR);
+ __ mov(THR, R0);
__ TagAndPushPP(); // Save caller's pool pointer and load a new one here.
__ LoadPoolPointer(PP);
__ LoadObject(R0, Bool::False(), PP);
__ PopAndUntagPP();
+ __ Pop(THR);
__ mov(CSP, SP);
__ ret();
}
ASSEMBLER_TEST_RUN(LoadObjectFalse, test) {
- typedef int64_t (*Int64Return)() DART_UNUSED;
- EXPECT_EQ(reinterpret_cast<int64_t>(Bool::False().raw()),
- EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
+ ASSEMBLER_TEST_RUN_WITH_THREAD(result);
+ EXPECT_EQ(reinterpret_cast<int64_t>(Bool::False().raw()), result);
}
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index 249fba0..1059706 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -2683,6 +2683,45 @@
}
+static void ComputeHeapStatsStateAddressForCid(intptr_t cid,
+ Address* state_address) {
+ ASSERT(cid < kNumPredefinedCids);
+ Isolate* isolate = Isolate::Current();
+ ClassTable* class_table = isolate->class_table();
+ const uword class_heap_stats_table_address =
+ class_table->PredefinedClassHeapStatsTableAddress();
+ const uword class_offset = cid * sizeof(ClassHeapStats); // NOLINT
+ const uword state_offset = ClassHeapStats::state_offset();
+ *state_address = Address::Absolute(class_heap_stats_table_address +
+ class_offset +
+ state_offset);
+}
+
+
+void Assembler::MaybeTraceAllocation(intptr_t cid,
+ Register temp_reg,
+ Label* trace,
+ bool near_jump) {
+ ASSERT(cid > 0);
+ Address state_address(kNoRegister, 0);
+ if (cid < kNumPredefinedCids) {
+ ComputeHeapStatsStateAddressForCid(cid, &state_address);
+ } else {
+ ASSERT(temp_reg != kNoRegister);
+ const uword class_offset = cid * sizeof(ClassHeapStats); // NOLINT
+ const uword state_offset = ClassHeapStats::state_offset();
+ // temp_reg gets address of class table pointer.
+ ClassTable* class_table = Isolate::Current()->class_table();
+ movl(temp_reg, Address::Absolute(class_table->ClassStatsTableAddress()));
+ state_address = Address(temp_reg, class_offset + state_offset);
+ }
+ testb(state_address, Immediate(ClassHeapStats::TraceAllocationMask()));
+ // We are tracing for this class, jump to the trace label which will use
+ // the allocation stub.
+ j(NOT_ZERO, trace, near_jump);
+}
+
+
void Assembler::UpdateAllocationStats(intptr_t cid,
Register temp_reg,
Heap::Space space) {
@@ -2739,6 +2778,10 @@
Register temp_reg) {
ASSERT(failure != NULL);
if (FLAG_inline_alloc) {
+ // If this allocation is traced, program will jump to failure path
+ // (i.e. the allocation stub) which will allocate the object and trace the
+ // allocation call site.
+ MaybeTraceAllocation(cls.id(), temp_reg, failure, near_jump);
Heap* heap = Isolate::Current()->heap();
const intptr_t instance_size = cls.instance_size();
Heap::Space space = heap->SpaceForAllocation(cls.id());
@@ -2772,6 +2815,10 @@
Register end_address) {
ASSERT(failure != NULL);
if (FLAG_inline_alloc) {
+ // If this allocation is traced, program will jump to failure path
+ // (i.e. the allocation stub) which will allocate the object and trace the
+ // allocation call site.
+ MaybeTraceAllocation(cid, kNoRegister, failure, near_jump);
Isolate* isolate = Isolate::Current();
Heap* heap = isolate->heap();
Heap::Space space = heap->SpaceForAllocation(cid);
@@ -2976,8 +3023,10 @@
void Assembler::LoadClassById(Register result, Register class_id) {
ASSERT(result != class_id);
- movl(result,
- Address::Absolute(Isolate::Current()->class_table()->TableAddress()));
+ LoadIsolate(result);
+ const intptr_t offset =
+ Isolate::class_table_offset() + ClassTable::table_offset();
+ movl(result, Address(result, offset));
movl(result, Address(result, class_id, TIMES_4, 0));
}
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index 7ebea1d..f08b9d0 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -871,6 +871,13 @@
return kEntryPointToPcMarkerOffset;
}
+ // If allocation tracing for |cid| is enabled, will jump to |trace| label,
+ // which will allocate in the runtime where tracing occurs.
+ void MaybeTraceAllocation(intptr_t cid,
+ Register temp_reg,
+ Label* trace,
+ bool near_jump);
+
void UpdateAllocationStats(intptr_t cid,
Register temp_reg,
Heap::Space space);
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index b418fc8..da5a6df 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -459,6 +459,12 @@
void Assembler::LoadObjectHelper(Register rd,
const Object& object,
bool is_unique) {
+ // Load common VM constants from the thread. This works also in places where
+ // no constant pool is set up (e.g. intrinsic code).
+ if (Thread::CanLoadFromThread(object)) {
+ lw(rd, Address(THR, Thread::OffsetFromThread(object)));
+ return;
+ }
ASSERT(!in_delay_slot_);
// Smis and VM heap objects are never relocated; do not use object pool.
if (object.IsSmi()) {
@@ -568,8 +574,8 @@
if (object != T0) {
mov(T0, object);
}
- StubCode* stub_code = Isolate::Current()->stub_code();
- BranchLink(&stub_code->UpdateStoreBufferLabel());
+ lw(T9, Address(THR, Thread::update_store_buffer_entry_point_offset()));
+ jalr(T9);
lw(RA, Address(SP, 0 * kWordSize));
if (value != T0) {
// Restore T0.
@@ -664,8 +670,10 @@
void Assembler::LoadClassById(Register result, Register class_id) {
ASSERT(!in_delay_slot_);
ASSERT(result != class_id);
- LoadImmediate(result, Isolate::Current()->class_table()->TableAddress());
- lw(result, Address(result, 0));
+ LoadIsolate(result);
+ const intptr_t offset =
+ Isolate::class_table_offset() + ClassTable::table_offset();
+ lw(result, Address(result, offset));
sll(TMP, class_id, 2);
addu(result, result, TMP);
lw(result, Address(result));
@@ -884,6 +892,33 @@
}
+void Assembler::MaybeTraceAllocation(intptr_t cid,
+ Register temp_reg,
+ Label* trace) {
+ ASSERT(cid > 0);
+ ASSERT(!in_delay_slot_);
+ ASSERT(temp_reg != kNoRegister);
+ ASSERT(temp_reg != TMP);
+ Isolate* isolate = Isolate::Current();
+ ClassTable* class_table = isolate->class_table();
+ const uword class_offset = cid * sizeof(ClassHeapStats); // NOLINT
+ if (cid < kNumPredefinedCids) {
+ const uword class_heap_stats_table_address =
+ class_table->PredefinedClassHeapStatsTableAddress();
+ LoadImmediate(temp_reg, class_heap_stats_table_address + class_offset);
+ } else {
+ LoadImmediate(temp_reg, class_table->ClassStatsTableAddress());
+ lw(temp_reg, Address(temp_reg, 0));
+ AddImmediate(temp_reg, class_offset);
+ }
+ const uword state_offset = ClassHeapStats::state_offset();
+ const Address& state_address = Address(temp_reg, state_offset);
+ lw(temp_reg, state_address);
+ andi(CMPRES1, temp_reg, Immediate(ClassHeapStats::TraceAllocationMask()));
+ bne(CMPRES1, ZR, trace);
+}
+
+
void Assembler::TryAllocate(const Class& cls,
Label* failure,
Register instance_reg,
@@ -891,6 +926,10 @@
ASSERT(!in_delay_slot_);
ASSERT(failure != NULL);
if (FLAG_inline_alloc) {
+ // If this allocation is traced, program will jump to failure path
+ // (i.e. the allocation stub) which will allocate the object and trace the
+ // allocation call site.
+ MaybeTraceAllocation(cls.id(), temp_reg, failure);
const intptr_t instance_size = cls.instance_size();
Heap* heap = Isolate::Current()->heap();
Heap::Space space = heap->SpaceForAllocation(cls.id());
@@ -934,6 +973,10 @@
Register temp1,
Register temp2) {
if (FLAG_inline_alloc) {
+ // If this allocation is traced, program will jump to failure path
+ // (i.e. the allocation stub) which will allocate the object and trace the
+ // allocation call site.
+ MaybeTraceAllocation(cid, temp1, failure);
Isolate* isolate = Isolate::Current();
Heap* heap = isolate->heap();
Heap::Space space = heap->SpaceForAllocation(cid);
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index a4c379b..00c0f62 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -312,6 +312,10 @@
Heap::Space space);
+ void MaybeTraceAllocation(intptr_t cid,
+ Register temp_reg,
+ Label* trace);
+
// Inlined allocation of an instance of class 'cls', code has no runtime
// calls. Jump to 'failure' if the instance cannot be allocated here.
// Allocated instance is returned in 'instance_reg'.
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 66b36d0..7477651 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -28,28 +28,6 @@
allow_constant_pool_(true) {
// Far branching mode is only needed and implemented for MIPS and ARM.
ASSERT(!use_far_branches);
- Isolate* isolate = Isolate::Current();
- if (isolate != Dart::vm_isolate()) {
- // These objects and labels need to be accessible through every pool-pointer
- // at the same index.
- intptr_t index = object_pool_wrapper_.AddObject(Object::null_object());
- ASSERT(index == 0);
-
- index = object_pool_wrapper_.AddObject(Bool::True());
- ASSERT(index == 1);
-
- index = object_pool_wrapper_.AddObject(Bool::False());
- ASSERT(index == 2);
-
- const Smi& vacant = Smi::Handle(Smi::New(0xfa >> kSmiTagShift));
- StubCode* stub_code = isolate->stub_code();
- if (stub_code->UpdateStoreBuffer_entry() != NULL) {
- object_pool_wrapper_.AddExternalLabel(
- &stub_code->UpdateStoreBufferLabel(), kNotPatchable);
- } else {
- object_pool_wrapper_.AddObject(vacant);
- }
- }
}
@@ -115,13 +93,9 @@
void Assembler::Call(const ExternalLabel* label, Register pp) {
- if (Isolate::Current() == Dart::vm_isolate()) {
- call(label);
- } else {
- const int32_t offset = ObjectPool::element_offset(
- object_pool_wrapper_.FindExternalLabel(label, kNotPatchable));
- call(Address::AddressBaseImm32(pp, offset - kHeapObjectTag));
- }
+ const int32_t offset = ObjectPool::element_offset(
+ object_pool_wrapper_.FindExternalLabel(label, kNotPatchable));
+ call(Address::AddressBaseImm32(pp, offset - kHeapObjectTag));
}
@@ -2794,18 +2768,10 @@
}
-// A set of VM objects that are present in every constant pool.
-static bool IsAlwaysInConstantPool(const Object& object) {
- // TODO(zra): Evaluate putting all VM heap objects into the pool.
- return (object.raw() == Object::null())
- || (object.raw() == Bool::True().raw())
- || (object.raw() == Bool::False().raw());
-}
-
-
-bool Assembler::CanLoadFromObjectPool(const Object& object) {
+bool Assembler::CanLoadFromObjectPool(const Object& object) const {
+ ASSERT(!Thread::CanLoadFromThread(object));
if (!allow_constant_pool()) {
- return IsAlwaysInConstantPool(object);
+ return false;
}
// TODO(zra, kmillikin): Also load other large immediates from the object
@@ -2817,7 +2783,7 @@
}
ASSERT(object.IsNotTemporaryScopedHandle());
ASSERT(object.IsOld());
- return (Isolate::Current() != Dart::vm_isolate());
+ return true;
}
@@ -2838,15 +2804,15 @@
const Object& object,
Register pp,
bool is_unique) {
- if (CanLoadFromObjectPool(object)) {
+ if (Thread::CanLoadFromThread(object)) {
+ movq(dst, Address(THR, Thread::OffsetFromThread(object)));
+ } else if (CanLoadFromObjectPool(object)) {
const int32_t offset = ObjectPool::element_offset(
is_unique ? object_pool_wrapper_.AddObject(object)
: object_pool_wrapper_.FindObject(object));
LoadWordFromPoolOffset(dst, pp, offset - kHeapObjectTag);
} else {
- ASSERT((Isolate::Current() == Dart::vm_isolate()) ||
- object.IsSmi() ||
- object.InVMHeap());
+ ASSERT(object.IsSmi() || object.InVMHeap());
LoadImmediate(dst, Immediate(reinterpret_cast<int64_t>(object.raw())), pp);
}
}
@@ -2866,7 +2832,10 @@
void Assembler::StoreObject(const Address& dst, const Object& object,
Register pp) {
- if (CanLoadFromObjectPool(object)) {
+ if (Thread::CanLoadFromThread(object)) {
+ movq(TMP, Address(THR, Thread::OffsetFromThread(object)));
+ movq(dst, TMP);
+ } else if (CanLoadFromObjectPool(object)) {
LoadObject(TMP, object, pp);
movq(dst, TMP);
} else {
@@ -2876,7 +2845,9 @@
void Assembler::PushObject(const Object& object, Register pp) {
- if (CanLoadFromObjectPool(object)) {
+ if (Thread::CanLoadFromThread(object)) {
+ pushq(Address(THR, Thread::OffsetFromThread(object)));
+ } else if (CanLoadFromObjectPool(object)) {
LoadObject(TMP, object, pp);
pushq(TMP);
} else {
@@ -2886,7 +2857,9 @@
void Assembler::CompareObject(Register reg, const Object& object, Register pp) {
- if (CanLoadFromObjectPool(object)) {
+ if (Thread::CanLoadFromThread(object)) {
+ cmpq(reg, Address(THR, Thread::OffsetFromThread(object)));
+ } else if (CanLoadFromObjectPool(object)) {
const int32_t offset =
ObjectPool::element_offset(object_pool_wrapper_.FindObject(object));
cmpq(reg, Address(pp, offset-kHeapObjectTag));
@@ -2898,7 +2871,6 @@
intptr_t Assembler::FindImmediate(int64_t imm) {
- ASSERT(Isolate::Current() != Dart::vm_isolate());
return object_pool_wrapper_.FindImmediate(imm);
}
@@ -2907,9 +2879,7 @@
if (!allow_constant_pool()) {
return false;
}
- return !imm.is_int32() &&
- (pp != kNoRegister) &&
- (Isolate::Current() != Dart::vm_isolate());
+ return !imm.is_int32() && (pp != kNoRegister);
}
@@ -3090,8 +3060,8 @@
if (object != RDX) {
movq(RDX, object);
}
- StubCode* stub_code = Isolate::Current()->stub_code();
- Call(&stub_code->UpdateStoreBufferLabel(), PP);
+ movq(TMP, Address(THR, Thread::update_store_buffer_entry_point_offset()));
+ call(TMP);
if (value != RDX) popq(RDX);
Bind(&done);
}
@@ -3491,6 +3461,46 @@
}
+void Assembler::ComputeHeapStatsStateAddressForCid(intptr_t cid,
+ Address* state_address) {
+ ASSERT(cid < kNumPredefinedCids);
+ Register temp_reg = TMP;
+ Isolate* isolate = Isolate::Current();
+ ClassTable* class_table = isolate->class_table();
+ const uword class_heap_stats_table_address =
+ class_table->PredefinedClassHeapStatsTableAddress();
+ const uword class_offset = cid * sizeof(ClassHeapStats); // NOLINT
+ const uword state_offset = ClassHeapStats::state_offset();
+ movq(temp_reg, Immediate(class_heap_stats_table_address +
+ class_offset +
+ state_offset));
+ *state_address = Address(temp_reg, 0);
+}
+
+
+void Assembler::MaybeTraceAllocation(intptr_t cid,
+ Label* trace,
+ bool near_jump) {
+ ASSERT(cid > 0);
+ Address state_address(kNoRegister, 0);
+ if (cid < kNumPredefinedCids) {
+ ComputeHeapStatsStateAddressForCid(cid, &state_address);
+ } else {
+ Register temp_reg = TMP;
+ const uword class_offset = cid * sizeof(ClassHeapStats); // NOLINT
+ const uword state_offset = ClassHeapStats::state_offset();
+ // temp_reg gets address of class table pointer.
+ ClassTable* class_table = Isolate::Current()->class_table();
+ movq(temp_reg, Immediate(class_table->ClassStatsTableAddress()));
+ state_address = Address(temp_reg, class_offset + state_offset);
+ }
+ testb(state_address, Immediate(ClassHeapStats::TraceAllocationMask()));
+ // We are tracing for this class, jump to the trace label which will use
+ // the allocation stub.
+ j(NOT_ZERO, trace, near_jump);
+}
+
+
void Assembler::UpdateAllocationStats(intptr_t cid,
Heap::Space space) {
ASSERT(cid > 0);
@@ -3543,6 +3553,10 @@
Register pp) {
ASSERT(failure != NULL);
if (FLAG_inline_alloc) {
+ // If this allocation is traced, program will jump to failure path
+ // (i.e. the allocation stub) which will allocate the object and trace the
+ // allocation call site.
+ MaybeTraceAllocation(cls.id(), failure, near_jump);
Heap* heap = Isolate::Current()->heap();
const intptr_t instance_size = cls.instance_size();
Heap::Space space = heap->SpaceForAllocation(cls.id());
@@ -3580,6 +3594,10 @@
Register end_address) {
ASSERT(failure != NULL);
if (FLAG_inline_alloc) {
+ // If this allocation is traced, program will jump to failure path
+ // (i.e. the allocation stub) which will allocate the object and trace the
+ // allocation call site.
+ MaybeTraceAllocation(cid, failure, near_jump);
Isolate* isolate = Isolate::Current();
Heap* heap = isolate->heap();
Heap::Space space = heap->SpaceForAllocation(cid);
@@ -3763,9 +3781,10 @@
void Assembler::LoadClassById(Register result, Register class_id, Register pp) {
ASSERT(result != class_id);
- Isolate* isolate = Isolate::Current();
- LoadImmediate(result, Immediate(isolate->class_table()->TableAddress()), pp);
- movq(result, Address(result, 0));
+ LoadIsolate(result);
+ const intptr_t offset =
+ Isolate::class_table_offset() + ClassTable::table_offset();
+ movq(result, Address(result, offset));
movq(result, Address(result, class_id, TIMES_8, 0));
}
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index d964931..56cff9c 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -994,6 +994,12 @@
intptr_t instance_size,
Heap::Space space);
+ // If allocation tracing for |cid| is enabled, will jump to |trace| label,
+ // which will allocate in the runtime where tracing occurs.
+ void MaybeTraceAllocation(intptr_t cid,
+ Label* trace,
+ bool near_jump);
+
// Inlined allocation of an instance of class 'cls', code has no runtime
// calls. Jump to 'failure' if the instance cannot be allocated here.
// Allocated instance is returned in 'instance_reg'.
@@ -1067,7 +1073,7 @@
bool allow_constant_pool_;
intptr_t FindImmediate(int64_t imm);
- bool CanLoadFromObjectPool(const Object& object);
+ bool CanLoadFromObjectPool(const Object& object) const;
void LoadObjectHelper(Register dst,
const Object& obj,
Register pp,
@@ -1129,6 +1135,8 @@
Heap::Space space,
Address* count_address,
Address* size_address);
+ void ComputeHeapStatsStateAddressForCid(intptr_t cid,
+ Address* state_address);
DISALLOW_ALLOCATION();
DISALLOW_COPY_AND_ASSIGN(Assembler);
};
diff --git a/runtime/vm/base_isolate.h b/runtime/vm/base_isolate.h
index dccb44b..1e92a22 100644
--- a/runtime/vm/base_isolate.h
+++ b/runtime/vm/base_isolate.h
@@ -12,6 +12,7 @@
class HandleScope;
class StackResource;
+class Thread;
class Zone;
// A BaseIsolate contains just enough functionality to allocate
@@ -19,18 +20,6 @@
// constructor/destructor for performance.
class BaseIsolate {
public:
- StackResource* top_resource() const { return top_resource_; }
- void set_top_resource(StackResource* value) { top_resource_ = value; }
- static intptr_t top_resource_offset() {
- return OFFSET_OF(BaseIsolate, top_resource_);
- }
-
- // DEPRECATED: Use Thread::current_zone.
- Zone* current_zone() const {
- AssertCurrentThreadIsMutator();
- return current_zone_;
- }
- void set_current_zone(Zone* zone) { current_zone_ = zone; }
#if defined(DEBUG)
void AssertCurrentThreadIsMutator() const;
#else
@@ -115,8 +104,7 @@
protected:
BaseIsolate()
- : top_resource_(NULL),
- current_zone_(NULL),
+ : mutator_thread_(NULL),
#if defined(DEBUG)
top_handle_scope_(NULL),
no_handle_scope_depth_(0),
@@ -129,8 +117,7 @@
// Do not delete stack resources: top_resource_ and current_zone_.
}
- StackResource* top_resource_;
- Zone* current_zone_;
+ Thread* mutator_thread_;
#if defined(DEBUG)
HandleScope* top_handle_scope_;
int32_t no_handle_scope_depth_;
@@ -139,6 +126,9 @@
int32_t no_callback_scope_depth_;
private:
+ // During migration, some deprecated interfaces will default to using the
+ // mutator_thread_ (can't use accessor in Isolate due to circular deps).
+ friend class StackResource;
DISALLOW_COPY_AND_ASSIGN(BaseIsolate);
};
diff --git a/runtime/vm/bigint_test.cc b/runtime/vm/bigint_test.cc
index b4e9cdd..967e036 100644
--- a/runtime/vm/bigint_test.cc
+++ b/runtime/vm/bigint_test.cc
@@ -10,7 +10,7 @@
namespace dart {
static uword ZoneAllocator(intptr_t size) {
- Zone* zone = Isolate::Current()->current_zone();
+ Zone* zone = Thread::Current()->zone();
return zone->AllocUnsafe(size);
}
diff --git a/runtime/vm/bitmap.cc b/runtime/vm/bitmap.cc
index 8a2ebde..ae091ae 100644
--- a/runtime/vm/bitmap.cc
+++ b/runtime/vm/bitmap.cc
@@ -54,7 +54,7 @@
data_size_in_bytes_ =
Utils::RoundUp(byte_offset + 1, kIncrementSizeInBytes);
ASSERT(data_size_in_bytes_ > 0);
- data_ = Isolate::Current()->current_zone()->Alloc<uint8_t>(
+ data_ = Thread::Current()->zone()->Alloc<uint8_t>(
data_size_in_bytes_);
ASSERT(data_ != NULL);
memmove(data_, old_data, old_size);
diff --git a/runtime/vm/bitmap.h b/runtime/vm/bitmap.h
index 6d3376a3..507167e 100644
--- a/runtime/vm/bitmap.h
+++ b/runtime/vm/bitmap.h
@@ -24,7 +24,7 @@
BitmapBuilder()
: length_(0),
data_size_in_bytes_(kInitialSizeInBytes),
- data_(Isolate::Current()->current_zone()->Alloc<uint8_t>(
+ data_(Thread::Current()->zone()->Alloc<uint8_t>(
kInitialSizeInBytes)) {
memset(data_, 0, kInitialSizeInBytes);
}
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 6784ece..cef070c 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -380,6 +380,7 @@
V(LibraryPrefix_load, 1) \
V(LibraryPrefix_invalidateDependentCode, 1) \
V(LibraryPrefix_loadError, 1) \
+ V(LibraryPrefix_isLoaded, 1) \
V(UserTag_new, 2) \
V(UserTag_label, 1) \
V(UserTag_defaultTag, 0) \
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc
index 8ec699b..1966b21 100644
--- a/runtime/vm/class_table.cc
+++ b/runtime/vm/class_table.cc
@@ -82,6 +82,12 @@
}
+void ClassTable::TraceAllocationsFor(intptr_t cid, bool trace) {
+ ClassHeapStats* stats = PreliminaryStatsAt(cid);
+ stats->set_trace_allocation(trace);
+}
+
+
void ClassTable::Register(const Class& cls) {
intptr_t index = cls.id();
if (index != kIllegalCid) {
@@ -233,6 +239,7 @@
last_reset.Reset();
promoted_count = 0;
promoted_size = 0;
+ state_ = 0;
}
diff --git a/runtime/vm/class_table.h b/runtime/vm/class_table.h
index 4781e37..9a23630 100644
--- a/runtime/vm/class_table.h
+++ b/runtime/vm/class_table.h
@@ -6,6 +6,7 @@
#define VM_CLASS_TABLE_H_
#include "platform/assert.h"
+#include "vm/bitfield.h"
#include "vm/globals.h"
namespace dart {
@@ -102,6 +103,12 @@
return OFFSET_OF(ClassHeapStats, recent) +
OFFSET_OF(AllocStats<intptr_t>, old_size);
}
+ static intptr_t state_offset() {
+ return OFFSET_OF(ClassHeapStats, state_);
+ }
+ static intptr_t TraceAllocationMask() {
+ return (1 << kTraceAllocationBit);
+ }
void Initialize();
void ResetAtNewGC();
@@ -112,10 +119,25 @@
void PrintToJSONObject(const Class& cls, JSONObject* obj) const;
void Verify();
+ bool trace_allocation() const {
+ return TraceAllocationBit::decode(state_);
+ }
+
+ void set_trace_allocation(bool trace_allocation) {
+ state_ = TraceAllocationBit::update(trace_allocation, state_);
+ }
+
private:
+ enum StateBits {
+ kTraceAllocationBit = 0,
+ };
+
+ class TraceAllocationBit : public BitField<bool, kTraceAllocationBit, 1> {};
+
// Recent old at start of last new GC (used to compute promoted_*).
intptr_t old_pre_new_gc_count_;
intptr_t old_pre_new_gc_size_;
+ intptr_t state_;
};
@@ -156,6 +178,7 @@
void PrintToJSONObject(JSONObject* object);
+ // Used by the generated code.
static intptr_t table_offset() {
return OFFSET_OF(ClassTable, table_);
}
@@ -172,11 +195,6 @@
void UpdatePromoted();
// Used by the generated code.
- uword TableAddress() {
- return reinterpret_cast<uword>(&table_);
- }
-
- // Used by the generated code.
uword PredefinedClassHeapStatsTableAddress() {
return reinterpret_cast<uword>(predefined_class_heap_stats_table_);
}
@@ -194,6 +212,8 @@
// Deallocates table copies. Do not call during concurrent access to table.
void FreeOldTables();
+ void TraceAllocationsFor(intptr_t cid, bool trace);
+
private:
friend class MarkingVisitor;
friend class ScavengerVisitor;
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 0afc458..9e15de3 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -64,6 +64,7 @@
DEFINE_FLAG(bool, verify_compiler, false,
"Enable compiler verification assertions");
+DECLARE_FLAG(bool, load_deferred_eagerly);
DECLARE_FLAG(bool, trace_failed_optimization_attempts);
DECLARE_FLAG(bool, trace_inlining_intervals);
DECLARE_FLAG(bool, trace_irregexp);
@@ -71,6 +72,7 @@
bool Compiler::always_optimize_ = false;
+bool Compiler::allow_recompilation_ = true;
// TODO(zerny): Factor out unoptimizing/optimizing pipelines and remove
@@ -788,6 +790,7 @@
ASSERT(CodePatcher::CodeIsPatchable(code));
}
if (parsed_function->HasDeferredPrefixes()) {
+ ASSERT(!FLAG_load_deferred_eagerly);
ZoneGrowableArray<const LibraryPrefix*>* prefixes =
parsed_function->deferred_prefixes();
for (intptr_t i = 0; i < prefixes->length(); i++) {
@@ -972,6 +975,11 @@
const Function& function,
bool optimized,
intptr_t osr_id) {
+ // Check that we optimize if 'Compiler::always_optimize()' is set to true,
+ // except if the function is marked as not optimizable.
+ ASSERT(!function.IsOptimizable() ||
+ !Compiler::always_optimize() || optimized);
+ ASSERT(Compiler::allow_recompilation() || !function.HasCode());
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
Thread* const thread = Thread::Current();
diff --git a/runtime/vm/compiler.h b/runtime/vm/compiler.h
index d4099cc..e8052c7 100644
--- a/runtime/vm/compiler.h
+++ b/runtime/vm/compiler.h
@@ -90,8 +90,14 @@
static bool always_optimize() { return always_optimize_; }
static void set_always_optimize(bool value) { always_optimize_ = value; }
+ static bool allow_recompilation() { return allow_recompilation_; }
+ static void set_allow_recompilation(bool value) {
+ allow_recompilation_ = value;
+ }
+
private:
static bool always_optimize_;
+ static bool allow_recompilation_;
};
} // namespace dart
diff --git a/runtime/vm/coverage.cc b/runtime/vm/coverage.cc
index ee74763..cef0201 100644
--- a/runtime/vm/coverage.cc
+++ b/runtime/vm/coverage.cc
@@ -252,7 +252,7 @@
intptr_t pid = OS::ProcessId();
intptr_t len = OS::SNPrint(NULL, 0, format,
FLAG_coverage_dir, pid, isolate->main_port());
- char* filename = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
+ char* filename = Thread::Current()->zone()->Alloc<char>(len + 1);
OS::SNPrint(filename, len + 1, format,
FLAG_coverage_dir, pid, isolate->main_port());
void* file = (*file_open)(filename, true);
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 4fd93cb..7bb4fe3 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -95,7 +95,7 @@
Isolate::SetEntropySourceCallback(entropy_source);
OS::InitOnce();
VirtualMemory::InitOnce();
- Thread::InitOnce();
+ Thread::InitOnceBeforeIsolate();
Isolate::InitOnce();
PortMap::InitOnce();
FreeListElement::InitOnce();
@@ -120,7 +120,6 @@
ASSERT(vm_isolate_ == NULL);
ASSERT(Flags::Initialized());
const bool is_vm_isolate = true;
- Thread::EnsureInit();
// Setup default flags for the VM isolate.
Isolate::Flags vm_flags;
@@ -140,6 +139,7 @@
Object::InitOnce(vm_isolate_);
ArgumentsDescriptor::InitOnce();
StubCode::InitOnce();
+ Thread::InitOnceAfterObjectAndStubCode();
// Now that the needed stub has been generated, set the stack limit.
vm_isolate_->InitializeStackLimit();
if (vm_isolate_snapshot != NULL) {
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 17406ea..99e9a55 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -439,7 +439,9 @@
Dart_Handle Api::NewError(const char* format, ...) {
- Isolate* isolate = Isolate::Current();
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ Zone* zone = thread->zone();
DARTSCOPE(isolate);
CHECK_CALLBACK_STATE(isolate);
@@ -448,13 +450,13 @@
intptr_t len = OS::VSNPrint(NULL, 0, format, args);
va_end(args);
- char* buffer = isolate->current_zone()->Alloc<char>(len + 1);
+ char* buffer = zone->Alloc<char>(len + 1);
va_list args2;
va_start(args2, format);
OS::VSNPrint(buffer, (len + 1), format, args2);
va_end(args2);
- const String& message = String::Handle(isolate, String::New(buffer));
+ const String& message = String::Handle(zone, String::New(buffer));
return Api::NewHandle(isolate, ApiError::New(message));
}
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 0364ac8..6f761b6 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -404,7 +404,7 @@
func_class.IsTopLevel() ? "" : ".",
func_name.ToCString());
len++; // String terminator.
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, kFormat,
func_class.IsTopLevel() ? "" : class_name.ToCString(),
func_class.IsTopLevel() ? "" : ".",
@@ -1020,7 +1020,7 @@
const String& url = String::Handle(SourceUrl());
intptr_t line = LineNumber();
const char* func_name = Debugger::QualifiedFunctionName(function());
- return Isolate::Current()->current_zone()->
+ return Thread::Current()->zone()->
PrintToString("[ Frame pc(0x%" Px ") fp(0x%" Px ") sp(0x%" Px ")\n"
"\tfunction = %s\n"
"\turl = %s\n"
diff --git a/runtime/vm/debugger_test.cc b/runtime/vm/debugger_test.cc
index 9ccfce1..7393c67 100644
--- a/runtime/vm/debugger_test.cc
+++ b/runtime/vm/debugger_test.cc
@@ -13,14 +13,12 @@
// TODO(turnidge): This function obscures the line number of failing
// EXPECTs. Rework this.
static void ExpectSubstringF(const char* buff, const char* fmt, ...) {
- Isolate* isolate = Isolate::Current();
-
va_list args;
va_start(args, fmt);
intptr_t len = OS::VSNPrint(NULL, 0, fmt, args);
va_end(args);
- char* buffer = isolate->current_zone()->Alloc<char>(len + 1);
+ char* buffer = Thread::Current()->zone()->Alloc<char>(len + 1);
va_list args2;
va_start(args2, fmt);
OS::VSNPrint(buffer, (len + 1), fmt, args2);
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index 3260760..d6e2568 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -1191,7 +1191,7 @@
static uint8_t* ZoneReAlloc(uint8_t* ptr,
intptr_t old_size,
intptr_t new_size) {
- return Isolate::Current()->current_zone()->Realloc<uint8_t>(
+ return Thread::Current()->zone()->Realloc<uint8_t>(
ptr, old_size, new_size);
}
diff --git a/runtime/vm/disassembler_ia32.cc b/runtime/vm/disassembler_ia32.cc
index c63057b..852621b 100644
--- a/runtime/vm/disassembler_ia32.cc
+++ b/runtime/vm/disassembler_ia32.cc
@@ -481,7 +481,7 @@
const char* full_class_name = clazz.ToCString();
const char* format = "instance of %s";
intptr_t len = OS::SNPrint(NULL, 0, format, full_class_name) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, full_class_name);
return chars;
}
diff --git a/runtime/vm/disassembler_x64.cc b/runtime/vm/disassembler_x64.cc
index 0b87662..dba7e42 100644
--- a/runtime/vm/disassembler_x64.cc
+++ b/runtime/vm/disassembler_x64.cc
@@ -798,7 +798,7 @@
const char* full_class_name = clazz.ToCString();
const char* format = "instance of %s";
intptr_t len = OS::SNPrint(NULL, 0, format, full_class_name) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, full_class_name);
return chars;
}
diff --git a/runtime/vm/double_conversion.cc b/runtime/vm/double_conversion.cc
index 44233fe..cb3c047 100644
--- a/runtime/vm/double_conversion.cc
+++ b/runtime/vm/double_conversion.cc
@@ -86,7 +86,7 @@
kDoubleToStringCommonExponentChar,
0, 0, 0, 0); // Last four values are ignored in fixed mode.
- char* buffer = Isolate::Current()->current_zone()->Alloc<char>(kBufferSize);
+ char* buffer = Thread::Current()->zone()->Alloc<char>(kBufferSize);
buffer[kBufferSize - 1] = '\0';
double_conversion::StringBuilder builder(buffer, kBufferSize);
bool status = converter.ToFixed(d, fraction_digits, &builder);
@@ -119,7 +119,7 @@
kDoubleToStringCommonExponentChar,
0, 0, 0, 0); // Last four values are ignored in exponential mode.
- char* buffer = Isolate::Current()->current_zone()->Alloc<char>(kBufferSize);
+ char* buffer = Thread::Current()->zone()->Alloc<char>(kBufferSize);
buffer[kBufferSize - 1] = '\0';
double_conversion::StringBuilder builder(buffer, kBufferSize);
bool status = converter.ToExponential(d, fraction_digits, &builder);
@@ -158,7 +158,7 @@
kMaxLeadingPaddingZeroes,
kMaxTrailingPaddingZeroes);
- char* buffer = Isolate::Current()->current_zone()->Alloc<char>(kBufferSize);
+ char* buffer = Thread::Current()->zone()->Alloc<char>(kBufferSize);
buffer[kBufferSize - 1] = '\0';
double_conversion::StringBuilder builder(buffer, kBufferSize);
bool status = converter.ToPrecision(d, precision, &builder);
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index d493fa3..1efd006 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -81,10 +81,14 @@
FLAG_collect_code = false;
FLAG_load_deferred_eagerly = true;
FLAG_deoptimize_alot = false; // Used in some tests.
- FLAG_deoptimize_every = 0; // Used in some tests.
+ FLAG_deoptimize_every = 0; // Used in some tests.
FLAG_collect_code = false;
FLAG_guess_other_cid = true;
Compiler::set_always_optimize(true);
+ // Triggers assert if we try to recompile (e.g., because of deferred
+ // loading, deoptimization, ...). Noopt mode simulates behavior
+ // of precompiled code, therefore do not allow recompilation.
+ Compiler::set_allow_recompilation(false);
// TODO(srdjan): Enable CHA deoptimization when eager class finalization is
// implemented, either with precompilation or as a special pass.
FLAG_use_cha_deopt = false;
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index 17b2612..2ea19ee 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -177,7 +177,7 @@
const char* kFormat = "Deopt stub for id %d, reason: %s";
const intptr_t len = OS::SNPrint(NULL, 0, kFormat,
deopt_id(), DeoptReasonToCString(reason())) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, kFormat,
deopt_id(), DeoptReasonToCString(reason()));
return chars;
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index add12f5..f2572a1 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -5536,7 +5536,7 @@
if (def == NULL) {
return "*";
} else {
- return Isolate::Current()->current_zone()->PrintToString(
+ return Thread::Current()->zone()->PrintToString(
"v%" Pd, def->ssa_temp_index());
}
}
@@ -5549,34 +5549,34 @@
case kField: {
const char* field_name = String::Handle(field().name()).ToCString();
if (field().is_static()) {
- return Isolate::Current()->current_zone()->PrintToString(
+ return Thread::Current()->zone()->PrintToString(
"<%s>", field_name);
} else {
- return Isolate::Current()->current_zone()->PrintToString(
+ return Thread::Current()->zone()->PrintToString(
"<%s.%s>", DefinitionName(instance()), field_name);
}
}
case kVMField:
- return Isolate::Current()->current_zone()->PrintToString(
+ return Thread::Current()->zone()->PrintToString(
"<%s.@%" Pd ">",
DefinitionName(instance()),
offset_in_bytes());
case kIndexed:
- return Isolate::Current()->current_zone()->PrintToString(
+ return Thread::Current()->zone()->PrintToString(
"<%s[%s]>",
DefinitionName(instance()),
DefinitionName(index()));
case kConstantIndexed:
if (element_size() == kNoSize) {
- return Isolate::Current()->current_zone()->PrintToString(
+ return Thread::Current()->zone()->PrintToString(
"<%s[%" Pd "]>",
DefinitionName(instance()),
index_constant());
} else {
- return Isolate::Current()->current_zone()->PrintToString(
+ return Thread::Current()->zone()->PrintToString(
"<%s[%" Pd "|%" Pd "]>",
DefinitionName(instance()),
index_constant(),
diff --git a/runtime/vm/flow_graph_range_analysis.cc b/runtime/vm/flow_graph_range_analysis.cc
index 5fec37b..cd45479 100644
--- a/runtime/vm/flow_graph_range_analysis.cc
+++ b/runtime/vm/flow_graph_range_analysis.cc
@@ -1516,7 +1516,7 @@
char buffer[1024];
BufferFormatter f(buffer, sizeof(buffer));
PrettyPrintIndexBoundRecursively(&f, index_bound);
- return Isolate::Current()->current_zone()->MakeCopyOfString(buffer);
+ return Thread::Current()->zone()->MakeCopyOfString(buffer);
}
RangeAnalysis* range_analysis_;
diff --git a/runtime/vm/growable_array.h b/runtime/vm/growable_array.h
index ba6f807..045c3e5 100644
--- a/runtime/vm/growable_array.h
+++ b/runtime/vm/growable_array.h
@@ -161,10 +161,10 @@
explicit GrowableArray(intptr_t initial_capacity)
: BaseGrowableArray<T, ValueObject>(
initial_capacity,
- ASSERT_NOTNULL(Isolate::Current()->current_zone())) {}
+ ASSERT_NOTNULL(Thread::Current()->zone())) {}
GrowableArray()
: BaseGrowableArray<T, ValueObject>(
- ASSERT_NOTNULL(Isolate::Current()->current_zone())) {}
+ ASSERT_NOTNULL(Thread::Current()->zone())) {}
};
@@ -177,10 +177,10 @@
explicit ZoneGrowableArray(intptr_t initial_capacity)
: BaseGrowableArray<T, ZoneAllocated>(
initial_capacity,
- ASSERT_NOTNULL(Isolate::Current()->current_zone())) {}
+ ASSERT_NOTNULL(Thread::Current()->zone())) {}
ZoneGrowableArray()
: BaseGrowableArray<T, ZoneAllocated>(
- ASSERT_NOTNULL(Isolate::Current()->current_zone())) {}
+ ASSERT_NOTNULL(Thread::Current()->zone())) {}
};
diff --git a/runtime/vm/hash_map.h b/runtime/vm/hash_map.h
index 37fdc9b..5c20d04 100644
--- a/runtime/vm/hash_map.h
+++ b/runtime/vm/hash_map.h
@@ -106,9 +106,9 @@
array_size_(other.array_size_),
lists_size_(other.lists_size_),
count_(other.count_),
- array_(Isolate::Current()->current_zone()->
+ array_(Thread::Current()->zone()->
Alloc<HashMapListElement>(other.array_size_)),
- lists_(Isolate::Current()->current_zone()->
+ lists_(Thread::Current()->zone()->
Alloc<HashMapListElement>(other.lists_size_)),
free_list_head_(other.free_list_head_) {
memmove(array_, other.array_, array_size_ * sizeof(HashMapListElement));
@@ -131,7 +131,7 @@
}
HashMapListElement* new_array =
- Isolate::Current()->current_zone()->Alloc<HashMapListElement>(new_size);
+ Thread::Current()->zone()->Alloc<HashMapListElement>(new_size);
InitArray(new_array, new_size);
HashMapListElement* old_array = array_;
@@ -169,7 +169,7 @@
ASSERT(new_size > lists_size_);
HashMapListElement* new_lists =
- Isolate::Current()->current_zone()->
+ Thread::Current()->zone()->
Alloc<HashMapListElement>(new_size);
InitArray(new_lists, new_size);
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index 0d79149..6a5ce90 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -180,7 +180,7 @@
char buffer[1024];
BufferFormatter f(buffer, sizeof(buffer));
PrintTo(&f);
- return Isolate::Current()->current_zone()->MakeCopyOfString(buffer);
+ return Thread::Current()->zone()->MakeCopyOfString(buffer);
}
@@ -247,7 +247,7 @@
char buffer[1024];
BufferFormatter f(buffer, sizeof(buffer));
PrintTo(&f);
- return Isolate::Current()->current_zone()->MakeCopyOfString(buffer);
+ return Thread::Current()->zone()->MakeCopyOfString(buffer);
}
@@ -321,7 +321,7 @@
f->Print("#%s", cstr);
} else {
const intptr_t pos = new_line - cstr;
- char* buffer = Isolate::Current()->current_zone()->Alloc<char>(pos + 1);
+ char* buffer = Thread::Current()->zone()->Alloc<char>(pos + 1);
strncpy(buffer, cstr, pos);
buffer[pos] = '\0';
f->Print("#%s\\n...", buffer);
@@ -351,7 +351,7 @@
char buffer[256];
BufferFormatter f(buffer, sizeof(buffer));
range->PrintTo(&f);
- return Isolate::Current()->current_zone()->MakeCopyOfString(buffer);
+ return Thread::Current()->zone()->MakeCopyOfString(buffer);
}
@@ -382,7 +382,7 @@
char buffer[256];
BufferFormatter f(buffer, sizeof(buffer));
PrintTo(&f);
- return Isolate::Current()->current_zone()->MakeCopyOfString(buffer);
+ return Thread::Current()->zone()->MakeCopyOfString(buffer);
}
@@ -1210,7 +1210,7 @@
char buffer[1024];
BufferFormatter bf(buffer, 1024);
PrintTo(&bf);
- return Isolate::Current()->current_zone()->MakeCopyOfString(buffer);
+ return Thread::Current()->zone()->MakeCopyOfString(buffer);
}
} // namespace dart
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index 6238014..893352e 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -189,6 +189,7 @@
#define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_shift) \
Label fall_through; \
const intptr_t kArrayLengthStackOffset = 0 * kWordSize; \
+ __ MaybeTraceAllocation(cid, R2, &fall_through); \
__ ldr(R2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \
/* Check that length is a positive Smi. */ \
/* R2: requested array length argument. */ \
@@ -225,7 +226,7 @@
\
/* Successfully allocated the object(s), now update top to point to */ \
/* next object start and initialize the object. */ \
- __ LoadAllocationStatsAddress(R4, cid, space); \
+ __ LoadAllocationStatsAddress(R4, cid); \
__ LoadImmediate(R3, heap->TopAddress(space)); \
__ str(R1, Address(R3, 0)); \
__ AddImmediate(R0, kHeapObjectTag); \
@@ -1762,7 +1763,7 @@
Label* failure) {
const Register length_reg = R2;
Label fail;
-
+ __ MaybeTraceAllocation(kOneByteStringCid, R0, failure);
__ mov(R6, Operand(length_reg)); // Save the length register.
// TODO(koda): Protect against negative length and overflow here.
__ SmiUntag(length_reg);
@@ -1793,7 +1794,7 @@
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
- __ LoadAllocationStatsAddress(R4, cid, space);
+ __ LoadAllocationStatsAddress(R4, cid);
__ str(R1, Address(R3, 0));
__ AddImmediate(R0, kHeapObjectTag);
diff --git a/runtime/vm/intrinsifier_arm64.cc b/runtime/vm/intrinsifier_arm64.cc
index dd46bcc..8cbb1ba 100644
--- a/runtime/vm/intrinsifier_arm64.cc
+++ b/runtime/vm/intrinsifier_arm64.cc
@@ -198,6 +198,7 @@
#define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_shift) \
Label fall_through; \
const intptr_t kArrayLengthStackOffset = 0 * kWordSize; \
+ __ MaybeTraceAllocation(cid, R2, kNoPP, &fall_through); \
__ ldr(R2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \
/* Check that length is a positive Smi. */ \
/* R2: requested array length argument. */ \
@@ -1842,7 +1843,7 @@
Label* failure) {
const Register length_reg = R2;
Label fail;
-
+ __ MaybeTraceAllocation(kOneByteStringCid, R0, kNoPP, failure);
__ mov(R6, length_reg); // Save the length register.
// TODO(koda): Protect against negative length and overflow here.
__ SmiUntag(length_reg);
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index 2b15a71..f2bb256 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -186,6 +186,7 @@
#define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_factor) \
Label fall_through; \
const intptr_t kArrayLengthStackOffset = 1 * kWordSize; \
+ __ MaybeTraceAllocation(cid, EDI, &fall_through, false); \
__ movl(EDI, Address(ESP, kArrayLengthStackOffset)); /* Array length. */ \
/* Check that length is a positive Smi. */ \
/* EDI: requested array length argument. */ \
@@ -1868,6 +1869,7 @@
Label* ok,
Label* failure,
Register length_reg) {
+ __ MaybeTraceAllocation(kOneByteStringCid, EAX, failure, false);
if (length_reg != EDI) {
__ movl(EDI, length_reg);
}
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index e20cbd0..1cbb12f 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -179,6 +179,7 @@
#define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_shift) \
Label fall_through; \
const intptr_t kArrayLengthStackOffset = 0 * kWordSize; \
+ __ MaybeTraceAllocation(cid, T2, &fall_through); \
__ lw(T2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \
/* Check that length is a positive Smi. */ \
/* T2: requested array length argument. */ \
@@ -1882,7 +1883,7 @@
Label* ok,
Label* failure) {
const Register length_reg = T2;
-
+ __ MaybeTraceAllocation(kOneByteStringCid, V0, failure);
__ mov(T6, length_reg); // Save the length register.
// TODO(koda): Protect against negative length and overflow here.
__ SmiUntag(length_reg);
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index 96fe7bc..6ed3726 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -130,6 +130,7 @@
#define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_factor) \
Label fall_through; \
const intptr_t kArrayLengthStackOffset = 1 * kWordSize; \
+ __ MaybeTraceAllocation(cid, &fall_through, false); \
__ movq(RDI, Address(RSP, kArrayLengthStackOffset)); /* Array length. */ \
/* Check that length is a positive Smi. */ \
/* RDI: requested array length argument. */ \
@@ -1237,9 +1238,9 @@
Label* not_double_smi) {
__ movq(RAX, Address(RSP, + 1 * kWordSize));
__ testq(RAX, Immediate(kSmiTagMask));
- __ j(ZERO, is_smi, Assembler::kNearJump); // Jump if Smi.
+ __ j(ZERO, is_smi); // Jump if Smi.
__ CompareClassId(RAX, kDoubleCid);
- __ j(NOT_EQUAL, not_double_smi, Assembler::kNearJump);
+ __ j(NOT_EQUAL, not_double_smi);
// Fall through if double.
}
@@ -1319,7 +1320,7 @@
Isolate::Current()->object_store()->double_class());
__ TryAllocate(double_class,
&fall_through,
- Assembler::kNearJump,
+ Assembler::kFarJump,
RAX, // Result register.
kNoRegister); // Pool pointer might not be loaded.
__ movsd(FieldAddress(RAX, Double::value_offset()), XMM0);
@@ -1353,7 +1354,7 @@
// Only smis allowed.
__ movq(RAX, Address(RSP, + 1 * kWordSize));
__ testq(RAX, Immediate(kSmiTagMask));
- __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);
+ __ j(NOT_ZERO, &fall_through);
// Is Smi.
__ SmiUntag(RAX);
__ cvtsi2sdq(XMM1, RAX);
@@ -1364,7 +1365,7 @@
Isolate::Current()->object_store()->double_class());
__ TryAllocate(double_class,
&fall_through,
- Assembler::kNearJump,
+ Assembler::kFarJump,
RAX, // Result register.
kNoRegister); // Pool pointer might not be loaded.
__ movsd(FieldAddress(RAX, Double::value_offset()), XMM0);
@@ -1378,7 +1379,7 @@
Label fall_through;
__ movq(RAX, Address(RSP, +1 * kWordSize));
__ testq(RAX, Immediate(kSmiTagMask));
- __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);
+ __ j(NOT_ZERO, &fall_through);
// Is Smi.
__ SmiUntag(RAX);
__ cvtsi2sdq(XMM0, RAX);
@@ -1386,7 +1387,7 @@
Isolate::Current()->object_store()->double_class());
__ TryAllocate(double_class,
&fall_through,
- Assembler::kNearJump,
+ Assembler::kFarJump,
RAX, // Result register.
kNoRegister); // Pool pointer might not be loaded.
__ movsd(FieldAddress(RAX, Double::value_offset()), XMM0);
@@ -1460,7 +1461,7 @@
Isolate::Current()->object_store()->double_class());
__ TryAllocate(double_class,
&fall_through,
- Assembler::kNearJump,
+ Assembler::kFarJump,
RAX, // Result register.
kNoRegister); // Pool pointer might not be loaded.
__ movsd(FieldAddress(RAX, Double::value_offset()), XMM0);
@@ -1726,6 +1727,7 @@
Label* ok,
Label* failure,
Register length_reg) {
+ __ MaybeTraceAllocation(kOneByteStringCid, failure, false);
if (length_reg != RDI) {
__ movq(RDI, length_reg);
}
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 50df955..b247e56 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -36,6 +36,7 @@
#include "vm/symbols.h"
#include "vm/tags.h"
#include "vm/thread_interrupter.h"
+#include "vm/thread_registry.h"
#include "vm/timeline.h"
#include "vm/timer.h"
#include "vm/visitor.h"
@@ -622,9 +623,9 @@
object##_handle_(NULL),
Isolate::Isolate(const Dart_IsolateFlags& api_flags)
- : mutator_thread_(NULL),
- vm_tag_(0),
+ : vm_tag_(0),
store_buffer_(new StoreBuffer()),
+ thread_registry_(new ThreadRegistry()),
message_notify_callback_(NULL),
name_(NULL),
debugger_name_(NULL),
@@ -726,6 +727,7 @@
compiler_stats_ = NULL;
}
RemoveTimelineEventRecorder();
+ delete thread_registry_;
}
@@ -1532,9 +1534,6 @@
// Visit objects in per isolate stubs.
StubCode::VisitObjectPointers(visitor);
- // Visit objects in zones.
- current_zone()->VisitObjectPointers(visitor);
-
// Visit objects in isolate specific handles area.
reusable_handles_.VisitObjectPointers(visitor);
@@ -1571,6 +1570,9 @@
if (deopt_context() != NULL) {
deopt_context()->VisitObjectPointers(visitor);
}
+
+ // Visit objects in thread registry (e.g., handles in zones).
+ thread_registry()->VisitObjectPointers(visitor);
}
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 447afac..88c789d 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -78,6 +78,7 @@
class StackZone;
class StoreBuffer;
class StubCode;
+class ThreadRegistry;
class TypeArguments;
class TypeParameter;
class UserTag;
@@ -144,6 +145,8 @@
StoreBuffer* store_buffer() { return store_buffer_; }
+ ThreadRegistry* thread_registry() { return thread_registry_; }
+
ClassTable* class_table() { return &class_table_; }
static intptr_t class_table_offset() {
return OFFSET_OF(Isolate, class_table_);
@@ -208,10 +211,24 @@
return OFFSET_OF(Isolate, object_store_);
}
- uword top_exit_frame_info() const { return top_exit_frame_info_; }
- void set_top_exit_frame_info(uword value) { top_exit_frame_info_ = value; }
- static intptr_t top_exit_frame_info_offset() {
- return OFFSET_OF(Isolate, top_exit_frame_info_);
+ // DEPRECATED: Use Thread's methods instead. During migration, these default
+ // to using the mutator thread (which must also be the current thread).
+ StackResource* top_resource() const {
+ ASSERT(Thread::Current() == mutator_thread_);
+ return mutator_thread_->top_resource();
+ }
+ void set_top_resource(StackResource* value) {
+ ASSERT(Thread::Current() == mutator_thread_);
+ mutator_thread_->set_top_resource(value);
+ }
+ // DEPRECATED: Use Thread's methods instead. During migration, these default
+ // to using the mutator thread.
+ // NOTE: These are also used by the profiler.
+ uword top_exit_frame_info() const {
+ return mutator_thread_->top_exit_frame_info();
+ }
+ void set_top_exit_frame_info(uword value) {
+ mutator_thread_->set_top_exit_frame_info(value);
}
uword vm_tag() const {
@@ -719,6 +736,17 @@
// Handle service messages until we are told to resume execution.
void PauseEventHandler();
+ // DEPRECATED: Use Thread's methods instead. During migration, these default
+ // to using the mutator thread (which must also be the current thread).
+ Zone* current_zone() const {
+ ASSERT(Thread::Current() == mutator_thread_);
+ return mutator_thread_->zone();
+ }
+ void set_current_zone(Zone* zone) {
+ ASSERT(Thread::Current() == mutator_thread_);
+ mutator_thread_->set_zone(zone);
+ }
+
private:
explicit Isolate(const Dart_IsolateFlags& api_flags);
@@ -743,9 +771,9 @@
template<class T> T* AllocateReusableHandle();
- Thread* mutator_thread_;
uword vm_tag_;
StoreBuffer* store_buffer_;
+ ThreadRegistry* thread_registry_;
ClassTable class_table_;
MegamorphicCacheTable megamorphic_cache_table_;
Dart_MessageNotifyCallback message_notify_callback_;
diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc
index e716e50..5b10ab0 100644
--- a/runtime/vm/json_stream.cc
+++ b/runtime/vm/json_stream.cc
@@ -131,14 +131,12 @@
JSONObject data(&jsobj, "data");
PrintRequest(&data, this);
if (details_format != NULL) {
- Isolate* isolate = Isolate::Current();
-
va_list args;
va_start(args, details_format);
intptr_t len = OS::VSNPrint(NULL, 0, details_format, args);
va_end(args);
- char* buffer = isolate->current_zone()->Alloc<char>(len + 1);
+ char* buffer = Thread::Current()->zone()->Alloc<char>(len + 1);
va_list args2;
va_start(args2, details_format);
OS::VSNPrint(buffer, (len + 1), details_format, args2);
diff --git a/runtime/vm/locations.cc b/runtime/vm/locations.cc
index 69fc7cc..525855a 100644
--- a/runtime/vm/locations.cc
+++ b/runtime/vm/locations.cc
@@ -219,7 +219,7 @@
char buffer[1024];
BufferFormatter bf(buffer, 1024);
PrintTo(&bf);
- return Isolate::Current()->current_zone()->MakeCopyOfString(buffer);
+ return Thread::Current()->zone()->MakeCopyOfString(buffer);
}
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 907156f..18d86ff 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -66,13 +66,15 @@
DEFINE_FLAG(bool, use_lib_cache, true, "Use library name cache");
DEFINE_FLAG(bool, trace_field_guards, false, "Trace changes in field's cids.");
+DECLARE_FLAG(charp, coverage_dir);
+DECLARE_FLAG(bool, load_deferred_eagerly);
+DECLARE_FLAG(bool, show_invisible_frames);
DECLARE_FLAG(bool, trace_compiler);
DECLARE_FLAG(bool, trace_deoptimization);
DECLARE_FLAG(bool, trace_deoptimization_verbose);
-DECLARE_FLAG(bool, show_invisible_frames);
-DECLARE_FLAG(charp, coverage_dir);
DECLARE_FLAG(bool, write_protect_code);
+
static const char* kGetterPrefix = "get:";
static const intptr_t kGetterPrefixLength = strlen(kGetterPrefix);
static const char* kSetterPrefix = "set:";
@@ -627,6 +629,9 @@
// isolate.
Class::NewExternalTypedDataClass(kExternalTypedDataUint8ArrayCid);
+ // Needed for object pools of VM isolate stubs.
+ Class::NewTypedDataClass(kTypedDataInt8ArrayCid);
+
// Allocate and initialize the empty_array instance.
{
uword address = heap->Allocate(Array::InstanceSize(0), Heap::kOld);
@@ -1440,7 +1445,6 @@
// Finish the initialization by compiling the bootstrap scripts containing the
// base interfaces and the implementation of the internal classes.
- StubCode::InitBootstrapStubs(isolate);
const Error& error = Error::Handle(Bootstrap::LoadandCompileScripts());
if (!error.IsNull()) {
return error.raw();
@@ -1593,7 +1597,6 @@
Context::New(0, Heap::kOld));
object_store->set_empty_context(context);
- StubCode::InitBootstrapStubs(isolate);
#endif // defined(DART_NO_SNAPSHOT).
return Error::null();
@@ -2736,6 +2739,9 @@
set_state_bits(
TraceAllocationBit::update(trace_allocation, raw_ptr()->state_bits_));
if (changed) {
+ Isolate* isolate = Isolate::Current();
+ ClassTable* class_table = isolate->class_table();
+ class_table->TraceAllocationsFor(id(), trace_allocation);
DisableAllocationStub();
}
}
@@ -4168,7 +4174,7 @@
const char* library_name = lib.IsNull() ? "" : lib.ToCString();
const char* class_name = String::Handle(Name()).ToCString();
intptr_t len = OS::SNPrint(NULL, 0, format, library_name, class_name) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, library_name, class_name);
return chars;
}
@@ -4339,7 +4345,7 @@
const char* format = "unresolved class '%s'";
const char* cname = String::Handle(Name()).ToCString();
intptr_t len = OS::SNPrint(NULL, 0, format, cname) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, cname);
return chars;
}
@@ -5093,7 +5099,7 @@
const AbstractType& type_at = AbstractType::Handle(TypeAt(i));
const char* type_cstr = type_at.IsNull() ? "null" : type_at.ToCString();
intptr_t len = OS::SNPrint(NULL, 0, format, prev_cstr, type_cstr) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, prev_cstr, type_cstr);
prev_cstr = chars;
}
@@ -5106,7 +5112,7 @@
const Class& cls = Class::Handle(patched_class());
const char* cls_name = cls.ToCString();
intptr_t len = OS::SNPrint(NULL, 0, kFormat, cls_name) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, kFormat, cls_name);
return chars;
}
@@ -5921,7 +5927,7 @@
reserve_len +=
OS::SNPrint(NULL, 0, lib_class_format, library_name, class_name);
ASSERT(chars != NULL);
- *chars = Isolate::Current()->current_zone()->Alloc<char>(reserve_len + 1);
+ *chars = Thread::Current()->zone()->Alloc<char>(reserve_len + 1);
written = OS::SNPrint(
*chars, reserve_len + 1, lib_class_format, library_name, class_name);
} else {
@@ -6926,7 +6932,7 @@
const char* function_name = String::Handle(name()).ToCString();
intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name,
static_str, abstract_str, kind_str, const_str) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, kFormat, function_name,
static_str, abstract_str, kind_str, const_str);
return chars;
@@ -7318,7 +7324,7 @@
const char* cls_name = String::Handle(cls.Name()).ToCString();
intptr_t len =
OS::SNPrint(NULL, 0, kFormat, cls_name, field_name, kF0, kF1, kF2) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, kFormat, cls_name, field_name, kF0, kF1, kF2);
return chars;
}
@@ -7528,10 +7534,10 @@
is_final()) {
ASSERT(guarded_list_length() != kUnknownFixedLength);
if (guarded_list_length() == kNoFixedLength) {
- return Isolate::Current()->current_zone()->PrintToString(
+ return Thread::Current()->zone()->PrintToString(
"<%s [*]>", class_name);
} else {
- return Isolate::Current()->current_zone()->PrintToString(
+ return Thread::Current()->zone()->PrintToString(
"<%s [%" Pd " @%" Pd "]>",
class_name,
guarded_list_length(),
@@ -7539,7 +7545,7 @@
}
}
- return Isolate::Current()->current_zone()->PrintToString("<%s %s>",
+ return Thread::Current()->zone()->PrintToString("<%s %s>",
is_nullable() ? "nullable" : "not-nullable",
class_name);
}
@@ -10011,7 +10017,7 @@
const char* kFormat = "Library:'%s'";
const String& name = String::Handle(url());
intptr_t len = OS::SNPrint(NULL, 0, kFormat, name.ToCString()) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, kFormat, name.ToCString());
return chars;
}
@@ -10219,7 +10225,7 @@
RawObject* LibraryPrefix::LookupObject(const String& name) const {
- if (!is_loaded()) {
+ if (!is_loaded() && !FLAG_load_deferred_eagerly) {
return Object::null();
}
Array& imports = Array::Handle(this->imports());
@@ -10425,7 +10431,7 @@
const char* kFormat = "LibraryPrefix:'%s'";
const String& prefix = String::Handle(name());
intptr_t len = OS::SNPrint(NULL, 0, kFormat, prefix.ToCString()) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, kFormat, prefix.ToCString());
return chars;
}
@@ -10481,7 +10487,7 @@
const char* kFormat = "Namespace for library '%s'";
const Library& lib = Library::Handle(library());
intptr_t len = OS::SNPrint(NULL, 0, kFormat, lib.ToCString()) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, kFormat, lib.ToCString());
return chars;
}
@@ -10989,7 +10995,7 @@
}
}
// Allocate the buffer.
- char* buffer = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* buffer = Thread::Current()->zone()->Alloc<char>(len);
// Layout the fields in the buffer.
intptr_t index = 0;
Iterator iter(*this, RawPcDescriptors::kAnyKind);
@@ -11177,7 +11183,7 @@
} else {
const char* kFormat = "%#" Px ": ";
intptr_t fixed_length = OS::SNPrint(NULL, 0, kFormat, PcOffset()) + 1;
- Isolate* isolate = Isolate::Current();
+ Thread* thread = Thread::Current();
// Guard against integer overflow in the computation of alloc_size.
//
// TODO(kmillikin): We could just truncate the string if someone
@@ -11186,7 +11192,7 @@
FATAL1("Length() is unexpectedly large (%" Pd ")", Length());
}
intptr_t alloc_size = fixed_length + Length();
- char* chars = isolate->current_zone()->Alloc<char>(alloc_size);
+ char* chars = thread->zone()->Alloc<char>(alloc_size);
intptr_t index = OS::SNPrint(chars, alloc_size, kFormat, PcOffset());
for (intptr_t i = 0; i < Length(); i++) {
chars[index++] = IsObject(i) ? '1' : '0';
@@ -11301,7 +11307,7 @@
GetInfo(i, &info);
len += PrintVarInfo(NULL, 0, i, var_name, info);
}
- char* buffer = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
+ char* buffer = Thread::Current()->zone()->Alloc<char>(len + 1);
buffer[0] = '\0';
intptr_t num_chars = 0;
for (intptr_t i = 0; i < Length(); i++) {
@@ -11544,7 +11550,7 @@
}
}
// Allocate the buffer.
- char* buffer = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* buffer = Thread::Current()->zone()->Alloc<char>(len);
// Layout the fields in the buffer.
intptr_t num_chars = 0;
for (intptr_t i = 0; i < num_entries(); i++) {
@@ -11653,7 +11659,7 @@
}
// Allocate the buffer.
- char* buffer = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* buffer = Thread::Current()->zone()->Alloc<char>(len);
// Layout the fields in the buffer.
intptr_t index = 0;
@@ -11690,7 +11696,7 @@
const intptr_t num_checks = NumberOfChecks();
intptr_t len = OS::SNPrint(NULL, 0, kFormat, name.ToCString(),
num_args, num_checks) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, kFormat, name.ToCString(), num_args, num_checks);
return chars;
}
@@ -12953,7 +12959,7 @@
const char* Code::ToCString() const {
const char* kFormat = "Code entry:%p";
intptr_t len = OS::SNPrint(NULL, 0, kFormat, EntryPoint()) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, kFormat, EntryPoint());
return chars;
}
@@ -13272,7 +13278,7 @@
if (IsNull()) {
return "Context (Null)";
}
- Zone* zone = Isolate::Current()->current_zone();
+ Zone* zone = Thread::Current()->zone();
const Context& parent_ctx = Context::Handle(parent());
if (parent_ctx.IsNull()) {
return zone->PrintToString("Context@%p num_variables:% " Pd "",
@@ -13473,7 +13479,7 @@
intptr_t lvl = ContextLevelAt(i);
intptr_t len =
OS::SNPrint(NULL, 0, format, prev_cstr, cname, pos, lvl, idx) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, prev_cstr, cname, pos, lvl, idx);
prev_cstr = chars;
}
@@ -13930,7 +13936,8 @@
const char* UnhandledException::ToErrorCString() const {
- Isolate* isolate = Isolate::Current();
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
HANDLESCOPE(isolate);
Object& strtmp = Object::Handle();
const char* exc_str;
@@ -13956,7 +13963,7 @@
}
const char* format = "Unhandled exception:\n%s\n%s";
intptr_t len = OS::SNPrint(NULL, 0, format, exc_str, stack_str);
- char* chars = isolate->current_zone()->Alloc<char>(len);
+ char* chars = thread->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, exc_str, stack_str);
return chars;
}
@@ -14122,7 +14129,7 @@
const char* kFormat = "field: %s\n";
const intptr_t len =
OS::SNPrint(NULL, 0, kFormat, obj.ToCString()) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, kFormat, obj.ToCString());
*error_str = chars;
return false;
@@ -14456,7 +14463,7 @@
const String& type_name = String::Handle(type.UserVisibleName());
// Calculate the size of the string.
intptr_t len = OS::SNPrint(NULL, 0, kFormat, type_name.ToCString()) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, kFormat, type_name.ToCString());
return chars;
}
@@ -15612,7 +15619,7 @@
const char* format = "%sType: class '%s'";
const intptr_t len =
OS::SNPrint(NULL, 0, format, unresolved, class_name) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, unresolved, class_name);
return chars;
} else if (IsResolved() && IsFinalized() && IsRecursive()) {
@@ -15621,7 +15628,7 @@
const char* args_cstr = TypeArguments::Handle(arguments()).ToCString();
const intptr_t len =
OS::SNPrint(NULL, 0, format, raw(), hash, class_name, args_cstr) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, raw(), hash, class_name, args_cstr);
return chars;
} else {
@@ -15629,7 +15636,7 @@
const char* args_cstr = TypeArguments::Handle(arguments()).ToCString();
const intptr_t len =
OS::SNPrint(NULL, 0, format, unresolved, class_name, args_cstr) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, unresolved, class_name, args_cstr);
return chars;
}
@@ -15814,13 +15821,13 @@
const intptr_t hash = ref_type.Hash();
const intptr_t len =
OS::SNPrint(NULL, 0, format, type_cstr, ref_type.raw(), hash) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, type_cstr, ref_type.raw(), hash);
return chars;
} else {
const char* format = "TypeRef: %s<...>";
const intptr_t len = OS::SNPrint(NULL, 0, format, type_cstr) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, type_cstr);
return chars;
}
@@ -16056,7 +16063,7 @@
const char* bound_cstr = String::Handle(upper_bound.Name()).ToCString();
intptr_t len = OS::SNPrint(
NULL, 0, format, name_cstr, index(), cls_cstr, bound_cstr) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, name_cstr, index(), cls_cstr, bound_cstr);
return chars;
}
@@ -16271,7 +16278,7 @@
const char* cls_cstr = String::Handle(cls.Name()).ToCString();
intptr_t len = OS::SNPrint(
NULL, 0, format, type_cstr, bound_cstr, type_param_cstr, cls_cstr) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(
chars, len, format, type_cstr, bound_cstr, type_param_cstr, cls_cstr);
return chars;
@@ -16317,7 +16324,7 @@
MixinTypeAt(0)).Name()).ToCString();
intptr_t len = OS::SNPrint(
NULL, 0, format, super_type_cstr, first_mixin_type_cstr) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, super_type_cstr, first_mixin_type_cstr);
return chars;
}
@@ -16804,7 +16811,7 @@
const char* kFormat = "%ld";
// Calculate the size of the string.
intptr_t len = OS::SNPrint(NULL, 0, kFormat, Value()) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, kFormat, Value());
return chars;
}
@@ -16935,7 +16942,7 @@
const char* kFormat = "%lld";
// Calculate the size of the string.
intptr_t len = OS::SNPrint(NULL, 0, kFormat, value()) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, kFormat, value());
return chars;
}
@@ -17066,7 +17073,7 @@
return value() < 0 ? "-Infinity" : "Infinity";
}
const int kBufferSize = 128;
- char* buffer = Isolate::Current()->current_zone()->Alloc<char>(kBufferSize);
+ char* buffer = Thread::Current()->zone()->Alloc<char>(kBufferSize);
buffer[kBufferSize - 1] = '\0';
DoubleToCString(value(), buffer, kBufferSize);
return buffer;
@@ -17815,7 +17822,7 @@
static uword BigintAllocator(intptr_t size) {
- Zone* zone = Isolate::Current()->current_zone();
+ Zone* zone = Thread::Current()->zone();
return zone->AllocUnsafe(size);
}
@@ -18401,7 +18408,7 @@
RawString* String::EncodeIRI(const String& str) {
const intptr_t len = Utf8::Length(str);
- Zone* zone = Isolate::Current()->current_zone();
+ Zone* zone = Thread::Current()->zone();
uint8_t* utf8 = zone->Alloc<uint8_t>(len);
str.ToUTF8(utf8, len);
intptr_t num_escapes = 0;
@@ -18465,7 +18472,7 @@
}
intptr_t utf8_len = len - num_escapes;
ASSERT(utf8_len >= 0);
- Zone* zone = Isolate::Current()->current_zone();
+ Zone* zone = Thread::Current()->zone();
uint8_t* utf8 = zone->Alloc<uint8_t>(utf8_len);
{
intptr_t index = 0;
@@ -18508,7 +18515,7 @@
intptr_t len = OS::VSNPrint(NULL, 0, format, args_copy);
va_end(args_copy);
- Zone* zone = Isolate::Current()->current_zone();
+ Zone* zone = Thread::Current()->zone();
char* buffer = zone->Alloc<char>(len + 1);
OS::VSNPrint(buffer, (len + 1), format, args);
@@ -18618,7 +18625,7 @@
if (len == 0) {
return "";
}
- Zone* zone = Isolate::Current()->current_zone();
+ Zone* zone = Thread::Current()->zone();
uint8_t* result = zone->Alloc<uint8_t>(len + 1);
NoSafepointScope no_safepoint;
const uint8_t* original_str = OneByteString::CharAddr(*this, 0);
@@ -18636,7 +18643,7 @@
}
}
const intptr_t len = Utf8::Length(*this);
- Zone* zone = Isolate::Current()->current_zone();
+ Zone* zone = Thread::Current()->zone();
uint8_t* result = zone->Alloc<uint8_t>(len + 1);
ToUTF8(result, len);
result[len] = 0;
@@ -18840,7 +18847,7 @@
} else if (str.IsExternalOneByteString()) {
startChar = ExternalOneByteString::CharAddr(str, start);
} else {
- uint8_t* chars = Isolate::Current()->current_zone()->Alloc<uint8_t>(length);
+ uint8_t* chars = Thread::Current()->zone()->Alloc<uint8_t>(length);
const Scanner::CharAtFunc char_at = str.CharAtFunc();
for (intptr_t i = 0; i < length; i++) {
int32_t ch = char_at(str, start + i);
@@ -19665,7 +19672,7 @@
if (IsNull()) {
return IsImmutable() ? "_ImmutableList NULL" : "_List NULL";
}
- Zone* zone = Isolate::Current()->current_zone();
+ Zone* zone = Thread::Current()->zone();
const char* format = IsImmutable() ? "_ImmutableList len:%" Pd
: "_List len:%" Pd;
return zone->PrintToString(format, Length());
@@ -19782,7 +19789,7 @@
const char* kFormat = "element at index %" Pd ": %s\n";
const intptr_t len =
OS::SNPrint(NULL, 0, kFormat, i, obj.ToCString()) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, kFormat, i, obj.ToCString());
*error_str = chars;
return false;
@@ -19909,7 +19916,7 @@
}
const char* format = "Instance(length:%" Pd ") of '_GrowableList'";
intptr_t len = OS::SNPrint(NULL, 0, format, Length()) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, Length());
return chars;
}
@@ -20017,7 +20024,7 @@
const char* LinkedHashMap::ToCString() const {
- Zone* zone = Isolate::Current()->current_zone();
+ Zone* zone = Thread::Current()->zone();
return zone->PrintToString("_LinkedHashMap len:%" Pd, Length());
}
@@ -20140,7 +20147,7 @@
float _w = w();
// Calculate the size of the string.
intptr_t len = OS::SNPrint(NULL, 0, kFormat, _x, _y, _z, _w) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, kFormat, _x, _y, _z, _w);
return chars;
}
@@ -20245,7 +20252,7 @@
int32_t _w = w();
// Calculate the size of the string.
intptr_t len = OS::SNPrint(NULL, 0, kFormat, _x, _y, _z, _w) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, kFormat, _x, _y, _z, _w);
return chars;
}
@@ -20325,7 +20332,7 @@
double _y = y();
// Calculate the size of the string.
intptr_t len = OS::SNPrint(NULL, 0, kFormat, _x, _y) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, kFormat, _x, _y);
return chars;
}
@@ -20595,7 +20602,7 @@
const char* fun_desc = is_implicit_closure ? fun.ToCString() : "";
const char* format = "Closure: %s%s%s";
intptr_t len = OS::SNPrint(NULL, 0, format, fun_sig, from, fun_desc) + 1;
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, fun_sig, from, fun_desc);
return chars;
}
@@ -20711,7 +20718,7 @@
}
-static intptr_t PrintOneStacktrace(Isolate* isolate,
+static intptr_t PrintOneStacktrace(Zone* zone,
GrowableArray<char*>* frame_strings,
uword pc,
const Function& function,
@@ -20721,10 +20728,10 @@
const char* kFormatNoCol = "#%-6d %s (%s:%d)\n";
const char* kFormatNoLine = "#%-6d %s (%s)\n";
const intptr_t token_pos = code.GetTokenIndexOfPC(pc);
- const Script& script = Script::Handle(isolate, function.script());
+ const Script& script = Script::Handle(zone, function.script());
const String& function_name =
- String::Handle(isolate, function.QualifiedUserVisibleName());
- const String& url = String::Handle(isolate, script.url());
+ String::Handle(zone, function.QualifiedUserVisibleName());
+ const String& url = String::Handle(zone, script.url());
intptr_t line = -1;
intptr_t column = -1;
if (token_pos > 0) {
@@ -20740,7 +20747,7 @@
len = OS::SNPrint(NULL, 0, kFormatWithCol,
frame_index, function_name.ToCString(),
url.ToCString(), line, column);
- chars = isolate->current_zone()->Alloc<char>(len + 1);
+ chars = zone->Alloc<char>(len + 1);
OS::SNPrint(chars, (len + 1), kFormatWithCol,
frame_index,
function_name.ToCString(),
@@ -20749,7 +20756,7 @@
len = OS::SNPrint(NULL, 0, kFormatNoCol,
frame_index, function_name.ToCString(),
url.ToCString(), line);
- chars = isolate->current_zone()->Alloc<char>(len + 1);
+ chars = zone->Alloc<char>(len + 1);
OS::SNPrint(chars, (len + 1), kFormatNoCol,
frame_index, function_name.ToCString(),
url.ToCString(), line);
@@ -20757,7 +20764,7 @@
len = OS::SNPrint(NULL, 0, kFormatNoLine,
frame_index, function_name.ToCString(),
url.ToCString());
- chars = isolate->current_zone()->Alloc<char>(len + 1);
+ chars = zone->Alloc<char>(len + 1);
OS::SNPrint(chars, (len + 1), kFormatNoLine,
frame_index, function_name.ToCString(),
url.ToCString());
@@ -20769,7 +20776,7 @@
const char* Stacktrace::ToCStringInternal(intptr_t* frame_index,
intptr_t max_frames) const {
- Isolate* isolate = Isolate::Current();
+ Zone* zone = Thread::Current()->zone();
Function& function = Function::Handle();
Code& code = Code::Handle();
// Iterate through the stack frames and create C string description
@@ -20784,7 +20791,7 @@
(FunctionAtFrame(i + 1) != Function::null())) {
const char* kTruncated = "...\n...\n";
intptr_t truncated_len = strlen(kTruncated) + 1;
- char* chars = isolate->current_zone()->Alloc<char>(truncated_len);
+ char* chars = zone->Alloc<char>(truncated_len);
OS::SNPrint(chars, truncated_len, "%s", kTruncated);
frame_strings.Add(chars);
total_len += truncated_len;
@@ -20806,20 +20813,20 @@
ASSERT(code.EntryPoint() <= pc);
ASSERT(pc < (code.EntryPoint() + code.Size()));
total_len += PrintOneStacktrace(
- isolate, &frame_strings, pc, function, code, *frame_index);
+ zone, &frame_strings, pc, function, code, *frame_index);
(*frame_index)++; // To account for inlined frames.
}
}
} else {
total_len += PrintOneStacktrace(
- isolate, &frame_strings, pc, function, code, *frame_index);
+ zone, &frame_strings, pc, function, code, *frame_index);
(*frame_index)++;
}
}
}
// Now concatenate the frame descriptions into a single C string.
- char* chars = isolate->current_zone()->Alloc<char>(total_len + 1);
+ char* chars = zone->Alloc<char>(total_len + 1);
intptr_t index = 0;
for (intptr_t i = 0; i < frame_strings.length(); i++) {
index += OS::SNPrint((chars + index),
@@ -20932,7 +20939,7 @@
const String& str = String::Handle(pattern());
const char* format = "JSRegExp: pattern=%s flags=%s";
intptr_t len = OS::SNPrint(NULL, 0, format, str.ToCString(), Flags());
- char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len + 1);
OS::SNPrint(chars, (len + 1), format, str.ToCString(), Flags());
return chars;
}
diff --git a/runtime/vm/os_android.cc b/runtime/vm/os_android.cc
index 6606381..676e278 100644
--- a/runtime/vm/os_android.cc
+++ b/runtime/vm/os_android.cc
@@ -76,7 +76,7 @@
const char* format = "%" Px " %" Px " %s%s\n";
const char* marker = optimized ? "*" : "";
intptr_t len = OS::SNPrint(NULL, 0, format, base, size, marker, name);
- char* buffer = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
+ char* buffer = Thread::Current()->zone()->Alloc<char>(len + 1);
OS::SNPrint(buffer, len + 1, format, base, size, marker, name);
(*file_write)(buffer, len, out_file_);
}
@@ -109,7 +109,7 @@
// <name> for rest of the code (first instruction is prologue sequence).
const char* kFormat = "%s_%s";
intptr_t len = OS::SNPrint(NULL, 0, kFormat, name, "entry");
- char* pname = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
+ char* pname = Thread::Current()->zone()->Alloc<char>(len + 1);
OS::SNPrint(pname, (len + 1), kFormat, name, "entry");
DebugInfo::RegisterSection(pname, base, size);
DebugInfo::RegisterSection(name,
diff --git a/runtime/vm/os_linux.cc b/runtime/vm/os_linux.cc
index 430af48..288db46 100644
--- a/runtime/vm/os_linux.cc
+++ b/runtime/vm/os_linux.cc
@@ -82,7 +82,7 @@
const char* format = "%" Px " %" Px " %s%s\n";
const char* marker = optimized ? "*" : "";
intptr_t len = OS::SNPrint(NULL, 0, format, base, size, marker, name);
- char* buffer = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
+ char* buffer = Thread::Current()->zone()->Alloc<char>(len + 1);
OS::SNPrint(buffer, len + 1, format, base, size, marker, name);
{
MutexLocker ml(CodeObservers::mutex());
@@ -118,7 +118,7 @@
// <name> for rest of the code (first instruction is prologue sequence).
const char* kFormat = "%s_%s";
intptr_t len = OS::SNPrint(NULL, 0, kFormat, name, "entry");
- char* pname = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
+ char* pname = Thread::Current()->zone()->Alloc<char>(len + 1);
OS::SNPrint(pname, (len + 1), kFormat, name, "entry");
DebugInfo::RegisterSection(pname, base, size);
DebugInfo::RegisterSection(name,
@@ -248,7 +248,7 @@
const char* format = "%s%s";
const char* marker = optimized ? "*" : "";
intptr_t len = OS::SNPrint(NULL, 0, format, marker, name);
- char* buffer = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
+ char* buffer = Thread::Current()->zone()->Alloc<char>(len + 1);
OS::SNPrint(buffer, len + 1, format, marker, name);
return buffer;
}
diff --git a/runtime/vm/os_thread.h b/runtime/vm/os_thread.h
index 2dfd3f5..c3250d8 100644
--- a/runtime/vm/os_thread.h
+++ b/runtime/vm/os_thread.h
@@ -6,7 +6,7 @@
#define VM_OS_THREAD_H_
#include "platform/globals.h"
-#include "vm/allocation.h"
+#include "vm/globals.h"
// Declare the OS-specific types ahead of defining the generic classes.
#if defined(TARGET_OS_ANDROID)
@@ -24,7 +24,8 @@
namespace dart {
// Low-level operations on OS platform threads.
-class OSThread : AllStatic {
+// TODO(koda): Move to runtime/platform.
+class OSThread {
public:
static ThreadLocalKey kUnsetThreadLocalKey;
static ThreadId kInvalidThreadId;
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index a966b40..d3ccd42 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -38,15 +38,17 @@
namespace dart {
DEFINE_FLAG(bool, enable_debug_break, false, "Allow use of break \"message\".");
+DEFINE_FLAG(bool, enable_mirrors, true,
+ "Disable to make importing dart:mirrors an error.");
DEFINE_FLAG(bool, load_deferred_eagerly, false,
"Load deferred libraries eagerly.");
DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations.");
DEFINE_FLAG(bool, warn_mixin_typedef, true, "Warning on legacy mixin typedef.");
+
+DECLARE_FLAG(bool, lazy_dispatchers);
+DECLARE_FLAG(bool, load_deferred_eagerly);
DECLARE_FLAG(bool, throw_on_javascript_int_overflow);
DECLARE_FLAG(bool, warn_on_javascript_compatibility);
-DEFINE_FLAG(bool, enable_mirrors, true,
- "Disable to make importing dart:mirrors an error.");
-DECLARE_FLAG(bool, lazy_dispatchers);
// Quick access to the current isolate and zone.
#define I (isolate())
@@ -172,6 +174,9 @@
void ParsedFunction::AddDeferredPrefix(const LibraryPrefix& prefix) {
+ // 'deferred_prefixes_' are used to invalidate code, but no invalidation is
+ // needed if --load_deferred_eagerly.
+ ASSERT(!FLAG_load_deferred_eagerly);
ASSERT(prefix.is_deferred_load());
ASSERT(!prefix.is_loaded());
for (intptr_t i = 0; i < deferred_prefixes_->length(); i++) {
@@ -10038,8 +10043,19 @@
}
-AstNode* Parser::ThrowTypeError(intptr_t type_pos, const AbstractType& type) {
+// Call _throwNewIfNotLoaded if prefix is not NULL, otherwise call _throwNew.
+AstNode* Parser::ThrowTypeError(intptr_t type_pos, const AbstractType& type,
+ LibraryPrefix* prefix) {
ArgumentListNode* arguments = new(Z) ArgumentListNode(type_pos);
+
+ String& method_name = String::Handle(Z);
+ if (prefix == NULL) {
+ method_name = Library::PrivateCoreLibName(Symbols::ThrowNew()).raw();
+ } else {
+ arguments->Add(new(Z) LiteralNode(type_pos, *prefix));
+ method_name = Library::PrivateCoreLibName(
+ Symbols::ThrowNewIfNotLoaded()).raw();
+ }
// Location argument.
arguments->Add(new(Z) LiteralNode(
type_pos, Integer::ZoneHandle(Z, Integer::New(type_pos))));
@@ -10054,20 +10070,29 @@
ASSERT(!error.IsNull());
arguments->Add(new(Z) LiteralNode(type_pos, String::ZoneHandle(Z,
Symbols::New(error.ToErrorCString()))));
- return MakeStaticCall(Symbols::TypeError(),
- Library::PrivateCoreLibName(Symbols::ThrowNew()),
- arguments);
+ return MakeStaticCall(Symbols::TypeError(), method_name, arguments);
}
+// Call _throwNewIfNotLoaded if prefix is not NULL, otherwise call _throwNew.
AstNode* Parser::ThrowNoSuchMethodError(intptr_t call_pos,
const Class& cls,
const String& function_name,
ArgumentListNode* function_arguments,
InvocationMirror::Call im_call,
InvocationMirror::Type im_type,
- const Function* func) {
+ const Function* func,
+ const LibraryPrefix* prefix) {
ArgumentListNode* arguments = new(Z) ArgumentListNode(call_pos);
+
+ String& method_name = String::Handle(Z);
+ if (prefix == NULL) {
+ method_name = Library::PrivateCoreLibName(Symbols::ThrowNew()).raw();
+ } else {
+ arguments->Add(new(Z) LiteralNode(call_pos, *prefix));
+ method_name = Library::PrivateCoreLibName(
+ Symbols::ThrowNewIfNotLoaded()).raw();
+ }
// Object receiver.
// If the function is external and dynamic, pass the actual receiver,
// otherwise, pass a class literal of the unresolved method's owner.
@@ -10140,9 +10165,7 @@
}
arguments->Add(new(Z) LiteralNode(call_pos, array));
- return MakeStaticCall(Symbols::NoSuchMethodError(),
- Library::PrivateCoreLibName(Symbols::ThrowNew()),
- arguments);
+ return MakeStaticCall(Symbols::NoSuchMethodError(), method_name, arguments);
}
@@ -11816,7 +11839,7 @@
return NULL;
}
Object& obj = Object::Handle(Z);
- if (prefix.is_loaded()) {
+ if (prefix.is_loaded() || FLAG_load_deferred_eagerly) {
obj = prefix.LookupObject(ident);
} else {
// Remember that this function depends on an import prefix of an
@@ -11952,16 +11975,25 @@
}
-// Parses type = [ident "."] ident ["<" type { "," type } ">"], then resolve and
-// finalize it according to the given type finalization mode.
RawAbstractType* Parser::ParseType(
ClassFinalizer::FinalizationKind finalization,
bool allow_deferred_type,
bool consume_unresolved_prefix) {
+ LibraryPrefix& prefix = LibraryPrefix::Handle(Z);
+ return ParseType(finalization, allow_deferred_type,
+ consume_unresolved_prefix, &prefix);
+}
+
+// Parses type = [ident "."] ident ["<" type { "," type } ">"], then resolve and
+// finalize it according to the given type finalization mode. Returns prefix.
+RawAbstractType* Parser::ParseType(
+ ClassFinalizer::FinalizationKind finalization,
+ bool allow_deferred_type,
+ bool consume_unresolved_prefix,
+ LibraryPrefix* prefix) {
TRACE_PARSER("ParseType");
CheckToken(Token::kIDENT, "type name expected");
intptr_t ident_pos = TokenPos();
- LibraryPrefix& prefix = LibraryPrefix::Handle(Z);
String& type_name = String::Handle(Z);
if (finalization == ClassFinalizer::kIgnore) {
@@ -11972,7 +12004,7 @@
}
SkipQualIdent();
} else {
- prefix = ParsePrefix();
+ *prefix = ParsePrefix();
type_name = CurrentLiteral()->raw();
ConsumeToken();
@@ -11982,7 +12014,7 @@
// a period and another identifier, consume the qualified identifier
// and create a malformed type.
if (consume_unresolved_prefix &&
- prefix.IsNull() &&
+ prefix->IsNull() &&
(CurrentToken() == Token::kPERIOD) &&
(Token::IsIdentifier(LookaheadToken(1)))) {
if (!is_top_level_ && (current_block_ != NULL)) {
@@ -12009,7 +12041,7 @@
// If parsing inside a local scope, check whether the type name
// is shadowed by a local declaration.
if (!is_top_level_ &&
- (prefix.IsNull()) &&
+ (prefix->IsNull()) &&
ResolveIdentInLocalScope(ident_pos, type_name, NULL)) {
// The type is malformed. Skip over its type arguments.
ParseTypeArguments(ClassFinalizer::kIgnore);
@@ -12020,29 +12052,30 @@
"using '%s' in this context is invalid",
type_name.ToCString());
}
- if (!prefix.IsNull() && prefix.is_deferred_load()) {
+ if ((!FLAG_load_deferred_eagerly || !allow_deferred_type) &&
+ !prefix->IsNull() && prefix->is_deferred_load()) {
// If deferred prefixes are allowed but it is not yet loaded,
// remember that this function depends on the prefix.
- if (allow_deferred_type && !prefix.is_loaded()) {
+ if (allow_deferred_type && !prefix->is_loaded()) {
if (parsed_function() != NULL) {
- parsed_function()->AddDeferredPrefix(prefix);
+ parsed_function()->AddDeferredPrefix(*prefix);
}
}
// If the deferred prefixes are not allowed, or if the prefix is not yet
// loaded when finalization is requested, return a malformed type.
// Otherwise, handle resolution below, as needed.
if (!allow_deferred_type ||
- (!prefix.is_loaded()
+ (!prefix->is_loaded()
&& (finalization > ClassFinalizer::kResolveTypeParameters))) {
ParseTypeArguments(ClassFinalizer::kIgnore);
return ClassFinalizer::NewFinalizedMalformedType(
Error::Handle(Z), // No previous error.
script_,
ident_pos,
- !prefix.is_loaded()
+ !prefix->is_loaded() && allow_deferred_type
? "deferred type '%s.%s' is not yet loaded"
: "using deferred type '%s.%s' is invalid",
- String::Handle(Z, prefix.name()).ToCString(),
+ String::Handle(Z, prefix->name()).ToCString(),
type_name.ToCString());
}
}
@@ -12050,7 +12083,7 @@
Object& type_class = Object::Handle(Z);
// Leave type_class as null if type finalization mode is kIgnore.
if (finalization != ClassFinalizer::kIgnore) {
- type_class = UnresolvedClass::New(prefix, type_name, ident_pos);
+ type_class = UnresolvedClass::New(*prefix, type_name, ident_pos);
}
TypeArguments& type_arguments = TypeArguments::Handle(
Z, ParseTypeArguments(finalization));
@@ -12599,10 +12632,28 @@
const bool allow_deferred_type = !is_const;
const bool consume_unresolved_prefix = (LookaheadToken(3) == Token::kLT) ||
(LookaheadToken(3) == Token::kPERIOD);
+ LibraryPrefix& prefix = LibraryPrefix::ZoneHandle(Z);
AbstractType& type = AbstractType::Handle(Z,
ParseType(ClassFinalizer::kCanonicalizeWellFormed,
allow_deferred_type,
- consume_unresolved_prefix));
+ consume_unresolved_prefix,
+ &prefix));
+ if (FLAG_load_deferred_eagerly &&
+ !prefix.IsNull() && prefix.is_deferred_load() && !prefix.is_loaded()) {
+ // Add runtime check.
+ Type& malformed_type = Type::Handle(Z);
+ malformed_type = ClassFinalizer::NewFinalizedMalformedType(
+ Error::Handle(Z), // No previous error.
+ script_,
+ type_pos,
+ "deferred type '%s.%s' is not yet loaded",
+ String::Handle(Z, prefix.name()).ToCString(),
+ String::Handle(type.Name()).ToCString());
+ // Note: Adding a statement to current block is a hack, parsing an
+ // expression should have no side-effect.
+ current_block_->statements->Add(
+ ThrowTypeError(type_pos, malformed_type, &prefix));
+ }
// In case the type is malformed, throw a dynamic type error after finishing
// parsing the instance creation expression.
if (!type.IsMalformed() && (type.IsTypeParameter() || type.IsDynamicType())) {
@@ -13083,6 +13134,26 @@
call_type,
NULL); // No existing function.
}
+ } else if (FLAG_load_deferred_eagerly && prefix.is_deferred_load()) {
+ // primary != NULL.
+ String& qualified_name = String::ZoneHandle(Z, prefix.name());
+ qualified_name = String::Concat(qualified_name, Symbols::Dot());
+ qualified_name = String::Concat(qualified_name, ident);
+ qualified_name = Symbols::New(qualified_name);
+ InvocationMirror::Type call_type =
+ CurrentToken() == Token::kLPAREN ?
+ InvocationMirror::kMethod : InvocationMirror::kGetter;
+ // Note: Adding a statement to current block is a hack, parsing an
+ // espression should have no side-effect.
+ current_block_->statements->Add(ThrowNoSuchMethodError(
+ qual_ident_pos,
+ current_class(),
+ qualified_name,
+ NULL, // No arguments.
+ InvocationMirror::kTopLevel,
+ call_type,
+ NULL, // No existing function.
+ &prefix));
}
}
ASSERT(primary != NULL);
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index ba56ec9..9cab860 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -432,6 +432,12 @@
RawAbstractType* ParseType(ClassFinalizer::FinalizationKind finalization,
bool allow_deferred_type = false,
bool consume_unresolved_prefix = true);
+ RawAbstractType* ParseType(
+ ClassFinalizer::FinalizationKind finalization,
+ bool allow_deferred_type,
+ bool consume_unresolved_prefix,
+ LibraryPrefix* prefix);
+
void ParseTypeParameters(const Class& cls);
RawTypeArguments* ParseTypeArguments(
ClassFinalizer::FinalizationKind finalization);
@@ -763,14 +769,16 @@
ArgumentListNode* arguments);
String& Interpolate(const GrowableArray<AstNode*>& values);
AstNode* MakeAssertCall(intptr_t begin, intptr_t end);
- AstNode* ThrowTypeError(intptr_t type_pos, const AbstractType& type);
+ AstNode* ThrowTypeError(intptr_t type_pos, const AbstractType& type,
+ LibraryPrefix* prefix = NULL);
AstNode* ThrowNoSuchMethodError(intptr_t call_pos,
const Class& cls,
const String& function_name,
ArgumentListNode* function_arguments,
InvocationMirror::Call call,
InvocationMirror::Type type,
- const Function* func);
+ const Function* func,
+ const LibraryPrefix* prefix = NULL);
void SetupSavedTryContext(LocalVariable* saved_try_context);
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index 5e8940a..fac0bf4 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -252,7 +252,7 @@
name_ = NULL;
}
intptr_t len = strlen(name);
- name_ = Isolate::Current()->current_zone()->Alloc<const char>(len + 1);
+ name_ = Thread::Current()->zone()->Alloc<const char>(len + 1);
strncpy(const_cast<char*>(name_), name, len);
const_cast<char*>(name_)[len] = '\0';
}
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index 4f1ea87..b4b9080 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -103,7 +103,7 @@
static RawClass* GetClass(const Library& lib, const char* name) {
const Class& cls = Class::Handle(
- lib.LookupClass(String::Handle(Symbols::New(name))));
+ lib.LookupClassAllowPrivate(String::Handle(Symbols::New(name))));
EXPECT(!cls.IsNull()); // No ambiguity error expected.
return cls.raw();
}
@@ -313,4 +313,422 @@
}
}
+
+TEST_CASE(Profiler_IntrinsicAllocation) {
+ const char* kScript = "double foo(double a, double b) => a + b;";
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ Library& root_library = Library::Handle();
+ root_library ^= Api::UnwrapHandle(lib);
+ Isolate* isolate = Isolate::Current();
+
+ const Class& double_class =
+ Class::Handle(isolate->object_store()->double_class());
+ EXPECT(!double_class.IsNull());
+
+ Dart_Handle args[2] = { Dart_NewDouble(1.0), Dart_NewDouble(2.0), };
+
+ Dart_Handle result = Dart_Invoke(lib, NewString("foo"), 2, &args[0]);
+ EXPECT_VALID(result);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, double_class.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should have no allocation samples.
+ EXPECT_EQ(0, profile.sample_count());
+ }
+
+ double_class.SetTraceAllocation(true);
+ result = Dart_Invoke(lib, NewString("foo"), 2, &args[0]);
+ EXPECT_VALID(result);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, double_class.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should have one allocation sample.
+ EXPECT_EQ(1, profile.sample_count());
+ ProfileTrieWalker walker(&profile);
+
+ walker.Reset(Profile::kExclusiveCode);
+ EXPECT(walker.Down());
+ EXPECT_STREQ("_Double._add", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("_Double.+", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("foo", walker.CurrentName());
+ EXPECT(!walker.Down());
+ }
+
+ double_class.SetTraceAllocation(false);
+ result = Dart_Invoke(lib, NewString("foo"), 2, &args[0]);
+ EXPECT_VALID(result);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, double_class.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should still only have one allocation sample.
+ EXPECT_EQ(1, profile.sample_count());
+ }
+}
+
+
+TEST_CASE(Profiler_ArrayAllocation) {
+ const char* kScript =
+ "List foo() => new List(4);\n"
+ "List bar() => new List();\n";
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ Library& root_library = Library::Handle();
+ root_library ^= Api::UnwrapHandle(lib);
+ Isolate* isolate = Isolate::Current();
+
+ const Class& array_class =
+ Class::Handle(isolate->object_store()->array_class());
+ EXPECT(!array_class.IsNull());
+
+ Dart_Handle result = Dart_Invoke(lib, NewString("foo"), 0, NULL);
+ EXPECT_VALID(result);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, array_class.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should have no allocation samples.
+ EXPECT_EQ(0, profile.sample_count());
+ }
+
+ array_class.SetTraceAllocation(true);
+ result = Dart_Invoke(lib, NewString("foo"), 0, NULL);
+ EXPECT_VALID(result);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, array_class.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should have one allocation sample.
+ EXPECT_EQ(1, profile.sample_count());
+ ProfileTrieWalker walker(&profile);
+
+ walker.Reset(Profile::kExclusiveCode);
+ EXPECT(walker.Down());
+ EXPECT_STREQ("_List._List", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("List.List", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("foo", walker.CurrentName());
+ EXPECT(!walker.Down());
+ }
+
+ array_class.SetTraceAllocation(false);
+ result = Dart_Invoke(lib, NewString("foo"), 0, NULL);
+ EXPECT_VALID(result);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, array_class.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should still only have one allocation sample.
+ EXPECT_EQ(1, profile.sample_count());
+ }
+
+ // Clear the samples.
+ ProfilerService::ClearSamples();
+
+ // Compile bar (many List objects allocated).
+ result = Dart_Invoke(lib, NewString("bar"), 0, NULL);
+ EXPECT_VALID(result);
+
+ // Enable again.
+ array_class.SetTraceAllocation(true);
+
+ // Run bar.
+ result = Dart_Invoke(lib, NewString("bar"), 0, NULL);
+ EXPECT_VALID(result);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, array_class.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should still only have one allocation sample.
+ EXPECT_EQ(1, profile.sample_count());
+ ProfileTrieWalker walker(&profile);
+
+ walker.Reset(Profile::kExclusiveCode);
+ EXPECT(walker.Down());
+ EXPECT_STREQ("_List._List", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("_GrowableList._GrowableList", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("List.List", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("bar", walker.CurrentName());
+ EXPECT(!walker.Down());
+ }
+}
+
+
+TEST_CASE(Profiler_TypedArrayAllocation) {
+ const char* kScript =
+ "import 'dart:typed_data';\n"
+ "List foo() => new Float32List(4);\n";
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ Library& root_library = Library::Handle();
+ root_library ^= Api::UnwrapHandle(lib);
+ Isolate* isolate = Isolate::Current();
+
+ const Library& typed_data_library =
+ Library::Handle(isolate->object_store()->typed_data_library());
+
+ const Class& float32_list_class =
+ Class::Handle(GetClass(typed_data_library, "_Float32Array"));
+ EXPECT(!float32_list_class.IsNull());
+
+ Dart_Handle result = Dart_Invoke(lib, NewString("foo"), 0, NULL);
+ EXPECT_VALID(result);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, float32_list_class.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should have no allocation samples.
+ EXPECT_EQ(0, profile.sample_count());
+ }
+
+ float32_list_class.SetTraceAllocation(true);
+ result = Dart_Invoke(lib, NewString("foo"), 0, NULL);
+ EXPECT_VALID(result);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, float32_list_class.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should have one allocation sample.
+ EXPECT_EQ(1, profile.sample_count());
+ ProfileTrieWalker walker(&profile);
+
+ walker.Reset(Profile::kExclusiveCode);
+ EXPECT(walker.Down());
+ EXPECT_STREQ("_Float32Array._new", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("_Float32Array._Float32Array", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("Float32List.Float32List", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("foo", walker.CurrentName());
+ EXPECT(!walker.Down());
+ }
+
+ float32_list_class.SetTraceAllocation(false);
+ result = Dart_Invoke(lib, NewString("foo"), 0, NULL);
+ EXPECT_VALID(result);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, float32_list_class.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should still only have one allocation sample.
+ EXPECT_EQ(1, profile.sample_count());
+ }
+
+ float32_list_class.SetTraceAllocation(true);
+ result = Dart_Invoke(lib, NewString("foo"), 0, NULL);
+ EXPECT_VALID(result);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, float32_list_class.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should now have two allocation samples.
+ EXPECT_EQ(2, profile.sample_count());
+ }
+}
+
+
+TEST_CASE(Profiler_StringAllocation) {
+ const char* kScript = "String foo(String a, String b) => a + b;";
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ Library& root_library = Library::Handle();
+ root_library ^= Api::UnwrapHandle(lib);
+ Isolate* isolate = Isolate::Current();
+
+ const Class& one_byte_string_class =
+ Class::Handle(isolate->object_store()->one_byte_string_class());
+ EXPECT(!one_byte_string_class.IsNull());
+
+ Dart_Handle args[2] = { NewString("a"), NewString("b"), };
+
+ Dart_Handle result = Dart_Invoke(lib, NewString("foo"), 2, &args[0]);
+ EXPECT_VALID(result);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, one_byte_string_class.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should have no allocation samples.
+ EXPECT_EQ(0, profile.sample_count());
+ }
+
+ one_byte_string_class.SetTraceAllocation(true);
+ result = Dart_Invoke(lib, NewString("foo"), 2, &args[0]);
+ EXPECT_VALID(result);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, one_byte_string_class.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should still only have one allocation sample.
+ EXPECT_EQ(1, profile.sample_count());
+ ProfileTrieWalker walker(&profile);
+
+ walker.Reset(Profile::kExclusiveCode);
+ EXPECT(walker.Down());
+ EXPECT_STREQ("_StringBase.+", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("foo", walker.CurrentName());
+ EXPECT(!walker.Down());
+ }
+
+ one_byte_string_class.SetTraceAllocation(false);
+ result = Dart_Invoke(lib, NewString("foo"), 2, &args[0]);
+ EXPECT_VALID(result);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, one_byte_string_class.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should still only have one allocation sample.
+ EXPECT_EQ(1, profile.sample_count());
+ }
+
+ one_byte_string_class.SetTraceAllocation(true);
+ result = Dart_Invoke(lib, NewString("foo"), 2, &args[0]);
+ EXPECT_VALID(result);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, one_byte_string_class.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should now have two allocation samples.
+ EXPECT_EQ(2, profile.sample_count());
+ }
+}
+
+
+TEST_CASE(Profiler_StringInterpolation) {
+ const char* kScript = "String foo(String a, String b) => '$a | $b';";
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ Library& root_library = Library::Handle();
+ root_library ^= Api::UnwrapHandle(lib);
+ Isolate* isolate = Isolate::Current();
+
+ const Class& one_byte_string_class =
+ Class::Handle(isolate->object_store()->one_byte_string_class());
+ EXPECT(!one_byte_string_class.IsNull());
+
+ Dart_Handle args[2] = { NewString("a"), NewString("b"), };
+
+ Dart_Handle result = Dart_Invoke(lib, NewString("foo"), 2, &args[0]);
+ EXPECT_VALID(result);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, one_byte_string_class.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should have no allocation samples.
+ EXPECT_EQ(0, profile.sample_count());
+ }
+
+ one_byte_string_class.SetTraceAllocation(true);
+ result = Dart_Invoke(lib, NewString("foo"), 2, &args[0]);
+ EXPECT_VALID(result);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, one_byte_string_class.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should still only have one allocation sample.
+ EXPECT_EQ(1, profile.sample_count());
+ ProfileTrieWalker walker(&profile);
+
+ walker.Reset(Profile::kExclusiveCode);
+ EXPECT(walker.Down());
+ EXPECT_STREQ("_OneByteString._allocate", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("_OneByteString._concatAll", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("_StringBase._interpolate", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("foo", walker.CurrentName());
+ EXPECT(!walker.Down());
+ }
+
+ one_byte_string_class.SetTraceAllocation(false);
+ result = Dart_Invoke(lib, NewString("foo"), 2, &args[0]);
+ EXPECT_VALID(result);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, one_byte_string_class.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should still only have one allocation sample.
+ EXPECT_EQ(1, profile.sample_count());
+ }
+
+ one_byte_string_class.SetTraceAllocation(true);
+ result = Dart_Invoke(lib, NewString("foo"), 2, &args[0]);
+ EXPECT_VALID(result);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, one_byte_string_class.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should now have two allocation samples.
+ EXPECT_EQ(2, profile.sample_count());
+ }
+}
+
} // namespace dart
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index c40f71e..4cbc5dd 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -1168,7 +1168,7 @@
static RawObject* LookupHeapObject(Isolate* isolate,
const char* id_original,
ObjectIdRing::LookupResult* result) {
- char* id = isolate->current_zone()->MakeCopyOfString(id_original);
+ char* id = Thread::Current()->zone()->MakeCopyOfString(id_original);
// Parse the id by splitting at each '/'.
const int MAX_PARTS = 8;
@@ -1296,7 +1296,7 @@
MessageSnapshotReader reader(message->data(),
message->len(),
isolate,
- isolate->current_zone());
+ Thread::Current()->zone());
const Object& msg_obj = Object::Handle(reader.ReadObject());
msg_obj.PrintJSON(js);
return true;
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index 80d6ca3..8c16909 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -77,14 +77,12 @@
static RawArray* EvalF(Dart_Handle lib, const char* fmt, ...) {
- Isolate* isolate = Isolate::Current();
-
va_list args;
va_start(args, fmt);
intptr_t len = OS::VSNPrint(NULL, 0, fmt, args);
va_end(args);
- char* buffer = isolate->current_zone()->Alloc<char>(len + 1);
+ char* buffer = Thread::Current()->zone()->Alloc<char>(len + 1);
va_list args2;
va_start(args2, fmt);
OS::VSNPrint(buffer, (len + 1), fmt, args2);
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 5bcf2ff..1d6651e 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -2075,7 +2075,7 @@
UnmarkAll(); // Unmark objects now as we are about to print stuff.
intptr_t len = OS::SNPrint(NULL, 0, format,
clazz.ToCString(), errorFunc.ToCString()) + 1;
- char* chars = isolate()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, clazz.ToCString(), errorFunc.ToCString());
SetWriteException(Exceptions::kArgument, chars);
}
@@ -2104,7 +2104,7 @@
UnmarkAll(); // Unmark objects now as we are about to print stuff.
const Class& clazz = Class::Handle(isolate(), cls);
intptr_t len = OS::SNPrint(NULL, 0, format, clazz.ToCString()) + 1;
- char* chars = isolate()->current_zone()->Alloc<char>(len);
+ char* chars = Thread::Current()->zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, clazz.ToCString());
SetWriteException(Exceptions::kArgument, chars);
}
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 3933f3dc..b314513 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -61,7 +61,7 @@
static uint8_t* zone_allocator(
uint8_t* ptr, intptr_t old_size, intptr_t new_size) {
- Zone* zone = Isolate::Current()->current_zone();
+ Zone* zone = Thread::Current()->zone();
return zone->Realloc<uint8_t>(ptr, old_size, new_size);
}
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index a8ceedf..bf5a05d 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -30,7 +30,7 @@
const char* StackFrame::ToCString() const {
ASSERT(isolate_ == Isolate::Current());
- Zone* zone = Isolate::Current()->current_zone();
+ Zone* zone = Thread::Current()->zone();
if (IsDartFrame()) {
const Code& code = Code::Handle(LookupDartCode());
ASSERT(!code.IsNull());
diff --git a/runtime/vm/stack_frame_test.cc b/runtime/vm/stack_frame_test.cc
index fd72877..426ede7 100644
--- a/runtime/vm/stack_frame_test.cc
+++ b/runtime/vm/stack_frame_test.cc
@@ -97,13 +97,12 @@
}
const char* name = function.ToFullyQualifiedCString();
// Currently all unit tests are loaded as being part of dart:core-lib.
- Isolate* isolate = Isolate::Current();
String& url = String::Handle(String::New(TestCase::url()));
const Library& lib = Library::Handle(Library::LookupLibrary(url));
ASSERT(!lib.IsNull());
const char* lib_name = String::Handle(lib.url()).ToCString();
intptr_t length = OS::SNPrint(NULL, 0, "%s_%s", lib_name, expected_name);
- char* full_name = isolate->current_zone()->Alloc<char>(length + 1);
+ char* full_name = Thread::Current()->zone()->Alloc<char>(length + 1);
ASSERT(full_name != NULL);
OS::SNPrint(full_name, (length + 1), "%s_%s", lib_name, expected_name);
if (strcmp(full_name, name) != 0) {
diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc
index 38fd623..ad51097 100644
--- a/runtime/vm/stub_code.cc
+++ b/runtime/vm/stub_code.cc
@@ -58,30 +58,18 @@
}
-void StubCode::GenerateBootstrapStubsFor(Isolate* init) {
- // Generate initial stubs.
- Code& code = Code::Handle();
- BOOTSTRAP_STUB_CODE_LIST(STUB_CODE_GENERATE);
-}
-
-
void StubCode::GenerateStubsFor(Isolate* init) {
// Generate all the other stubs.
Code& code = Code::Handle();
- REST_STUB_CODE_LIST(STUB_CODE_GENERATE);
+ STUB_CODE_LIST(STUB_CODE_GENERATE);
}
#undef STUB_CODE_GENERATE
-void StubCode::InitBootstrapStubs(Isolate* isolate) {
+void StubCode::Init(Isolate* isolate) {
StubCode* stubs = new StubCode(isolate);
isolate->set_stub_code(stubs);
- stubs->GenerateBootstrapStubsFor(isolate);
-}
-
-
-void StubCode::Init(Isolate* isolate) {
isolate->stub_code()->GenerateStubsFor(isolate);
}
diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h
index 67e022d..cf25bba 100644
--- a/runtime/vm/stub_code.h
+++ b/runtime/vm/stub_code.h
@@ -22,32 +22,26 @@
#define VM_STUB_CODE_LIST(V) \
V(GetStackPointer) \
V(JumpToExceptionHandler) \
-
-// Is it permitted for the stubs above to refer to Object::null(), which is
-// allocated in the VM isolate and shared across all isolates.
-// However, in cases where a simple GC-safe placeholder is needed on the stack,
-// using Smi 0 instead of Object::null() is slightly more efficient, since a Smi
-// does not require relocation.
-
-// List of stubs created per isolate, these stubs could potentially contain
-// embedded objects and hence cannot be shared across isolates.
-// The initial stubs are needed for loading bootstrapping scripts and have to
-// be generated before Object::Init is called.
-#define BOOTSTRAP_STUB_CODE_LIST(V) \
+ V(UpdateStoreBuffer) \
V(PrintStopMessage) \
V(CallToRuntime) \
V(LazyCompile) \
-
-#define REST_STUB_CODE_LIST(V) \
V(CallBootstrapCFunction) \
V(CallNativeCFunction) \
V(FixCallersTarget) \
V(CallStaticFunction) \
+ V(OptimizeFunction) \
+ V(InvokeDartCode) \
+ V(DebugStepCheck) \
+ V(MegamorphicLookup) \
V(FixAllocationStubTarget) \
V(FixAllocateArrayStubTarget) \
- V(CallClosureNoSuchMethod) \
- V(AllocateContext) \
- V(UpdateStoreBuffer) \
+ V(Deoptimize) \
+ V(DeoptimizeLazy) \
+ V(UnoptimizedIdenticalWithNumberCheck) \
+ V(OptimizedIdenticalWithNumberCheck) \
+ V(ICCallBreakpoint) \
+ V(RuntimeCallBreakpoint) \
V(OneArgCheckInlineCache) \
V(TwoArgsCheckInlineCache) \
V(SmiAddInlineCache) \
@@ -60,23 +54,22 @@
V(ZeroArgsUnoptimizedStaticCall) \
V(OneArgUnoptimizedStaticCall) \
V(TwoArgsUnoptimizedStaticCall) \
- V(OptimizeFunction) \
- V(InvokeDartCode) \
V(Subtype1TestCache) \
V(Subtype2TestCache) \
V(Subtype3TestCache) \
- V(Deoptimize) \
- V(DeoptimizeLazy) \
- V(ICCallBreakpoint) \
- V(RuntimeCallBreakpoint) \
- V(UnoptimizedIdenticalWithNumberCheck) \
- V(OptimizedIdenticalWithNumberCheck) \
- V(DebugStepCheck) \
- V(MegamorphicLookup) \
+// Is it permitted for the stubs above to refer to Object::null(), which is
+// allocated in the VM isolate and shared across all isolates.
+// However, in cases where a simple GC-safe placeholder is needed on the stack,
+// using Smi 0 instead of Object::null() is slightly more efficient, since a Smi
+// does not require relocation.
+
+// List of stubs created per isolate, these stubs could potentially contain
+// embedded objects and hence cannot be shared across isolates.
#define STUB_CODE_LIST(V) \
- BOOTSTRAP_STUB_CODE_LIST(V) \
- REST_STUB_CODE_LIST(V)
+ V(CallClosureNoSuchMethod) \
+ V(AllocateContext) \
+
// class StubEntry is used to describe stub methods generated in dart to
// abstract out common code executed from generated dart code.
@@ -121,9 +114,6 @@
// Generate all stubs which are generated on a per isolate basis as they
// have embedded objects which are isolate specific.
- // Bootstrap stubs are needed before Object::Init to compile the bootstrap
- // scripts.
- static void InitBootstrapStubs(Isolate* isolate);
static void Init(Isolate* isolate);
static void VisitObjectPointers(ObjectPointerVisitor* visitor);
@@ -185,7 +175,6 @@
Assembler*, Register recv, Register cache, Register target);
private:
- void GenerateBootstrapStubsFor(Isolate* isolate);
void GenerateStubsFor(Isolate* isolate);
friend class MegamorphicCacheTable;
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 0d876d3..1337934 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -51,7 +51,7 @@
// Save exit frame information to enable stack walking as we are about
// to transition to Dart VM C++ code.
- __ StoreToOffset(kWord, FP, R9, Isolate::top_exit_frame_info_offset());
+ __ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset());
#if defined(DEBUG)
{ Label ok;
@@ -101,7 +101,7 @@
// Reset exit frame information in Isolate structure.
__ LoadImmediate(R2, 0);
- __ StoreToOffset(kWord, R2, R9, Isolate::top_exit_frame_info_offset());
+ __ StoreToOffset(kWord, R2, THR, Thread::top_exit_frame_info_offset());
__ LeaveStubFrame();
__ Ret();
@@ -146,7 +146,7 @@
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
- __ StoreToOffset(kWord, FP, R9, Isolate::top_exit_frame_info_offset());
+ __ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset());
#if defined(DEBUG)
{ Label ok;
@@ -209,7 +209,7 @@
// Reset exit frame information in Isolate structure.
__ LoadImmediate(R2, 0);
- __ StoreToOffset(kWord, R2, R9, Isolate::top_exit_frame_info_offset());
+ __ StoreToOffset(kWord, R2, THR, Thread::top_exit_frame_info_offset());
__ LeaveStubFrame();
__ Ret();
@@ -235,7 +235,7 @@
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
- __ StoreToOffset(kWord, FP, R9, Isolate::top_exit_frame_info_offset());
+ __ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset());
#if defined(DEBUG)
{ Label ok;
@@ -289,7 +289,7 @@
// Reset exit frame information in Isolate structure.
__ LoadImmediate(R2, 0);
- __ StoreToOffset(kWord, R2, R9, Isolate::top_exit_frame_info_offset());
+ __ StoreToOffset(kWord, R2, THR, Thread::top_exit_frame_info_offset());
__ LeaveStubFrame();
__ Ret();
@@ -632,15 +632,20 @@
uword* entry_patch_offset, uword* patch_code_pc_offset) {
*entry_patch_offset = assembler->CodeSize();
Label slow_case;
-
+ Isolate* isolate = Isolate::Current();
// Compute the size to be allocated, it is based on the array length
// and is computed as:
// RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)).
__ MoveRegister(R3, R2); // Array length.
-
+ const Class& cls = Class::Handle(isolate->object_store()->array_class());
+ ASSERT(!cls.IsNull());
// Check that length is a positive Smi.
__ tst(R3, Operand(kSmiTagMask));
- __ b(&slow_case, NE);
+ if (FLAG_use_slow_path || cls.trace_allocation()) {
+ __ b(&slow_case);
+ } else {
+ __ b(&slow_case, NE);
+ }
__ cmp(R3, Operand(0));
__ b(&slow_case, LT);
@@ -658,7 +663,6 @@
// R9: Allocation size.
- Isolate* isolate = Isolate::Current();
Heap* heap = isolate->heap();
const intptr_t cid = kArrayCid;
Heap::Space space = heap->SpaceForAllocation(cid);
@@ -678,7 +682,7 @@
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
- __ LoadAllocationStatsAddress(R3, cid, space);
+ __ LoadAllocationStatsAddress(R3, cid);
__ str(R7, Address(R6, 0));
__ add(R0, R0, Operand(kHeapObjectTag));
@@ -795,11 +799,11 @@
// 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.
- __ LoadFromOffset(kWord, R5, R9, Isolate::top_exit_frame_info_offset());
- __ LoadFromOffset(kWord, R4, R9, Isolate::top_resource_offset());
+ __ LoadFromOffset(kWord, R5, THR, Thread::top_exit_frame_info_offset());
+ __ LoadFromOffset(kWord, R4, THR, Thread::top_resource_offset());
__ LoadImmediate(R6, 0);
- __ StoreToOffset(kWord, R6, R9, Isolate::top_resource_offset());
- __ StoreToOffset(kWord, R6, R9, Isolate::top_exit_frame_info_offset());
+ __ StoreToOffset(kWord, R6, THR, Thread::top_resource_offset());
+ __ StoreToOffset(kWord, R6, THR, Thread::top_exit_frame_info_offset());
// kExitLinkSlotFromEntryFp must be kept in sync with the code below.
__ Push(R4);
@@ -842,9 +846,9 @@
// 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);
- __ StoreToOffset(kWord, R5, R9, Isolate::top_exit_frame_info_offset());
+ __ StoreToOffset(kWord, R5, THR, Thread::top_exit_frame_info_offset());
__ Pop(R5);
- __ StoreToOffset(kWord, R5, R9, Isolate::top_resource_offset());
+ __ StoreToOffset(kWord, R5, THR, Thread::top_resource_offset());
// Restore the current VMTag from the stack.
__ Pop(R4);
@@ -913,7 +917,7 @@
// R2: object size.
// R3: next object start.
// R5: top address.
- __ LoadAllocationStatsAddress(R6, cid, space);
+ __ LoadAllocationStatsAddress(R6, cid);
__ str(R3, Address(R5, 0));
__ add(R0, R0, Operand(kHeapObjectTag));
@@ -1108,7 +1112,7 @@
// Load the address of the allocation stats table. We split up the load
// and the increment so that the dependent load is not too nearby.
- __ LoadAllocationStatsAddress(R5, cls.id(), space);
+ __ LoadAllocationStatsAddress(R5, cls.id());
// R0: new object start.
// R1: next object start.
@@ -1922,7 +1926,7 @@
__ StoreToOffset(kWord, R2, R3, Isolate::vm_tag_offset());
// Clear top exit frame.
__ LoadImmediate(R2, 0);
- __ StoreToOffset(kWord, R2, R3, Isolate::top_exit_frame_info_offset());
+ __ StoreToOffset(kWord, R2, THR, Thread::top_exit_frame_info_offset());
__ bx(LR); // Jump to the exception handler code.
}
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index 10e2411..672a82b 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -48,11 +48,11 @@
__ EnterStubFrame();
COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R28)) != 0);
- __ LoadIsolate(R28, kNoPP);
+ __ LoadIsolate(R28);
// Save exit frame information to enable stack walking as we are about
// to transition to Dart VM C++ code.
- __ StoreToOffset(FP, R28, Isolate::top_exit_frame_info_offset(), kNoPP);
+ __ StoreToOffset(FP, THR, Thread::top_exit_frame_info_offset(), kNoPP);
#if defined(DEBUG)
{ Label ok;
@@ -121,7 +121,7 @@
__ StoreToOffset(R2, R28, Isolate::vm_tag_offset(), kNoPP);
// Reset exit frame information in Isolate structure.
- __ StoreToOffset(ZR, R28, Isolate::top_exit_frame_info_offset(), kNoPP);
+ __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset(), kNoPP);
__ LeaveStubFrame();
__ ret();
@@ -148,11 +148,11 @@
__ EnterStubFrame();
COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R28)) != 0);
- __ LoadIsolate(R28, kNoPP);
+ __ LoadIsolate(R28);
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
- __ StoreToOffset(FP, R28, Isolate::top_exit_frame_info_offset(), kNoPP);
+ __ StoreToOffset(FP, THR, Thread::top_exit_frame_info_offset(), kNoPP);
#if defined(DEBUG)
{ Label ok;
@@ -228,7 +228,7 @@
__ StoreToOffset(R2, R28, Isolate::vm_tag_offset(), kNoPP);
// Reset exit frame information in Isolate structure.
- __ StoreToOffset(ZR, R28, Isolate::top_exit_frame_info_offset(), kNoPP);
+ __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset(), kNoPP);
__ LeaveStubFrame();
__ ret();
@@ -250,11 +250,11 @@
__ EnterStubFrame();
COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R28)) != 0);
- __ LoadIsolate(R28, kNoPP);
+ __ LoadIsolate(R28);
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
- __ StoreToOffset(FP, R28, Isolate::top_exit_frame_info_offset(), kNoPP);
+ __ StoreToOffset(FP, THR, Thread::top_exit_frame_info_offset(), kNoPP);
#if defined(DEBUG)
{ Label ok;
@@ -321,7 +321,7 @@
__ StoreToOffset(R2, R28, Isolate::vm_tag_offset(), kNoPP);
// Reset exit frame information in Isolate structure.
- __ StoreToOffset(ZR, R28, Isolate::top_exit_frame_info_offset(), kNoPP);
+ __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset(), kNoPP);
__ LeaveStubFrame();
__ ret();
@@ -661,12 +661,15 @@
uword* entry_patch_offset, uword* patch_code_pc_offset) {
*entry_patch_offset = assembler->CodeSize();
Label slow_case;
+ Isolate* isolate = Isolate::Current();
+ const Class& cls = Class::Handle(isolate->object_store()->array_class());
+ ASSERT(!cls.IsNull());
// Compute the size to be allocated, it is based on the array length
// and is computed as:
// RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)).
// Assert that length is a Smi.
__ tsti(R2, Immediate(kSmiTagMask));
- if (FLAG_use_slow_path) {
+ if (FLAG_use_slow_path || cls.trace_allocation()) {
__ b(&slow_case);
} else {
__ b(&slow_case, NE);
@@ -674,7 +677,6 @@
__ cmp(R2, Operand(0));
__ b(&slow_case, LT);
- Isolate* isolate = Isolate::Current();
Heap* heap = isolate->heap();
const intptr_t cid = kArrayCid;
Heap::Space space = heap->SpaceForAllocation(cid);
@@ -839,7 +841,7 @@
__ mov(THR, R3);
}
// Load Isolate pointer into temporary register R5.
- __ LoadIsolate(R5, PP);
+ __ LoadIsolate(R5);
// Save the current VMTag on the stack.
__ LoadFromOffset(R4, R5, Isolate::vm_tag_offset(), PP);
@@ -851,11 +853,11 @@
// 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.
- __ LoadFromOffset(R6, R5, Isolate::top_resource_offset(), PP);
- __ StoreToOffset(ZR, R5, Isolate::top_resource_offset(), PP);
+ __ LoadFromOffset(R6, THR, Thread::top_resource_offset(), PP);
+ __ StoreToOffset(ZR, THR, Thread::top_resource_offset(), PP);
__ Push(R6);
- __ LoadFromOffset(R6, R5, Isolate::top_exit_frame_info_offset(), PP);
- __ StoreToOffset(ZR, R5, Isolate::top_exit_frame_info_offset(), PP);
+ __ LoadFromOffset(R6, THR, Thread::top_exit_frame_info_offset(), PP);
+ __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset(), PP);
// kExitLinkSlotFromEntryFp must be kept in sync with the code below.
ASSERT(kExitLinkSlotFromEntryFp == -21);
__ Push(R6);
@@ -896,14 +898,14 @@
// Get rid of arguments pushed on the stack.
__ AddImmediate(SP, FP, kExitLinkSlotFromEntryFp * kWordSize, PP);
- __ LoadIsolate(R28, PP);
+ __ 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);
- __ StoreToOffset(R6, R28, Isolate::top_exit_frame_info_offset(), PP);
+ __ StoreToOffset(R6, THR, Thread::top_exit_frame_info_offset(), PP);
__ Pop(R6);
- __ StoreToOffset(R6, R28, Isolate::top_resource_offset(), PP);
+ __ StoreToOffset(R6, THR, Thread::top_resource_offset(), PP);
// Restore the current VMTag from the stack.
__ Pop(R4);
@@ -1431,7 +1433,7 @@
Label stepping, done_stepping;
if (FLAG_support_debugger && !optimized) {
__ Comment("Check single stepping");
- __ LoadIsolate(R6, kNoPP);
+ __ LoadIsolate(R6);
__ LoadFromOffset(
R6, R6, Isolate::single_step_offset(), kNoPP, kUnsignedByte);
__ CompareRegisters(R6, ZR);
@@ -1725,7 +1727,7 @@
// Check single stepping.
Label stepping, done_stepping;
if (FLAG_support_debugger) {
- __ LoadIsolate(R6, kNoPP);
+ __ LoadIsolate(R6);
__ LoadFromOffset(
R6, R6, Isolate::single_step_offset(), kNoPP, kUnsignedByte);
__ CompareImmediate(R6, 0, kNoPP);
@@ -1841,7 +1843,7 @@
Assembler* assembler) {
// Check single stepping.
Label stepping, done_stepping;
- __ LoadIsolate(R1, kNoPP);
+ __ LoadIsolate(R1);
__ LoadFromOffset(
R1, R1, Isolate::single_step_offset(), kNoPP, kUnsignedByte);
__ CompareImmediate(R1, 0, kNoPP);
@@ -1989,12 +1991,12 @@
__ mov(R0, R3); // Exception object.
__ mov(R1, R4); // StackTrace object.
__ mov(THR, R5);
- __ LoadIsolate(R5, kNoPP);
+ __ LoadIsolate(R5);
// Set the tag.
__ LoadImmediate(R2, VMTag::kDartTagId, kNoPP);
__ StoreToOffset(R2, R5, Isolate::vm_tag_offset(), kNoPP);
// Clear top exit frame.
- __ StoreToOffset(ZR, R5, Isolate::top_exit_frame_info_offset(), kNoPP);
+ __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset(), kNoPP);
__ ret(); // Jump to the exception handler code.
}
@@ -2096,7 +2098,7 @@
// Check single stepping.
Label stepping, done_stepping;
if (FLAG_support_debugger) {
- __ LoadIsolate(R1, kNoPP);
+ __ LoadIsolate(R1);
__ LoadFromOffset(
R1, R1, Isolate::single_step_offset(), kNoPP, kUnsignedByte);
__ CompareImmediate(R1, 0, kNoPP);
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index 95ba111..3addb33 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -53,7 +53,7 @@
// Save exit frame information to enable stack walking as we are about
// to transition to Dart VM C++ code.
- __ movl(Address(EDI, Isolate::top_exit_frame_info_offset()), EBP);
+ __ movl(Address(THR, Thread::top_exit_frame_info_offset()), EBP);
#if defined(DEBUG)
{ Label ok;
@@ -91,7 +91,7 @@
Immediate(VMTag::kDartTagId));
// Reset exit frame information in Isolate structure.
- __ movl(Address(EDI, Isolate::top_exit_frame_info_offset()), Immediate(0));
+ __ movl(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
__ LeaveFrame();
__ ret();
@@ -143,7 +143,7 @@
// Save exit frame information to enable stack walking as we are about
// to transition to dart VM code.
- __ movl(Address(EDI, Isolate::top_exit_frame_info_offset()), EBP);
+ __ movl(Address(THR, Thread::top_exit_frame_info_offset()), EBP);
#if defined(DEBUG)
{ Label ok;
@@ -185,7 +185,7 @@
Immediate(VMTag::kDartTagId));
// Reset exit frame information in Isolate structure.
- __ movl(Address(EDI, Isolate::top_exit_frame_info_offset()), Immediate(0));
+ __ movl(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
__ LeaveFrame();
__ ret();
@@ -216,7 +216,7 @@
// Save exit frame information to enable stack walking as we are about
// to transition to dart VM code.
- __ movl(Address(EDI, Isolate::top_exit_frame_info_offset()), EBP);
+ __ movl(Address(THR, Thread::top_exit_frame_info_offset()), EBP);
#if defined(DEBUG)
{ Label ok;
@@ -255,7 +255,7 @@
Immediate(VMTag::kDartTagId));
// Reset exit frame information in Isolate structure.
- __ movl(Address(EDI, Isolate::top_exit_frame_info_offset()), Immediate(0));
+ __ movl(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
__ LeaveFrame();
__ ret();
@@ -589,12 +589,16 @@
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ Isolate* isolate = Isolate::Current();
+ const Class& cls = Class::Handle(isolate->object_store()->array_class());
+ ASSERT(!cls.IsNull());
// Compute the size to be allocated, it is based on the array length
// and is computed as:
// RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)).
// Assert that length is a Smi.
__ testl(EDX, Immediate(kSmiTagMask));
- if (FLAG_use_slow_path) {
+
+ if (FLAG_use_slow_path || cls.trace_allocation()) {
__ jmp(&slow_case);
} else {
__ j(NOT_ZERO, &slow_case);
@@ -617,7 +621,6 @@
// EDX: array length as Smi.
// EDI: allocation size.
- Isolate* isolate = Isolate::Current();
Heap* heap = isolate->heap();
const intptr_t cid = kArrayCid;
Heap::Space space = heap->SpaceForAllocation(cid);
@@ -757,15 +760,15 @@
// 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.
- __ movl(EDX, Address(EDI, Isolate::top_resource_offset()));
+ __ movl(EDX, Address(THR, Thread::top_resource_offset()));
__ pushl(EDX);
- __ movl(Address(EDI, Isolate::top_resource_offset()), Immediate(0));
+ __ movl(Address(THR, Thread::top_resource_offset()), Immediate(0));
// The constant kExitLinkSlotFromEntryFp must be kept in sync with the
// code below.
ASSERT(kExitLinkSlotFromEntryFp == -6);
- __ movl(EDX, Address(EDI, Isolate::top_exit_frame_info_offset()));
+ __ movl(EDX, Address(THR, Thread::top_exit_frame_info_offset()));
__ pushl(EDX);
- __ movl(Address(EDI, Isolate::top_exit_frame_info_offset()), Immediate(0));
+ __ movl(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
// Load arguments descriptor array into EDX.
__ movl(EDX, Address(EBP, kArgumentsDescOffset));
@@ -809,8 +812,8 @@
// Restore the saved top exit frame info and top resource back into the
// Isolate structure.
__ LoadIsolate(EDI);
- __ popl(Address(EDI, Isolate::top_exit_frame_info_offset()));
- __ popl(Address(EDI, Isolate::top_resource_offset()));
+ __ 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()));
@@ -1344,9 +1347,8 @@
Label stepping, done_stepping;
if (FLAG_support_debugger && !optimized) {
__ Comment("Check single stepping");
- uword single_step_address = reinterpret_cast<uword>(Isolate::Current()) +
- Isolate::single_step_offset();
- __ cmpb(Address::Absolute(single_step_address), Immediate(0));
+ __ LoadIsolate(EAX);
+ __ cmpb(Address(EAX, Isolate::single_step_offset()), Immediate(0));
__ j(NOT_EQUAL, &stepping);
__ Bind(&done_stepping);
}
@@ -1646,9 +1648,8 @@
// Check single stepping.
Label stepping, done_stepping;
if (FLAG_support_debugger) {
- uword single_step_address = reinterpret_cast<uword>(Isolate::Current()) +
- Isolate::single_step_offset();
- __ cmpb(Address::Absolute(single_step_address), Immediate(0));
+ __ LoadIsolate(EAX);
+ __ cmpb(Address(EAX, Isolate::single_step_offset()), Immediate(0));
__ j(NOT_EQUAL, &stepping, Assembler::kNearJump);
__ Bind(&done_stepping);
}
@@ -1926,7 +1927,7 @@
__ movl(Address(EDI, Isolate::vm_tag_offset()),
Immediate(VMTag::kDartTagId));
// Clear top exit frame.
- __ movl(Address(EDI, Isolate::top_exit_frame_info_offset()), Immediate(0));
+ __ 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 eb53d7f..a1dd725 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -52,7 +52,7 @@
// Save exit frame information to enable stack walking as we are about
// to transition to Dart VM C++ code.
- __ sw(FP, Address(S6, Isolate::top_exit_frame_info_offset()));
+ __ sw(FP, Address(THR, Thread::top_exit_frame_info_offset()));
#if defined(DEBUG)
{ Label ok;
@@ -107,7 +107,7 @@
__ sw(A2, Address(S6, Isolate::vm_tag_offset()));
// Reset exit frame information in Isolate structure.
- __ sw(ZR, Address(S6, Isolate::top_exit_frame_info_offset()));
+ __ sw(ZR, Address(THR, Thread::top_exit_frame_info_offset()));
__ LeaveStubFrameAndReturn();
}
@@ -153,7 +153,7 @@
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
- __ sw(FP, Address(S6, Isolate::top_exit_frame_info_offset()));
+ __ sw(FP, Address(THR, Thread::top_exit_frame_info_offset()));
#if defined(DEBUG)
{ Label ok;
@@ -216,7 +216,7 @@
__ sw(A2, Address(S6, Isolate::vm_tag_offset()));
// Reset exit frame information in Isolate structure.
- __ sw(ZR, Address(S6, Isolate::top_exit_frame_info_offset()));
+ __ sw(ZR, Address(THR, Thread::top_exit_frame_info_offset()));
__ LeaveStubFrameAndReturn();
}
@@ -243,7 +243,7 @@
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
- __ sw(FP, Address(S6, Isolate::top_exit_frame_info_offset()));
+ __ sw(FP, Address(THR, Thread::top_exit_frame_info_offset()));
#if defined(DEBUG)
{ Label ok;
@@ -301,7 +301,7 @@
__ sw(A2, Address(S6, Isolate::vm_tag_offset()));
// Reset exit frame information in Isolate structure.
- __ sw(ZR, Address(S6, Isolate::top_exit_frame_info_offset()));
+ __ sw(ZR, Address(THR, Thread::top_exit_frame_info_offset()));
__ LeaveStubFrameAndReturn();
}
@@ -693,6 +693,9 @@
__ Comment("AllocateArrayStub");
*entry_patch_offset = assembler->CodeSize();
Label slow_case;
+ Isolate* isolate = Isolate::Current();
+ const Class& cls = Class::Handle(isolate->object_store()->array_class());
+ ASSERT(!cls.IsNull());
// Compute the size to be allocated, it is based on the array length
// and is computed as:
@@ -701,7 +704,11 @@
// Check that length is a positive Smi.
__ andi(CMPRES1, T3, Immediate(kSmiTagMask));
- __ bne(CMPRES1, ZR, &slow_case);
+ if (FLAG_use_slow_path || cls.trace_allocation()) {
+ __ b(&slow_case);
+ } else {
+ __ bne(CMPRES1, ZR, &slow_case);
+ }
__ bltz(T3, &slow_case);
// Check for maximum allowed length.
@@ -719,7 +726,6 @@
// T2: Allocation size.
- Isolate* isolate = Isolate::Current();
Heap* heap = isolate->heap();
const intptr_t cid = kArrayCid;
Heap::Space space = heap->SpaceForAllocation(cid);
@@ -884,11 +890,11 @@
// 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.
- __ lw(T0, Address(T2, Isolate::top_resource_offset()));
- __ sw(ZR, Address(T2, Isolate::top_resource_offset()));
+ __ lw(T0, Address(THR, Thread::top_resource_offset()));
+ __ sw(ZR, Address(THR, Thread::top_resource_offset()));
__ sw(T0, Address(SP, 1 * kWordSize));
- __ lw(T0, Address(T2, Isolate::top_exit_frame_info_offset()));
- __ sw(ZR, Address(T2, Isolate::top_exit_frame_info_offset()));
+ __ lw(T0, Address(THR, Thread::top_exit_frame_info_offset()));
+ __ sw(ZR, Address(THR, Thread::top_exit_frame_info_offset()));
// kExitLinkSlotFromEntryFp must be kept in sync with the code below.
ASSERT(kExitLinkSlotFromEntryFp == -23);
__ sw(T0, Address(SP, 0 * kWordSize));
@@ -940,9 +946,9 @@
// Restore the saved top resource and top exit frame info back into the
// Isolate structure. Uses T0 as a temporary register for this.
__ lw(T0, Address(SP, 1 * kWordSize));
- __ sw(T0, Address(S6, Isolate::top_resource_offset()));
+ __ sw(T0, Address(THR, Thread::top_resource_offset()));
__ lw(T0, Address(SP, 0 * kWordSize));
- __ sw(T0, Address(S6, Isolate::top_exit_frame_info_offset()));
+ __ sw(T0, Address(THR, Thread::top_exit_frame_info_offset()));
// Restore C++ ABI callee-saved registers.
for (int i = S0; i <= S7; i++) {
@@ -2087,7 +2093,7 @@
__ LoadImmediate(A2, VMTag::kDartTagId);
__ sw(A2, Address(A3, Isolate::vm_tag_offset()));
// Clear top exit frame.
- __ sw(ZR, Address(A3, Isolate::top_exit_frame_info_offset()));
+ __ sw(ZR, Address(THR, Thread::top_exit_frame_info_offset()));
__ jr(A0); // Jump to the exception handler code.
__ delay_slot()->mov(SP, A1); // Stack pointer.
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index c844e1f..e50c260 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -52,7 +52,7 @@
// Save exit frame information to enable stack walking as we are about
// to transition to Dart VM C++ code.
- __ movq(Address(R12, Isolate::top_exit_frame_info_offset()), RBP);
+ __ movq(Address(THR, Thread::top_exit_frame_info_offset()), RBP);
#if defined(DEBUG)
{ Label ok;
@@ -94,7 +94,7 @@
Immediate(VMTag::kDartTagId));
// Reset exit frame information in Isolate structure.
- __ movq(Address(R12, Isolate::top_exit_frame_info_offset()), Immediate(0));
+ __ movq(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
__ LeaveStubFrame();
__ ret();
@@ -149,7 +149,7 @@
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
- __ movq(Address(R12, Isolate::top_exit_frame_info_offset()), RBP);
+ __ movq(Address(THR, Thread::top_exit_frame_info_offset()), RBP);
#if defined(DEBUG)
{ Label ok;
@@ -191,7 +191,7 @@
Immediate(VMTag::kDartTagId));
// Reset exit frame information in Isolate structure.
- __ movq(Address(R12, Isolate::top_exit_frame_info_offset()), Immediate(0));
+ __ movq(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
__ LeaveStubFrame();
__ ret();
@@ -223,7 +223,7 @@
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
- __ movq(Address(R12, Isolate::top_exit_frame_info_offset()), RBP);
+ __ movq(Address(THR, Thread::top_exit_frame_info_offset()), RBP);
#if defined(DEBUG)
{ Label ok;
@@ -263,7 +263,7 @@
Immediate(VMTag::kDartTagId));
// Reset exit frame information in Isolate structure.
- __ movq(Address(R12, Isolate::top_exit_frame_info_offset()), Immediate(0));
+ __ movq(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
__ LeaveStubFrame();
__ ret();
@@ -611,13 +611,20 @@
__ LoadPoolPointer(new_pp);
*entry_patch_offset = assembler->CodeSize();
Label slow_case;
+ Isolate* isolate = Isolate::Current();
+ const Class& cls = Class::Handle(isolate->object_store()->array_class());
+ ASSERT(!cls.IsNull());
// Compute the size to be allocated, it is based on the array length
// and is computed as:
// RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)).
__ movq(RDI, R10); // Array Length.
// Check that length is a positive Smi.
__ testq(RDI, Immediate(kSmiTagMask));
- __ j(NOT_ZERO, &slow_case);
+ if (FLAG_use_slow_path || cls.trace_allocation()) {
+ __ jmp(&slow_case);
+ } else {
+ __ j(NOT_ZERO, &slow_case);
+ }
__ cmpq(RDI, Immediate(0));
__ j(LESS, &slow_case);
// Check for maximum allowed length.
@@ -630,7 +637,6 @@
ASSERT(kSmiTagShift == 1);
__ andq(RDI, Immediate(-kObjectAlignment));
- Isolate* isolate = Isolate::Current();
Heap* heap = isolate->heap();
const intptr_t cid = kArrayCid;
Heap::Space space = heap->SpaceForAllocation(cid);
@@ -787,11 +793,11 @@
// 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.
- __ movq(RAX, Address(kIsolateReg, Isolate::top_resource_offset()));
+ __ movq(RAX, Address(THR, Thread::top_resource_offset()));
__ pushq(RAX);
- __ movq(Address(kIsolateReg, Isolate::top_resource_offset()),
+ __ movq(Address(THR, Thread::top_resource_offset()),
Immediate(0));
- __ movq(RAX, Address(kIsolateReg, Isolate::top_exit_frame_info_offset()));
+ __ movq(RAX, Address(THR, Thread::top_exit_frame_info_offset()));
// The constant kExitLinkSlotFromEntryFp must be kept in sync with the
// code below.
__ pushq(RAX);
@@ -805,7 +811,7 @@
__ Bind(&ok);
}
#endif
- __ movq(Address(kIsolateReg, Isolate::top_exit_frame_info_offset()),
+ __ movq(Address(THR, Thread::top_exit_frame_info_offset()),
Immediate(0));
// Load arguments descriptor array into R10, which is passed to Dart code.
@@ -849,8 +855,8 @@
// Restore the saved top exit frame info and top resource back into the
// Isolate structure.
__ LoadIsolate(kIsolateReg);
- __ popq(Address(kIsolateReg, Isolate::top_exit_frame_info_offset()));
- __ popq(Address(kIsolateReg, Isolate::top_resource_offset()));
+ __ 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()));
@@ -1985,7 +1991,7 @@
__ movq(Address(isolate_reg, Isolate::vm_tag_offset()),
Immediate(VMTag::kDartTagId));
// Clear top exit frame.
- __ movq(Address(isolate_reg, Isolate::top_exit_frame_info_offset()),
+ __ movq(Address(THR, Thread::top_exit_frame_info_offset()),
Immediate(0));
__ jmp(CallingConventions::kArg1Reg); // Jump to the exception handler code.
}
diff --git a/runtime/vm/symbols.cc b/runtime/vm/symbols.cc
index f9b3abf..7cafda2 100644
--- a/runtime/vm/symbols.cc
+++ b/runtime/vm/symbols.cc
@@ -350,7 +350,7 @@
Utf8::Type type;
intptr_t len = Utf8::CodeUnitCount(utf8_array, array_len, &type);
ASSERT(len != 0);
- Zone* zone = Isolate::Current()->current_zone();
+ Zone* zone = Thread::Current()->zone();
if (type == Utf8::kLatin1) {
uint8_t* characters = zone->Alloc<uint8_t>(len);
Utf8::DecodeToLatin1(utf8_array, array_len, characters, len);
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index ee38d31..ee8a711 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -66,6 +66,7 @@
V(NoSuchMethodError, "NoSuchMethodError") \
V(CyclicInitializationError, "CyclicInitializationError") \
V(ThrowNew, "_throwNew") \
+ V(ThrowNewIfNotLoaded, "_throwNewIfNotLoaded") \
V(Symbol, "Symbol") \
V(SymbolCtor, "Symbol.") \
V(List, "List") \
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index ba6db93..a82c8b3 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -4,11 +4,15 @@
#include "vm/thread.h"
+#include "vm/growable_array.h"
#include "vm/isolate.h"
+#include "vm/lockers.h"
+#include "vm/object.h"
#include "vm/os_thread.h"
#include "vm/profiler.h"
+#include "vm/stub_code.h"
#include "vm/thread_interrupter.h"
-
+#include "vm/thread_registry.h"
namespace dart {
@@ -23,10 +27,21 @@
}
-void Thread::InitOnce() {
+void Thread::InitOnceBeforeIsolate() {
ASSERT(thread_key_ == OSThread::kUnsetThreadLocalKey);
thread_key_ = OSThread::CreateThreadLocal(DeleteThread);
ASSERT(thread_key_ != OSThread::kUnsetThreadLocalKey);
+ ASSERT(Thread::Current() == NULL);
+ // Postpone initialization of VM constants for this first thread.
+ SetCurrent(new Thread(false));
+}
+
+
+void Thread::InitOnceAfterObjectAndStubCode() {
+ Thread* thread = Thread::Current();
+ ASSERT(thread != NULL);
+ ASSERT(thread->isolate() == Dart::vm_isolate());
+ thread->InitVMConstants();
}
@@ -53,6 +68,51 @@
#endif
+Thread::Thread(bool init_vm_constants)
+ : isolate_(NULL),
+ store_buffer_block_(NULL) {
+ ClearState();
+#define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value) \
+ member_name = default_init_value;
+CACHED_CONSTANTS_LIST(DEFAULT_INIT)
+#undef DEFAULT_INIT
+ if (init_vm_constants) {
+ InitVMConstants();
+ }
+}
+
+
+void Thread::InitVMConstants() {
+#define ASSERT_VM_HEAP(type_name, member_name, init_expr, default_init_value) \
+ ASSERT((init_expr)->IsOldObject());
+CACHED_VM_OBJECTS_LIST(ASSERT_VM_HEAP)
+#undef ASSERT_VM_HEAP
+
+#define INIT_VALUE(type_name, member_name, init_expr, default_init_value) \
+ ASSERT(member_name == default_init_value); \
+ member_name = (init_expr);
+CACHED_CONSTANTS_LIST(INIT_VALUE)
+#undef INIT_VALUE
+}
+
+
+void Thread::Schedule(Isolate* isolate) {
+ State st;
+ if (isolate->thread_registry()->RestoreStateTo(this, &st)) {
+ ASSERT(isolate->thread_registry()->Contains(this));
+ state_ = st;
+ }
+}
+
+
+void Thread::Unschedule() {
+ ThreadRegistry* reg = isolate_->thread_registry();
+ ASSERT(reg->Contains(this));
+ reg->SaveStateFrom(this, state_);
+ ClearState();
+}
+
+
void Thread::EnterIsolate(Isolate* isolate) {
Thread* thread = Thread::Current();
ASSERT(thread != NULL);
@@ -74,6 +134,7 @@
isolate->set_vm_tag(VMTag::kVMTagId);
ASSERT(thread->store_buffer_block_ == NULL);
thread->store_buffer_block_ = isolate->store_buffer()->PopBlock();
+ thread->Schedule(isolate);
}
@@ -82,6 +143,7 @@
// TODO(koda): Audit callers; they should know whether they're in an isolate.
if (thread == NULL || thread->isolate() == NULL) return;
Isolate* isolate = thread->isolate();
+ thread->Unschedule();
StoreBufferBlock* block = thread->store_buffer_block_;
thread->store_buffer_block_ = NULL;
isolate->store_buffer()->PushBlock(block);
@@ -106,6 +168,7 @@
// Do not update isolate->mutator_thread, but perform sanity check:
// this thread should not be both the main mutator and helper.
ASSERT(isolate->mutator_thread() != thread);
+ thread->Schedule(isolate);
}
@@ -116,6 +179,7 @@
ASSERT(thread->store_buffer_block_ == NULL);
Isolate* isolate = thread->isolate();
ASSERT(isolate != NULL);
+ thread->Unschedule();
thread->isolate_ = NULL;
ASSERT(isolate->mutator_thread() != thread);
}
@@ -168,4 +232,24 @@
isolate_->cha_ = value;
}
+
+bool Thread::CanLoadFromThread(const Object& object) {
+#define CHECK_OBJECT(type_name, member_name, expr, default_init_value) \
+ if (object.raw() == expr) return true;
+CACHED_VM_OBJECTS_LIST(CHECK_OBJECT)
+#undef CHECK_OBJECT
+ return false;
+}
+
+
+intptr_t Thread::OffsetFromThread(const Object& object) {
+#define COMPUTE_OFFSET(type_name, member_name, expr, default_init_value) \
+ ASSERT((expr)->IsVMHeapObject()); \
+ if (object.raw() == expr) return Thread::member_name##offset();
+CACHED_VM_OBJECTS_LIST(COMPUTE_OFFSET)
+#undef COMPUTE_OFFSET
+ UNREACHABLE();
+ return -1;
+}
+
} // namespace dart
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 3a8dacd..00cea34 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -5,7 +5,6 @@
#ifndef VM_THREAD_H_
#define VM_THREAD_H_
-#include "vm/base_isolate.h"
#include "vm/globals.h"
#include "vm/os_thread.h"
#include "vm/store_buffer.h"
@@ -14,6 +13,26 @@
class CHA;
class Isolate;
+class Object;
+class RawBool;
+class RawObject;
+class StackResource;
+class Zone;
+
+// List of VM-global objects/addresses cached in each Thread object.
+#define CACHED_VM_OBJECTS_LIST(V) \
+ V(RawObject*, object_null_, Object::null(), NULL) \
+ V(RawBool*, bool_true_, Object::bool_true().raw(), NULL) \
+ V(RawBool*, bool_false_, Object::bool_false().raw(), NULL) \
+
+#define CACHED_ADDRESSES_LIST(V) \
+ V(uword, update_store_buffer_entry_point_, \
+ StubCode::UpdateStoreBufferEntryPoint(), 0)
+
+#define CACHED_CONSTANTS_LIST(V) \
+ CACHED_VM_OBJECTS_LIST(V) \
+ CACHED_ADDRESSES_LIST(V)
+
// A VM thread; may be executing Dart code or performing helper tasks like
// garbage collection or compilation. The Thread structure associated with
@@ -53,12 +72,11 @@
#endif
// Called at VM startup.
- static void InitOnce();
+ static void InitOnceBeforeIsolate();
+ static void InitOnceAfterObjectAndStubCode();
// The topmost zone used for allocation in this thread.
- Zone* zone() {
- return reinterpret_cast<BaseIsolate*>(isolate())->current_zone();
- }
+ Zone* zone() const { return state_.zone; }
// The isolate that this thread is operating on, or NULL if none.
Isolate* isolate() const { return isolate_; }
@@ -83,17 +101,71 @@
return OFFSET_OF(Thread, store_buffer_block_);
}
+ uword top_exit_frame_info() const { return state_.top_exit_frame_info; }
+ static intptr_t top_exit_frame_info_offset() {
+ return OFFSET_OF(Thread, state_) + OFFSET_OF(State, top_exit_frame_info);
+ }
+
+ StackResource* top_resource() const { return state_.top_resource; }
+ void set_top_resource(StackResource* value) {
+ state_.top_resource = value;
+ }
+ static intptr_t top_resource_offset() {
+ return OFFSET_OF(Thread, state_) + OFFSET_OF(State, top_resource);
+ }
+
+ // Collection of isolate-specific state of a thread that is saved/restored
+ // on isolate exit/re-entry.
+ struct State {
+ Zone* zone;
+ uword top_exit_frame_info;
+ StackResource* top_resource;
+ };
+
+#define DEFINE_OFFSET_METHOD(type_name, member_name, expr, default_init_value) \
+ static intptr_t member_name##offset() { \
+ return OFFSET_OF(Thread, member_name); \
+ }
+CACHED_CONSTANTS_LIST(DEFINE_OFFSET_METHOD)
+#undef DEFINE_OFFSET_METHOD
+
+ static bool CanLoadFromThread(const Object& object);
+ static intptr_t OffsetFromThread(const Object& object);
+
private:
static ThreadLocalKey thread_key_;
Isolate* isolate_;
+ State state_;
StoreBufferBlock* store_buffer_block_;
+#define DECLARE_MEMBERS(type_name, member_name, expr, default_init_value) \
+ type_name member_name;
+CACHED_CONSTANTS_LIST(DECLARE_MEMBERS)
+#undef DECLARE_MEMBERS
- Thread()
- : isolate_(NULL), store_buffer_block_(NULL) {}
+ explicit Thread(bool init_vm_constants = true);
+
+ void InitVMConstants();
+
+ void ClearState() {
+ memset(&state_, 0, sizeof(state_));
+ }
+
+ void set_zone(Zone* zone) {
+ state_.zone = zone;
+ }
+
+ void set_top_exit_frame_info(uword top_exit_frame_info) {
+ state_.top_exit_frame_info = top_exit_frame_info;
+ }
static void SetCurrent(Thread* current);
+ void Schedule(Isolate* isolate);
+ void Unschedule();
+
+ friend class Isolate;
+ friend class StackZone;
DISALLOW_COPY_AND_ASSIGN(Thread);
};
diff --git a/runtime/vm/thread_registry.h b/runtime/vm/thread_registry.h
new file mode 100644
index 0000000..d4de8a3
--- /dev/null
+++ b/runtime/vm/thread_registry.h
@@ -0,0 +1,105 @@
+// 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.
+
+#ifndef VM_THREAD_REGISTRY_H_
+#define VM_THREAD_REGISTRY_H_
+
+#include "vm/globals.h"
+#include "vm/growable_array.h"
+#include "vm/isolate.h"
+#include "vm/lockers.h"
+#include "vm/thread.h"
+
+namespace dart {
+
+// Unordered collection of threads relating to a particular isolate.
+class ThreadRegistry {
+ public:
+ ThreadRegistry() : mutex_(new Mutex()), entries_() {}
+
+ bool RestoreStateTo(Thread* thread, Thread::State* state) {
+ MutexLocker ml(mutex_);
+ Entry* entry = FindEntry(thread);
+ if (entry != NULL) {
+ Thread::State st = entry->state;
+ // TODO(koda): Support same thread re-entering same isolate with
+ // Dart frames in between. For now, just assert it doesn't happen.
+ if (st.top_exit_frame_info != thread->top_exit_frame_info()) {
+ ASSERT(thread->top_exit_frame_info() == 0 ||
+ thread->top_exit_frame_info() > st.top_exit_frame_info);
+ }
+ ASSERT(!entry->scheduled);
+ entry->scheduled = true;
+#if defined(DEBUG)
+ // State field is not in use, so zap it.
+ memset(&entry->state, 0xda, sizeof(entry->state));
+#endif
+ *state = st;
+ return true;
+ }
+ Entry new_entry;
+ new_entry.thread = thread;
+ new_entry.scheduled = true;
+#if defined(DEBUG)
+ // State field is not in use, so zap it.
+ memset(&new_entry.state, 0xda, sizeof(new_entry.state));
+#endif
+ entries_.Add(new_entry);
+ return false;
+ }
+
+ void SaveStateFrom(Thread* thread, const Thread::State& state) {
+ MutexLocker ml(mutex_);
+ Entry* entry = FindEntry(thread);
+ ASSERT(entry != NULL);
+ ASSERT(entry->scheduled);
+ entry->scheduled = false;
+ entry->state = state;
+ }
+
+ bool Contains(Thread* thread) {
+ MutexLocker ml(mutex_);
+ return (FindEntry(thread) != NULL);
+ }
+
+ void VisitObjectPointers(ObjectPointerVisitor* visitor) {
+ MutexLocker ml(mutex_);
+ for (int i = 0; i < entries_.length(); ++i) {
+ const Entry& entry = entries_[i];
+ Zone* zone = entry.scheduled ? entry.thread->zone() : entry.state.zone;
+ if (zone != NULL) {
+ zone->VisitObjectPointers(visitor);
+ }
+ }
+ }
+
+ private:
+ struct Entry {
+ Thread* thread;
+ bool scheduled;
+ Thread::State state;
+ };
+
+ // Returns Entry corresponding to thread in registry or NULL.
+ // Note: Lock should be taken before this function is called.
+ Entry* FindEntry(Thread* thread) {
+ DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread());
+ for (int i = 0; i < entries_.length(); ++i) {
+ if (entries_[i].thread == thread) {
+ return &entries_[i];
+ }
+ }
+ return NULL;
+ }
+
+ Mutex* mutex_;
+ MallocGrowableArray<Entry> entries_;
+
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadRegistry);
+};
+
+} // namespace dart
+
+#endif // VM_THREAD_REGISTRY_H_
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index 5cb270b6b..0eccd64 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -7,6 +7,8 @@
#include "vm/lockers.h"
#include "vm/unit_test.h"
#include "vm/profiler.h"
+#include "vm/thread_pool.h"
+#include "vm/thread_registry.h"
namespace dart {
@@ -82,4 +84,142 @@
delete monitor;
}
+
+class ObjectCounter : public ObjectPointerVisitor {
+ public:
+ explicit ObjectCounter(Isolate* isolate, const Object* obj)
+ : ObjectPointerVisitor(isolate), obj_(obj), count_(0) { }
+
+ virtual void VisitPointers(RawObject** first, RawObject** last) {
+ for (RawObject** current = first; current <= last; ++current) {
+ if (*current == obj_->raw()) {
+ ++count_;
+ }
+ }
+ }
+
+ intptr_t count() const { return count_; }
+
+ private:
+ const Object* obj_;
+ intptr_t count_;
+};
+
+
+class TaskWithZoneAllocation : public ThreadPool::Task {
+ public:
+ TaskWithZoneAllocation(Isolate* isolate,
+ const String& foo,
+ Monitor* monitor,
+ bool* done,
+ intptr_t id)
+ : isolate_(isolate), foo_(foo), monitor_(monitor), done_(done), id_(id) {}
+ virtual void Run() {
+ Thread::EnterIsolateAsHelper(isolate_);
+ {
+ // Create a zone (which is also a stack resource) and exercise it a bit.
+ StackZone stack_zone(Thread::Current());
+ Zone* zone = Thread::Current()->zone();
+ EXPECT_EQ(zone, stack_zone.GetZone());
+ ZoneGrowableArray<bool>* a0 = new(zone) ZoneGrowableArray<bool>(zone, 1);
+ GrowableArray<bool> a1(zone, 1);
+ for (intptr_t i = 0; i < 100000; ++i) {
+ a0->Add(true);
+ a1.Add(true);
+ }
+ // Check that we can create handles (but not yet allocate heap objects).
+ String& str = String::Handle(zone, foo_.raw());
+ EXPECT(str.Equals("foo"));
+ const intptr_t unique_smi = id_ + 928327281;
+ Smi& smi = Smi::Handle(zone, Smi::New(unique_smi));
+ EXPECT(smi.Value() == unique_smi);
+ ObjectCounter counter(isolate_, &smi);
+ // Ensure that our particular zone is visited.
+ // TODO(koda): Remove "->thread_registry()" after updating stack walker.
+ isolate_->thread_registry()->VisitObjectPointers(&counter);
+ EXPECT_EQ(1, counter.count());
+ }
+ Thread::ExitIsolateAsHelper();
+ {
+ MonitorLocker ml(monitor_);
+ *done_ = true;
+ ml.Notify();
+ }
+ }
+
+ private:
+ Isolate* isolate_;
+ const String& foo_;
+ Monitor* monitor_;
+ bool* done_;
+ intptr_t id_;
+};
+
+
+TEST_CASE(ManyTasksWithZones) {
+ const int kTaskCount = 100;
+ Monitor sync[kTaskCount];
+ bool done[kTaskCount];
+ Isolate* isolate = Thread::Current()->isolate();
+ String& foo = String::Handle(String::New("foo"));
+
+ for (int i = 0; i < kTaskCount; i++) {
+ done[i] = false;
+ Dart::thread_pool()->Run(
+ new TaskWithZoneAllocation(isolate, foo, &sync[i], &done[i], i));
+ }
+ for (int i = 0; i < kTaskCount; i++) {
+ // Check that main mutator thread can still freely use its own zone.
+ String& bar = String::Handle(String::New("bar"));
+ if (i % 10 == 0) {
+ // Mutator thread is free to independently move in/out/between isolates.
+ Thread::ExitIsolate();
+ }
+ MonitorLocker ml(&sync[i]);
+ while (!done[i]) {
+ ml.Wait();
+ }
+ EXPECT(done[i]);
+ if (i % 10 == 0) {
+ Thread::EnterIsolate(isolate);
+ }
+ EXPECT(bar.Equals("bar"));
+ }
+}
+
+
+TEST_CASE(ThreadRegistry) {
+ Isolate* orig = Thread::Current()->isolate();
+ Zone* orig_zone = Thread::Current()->zone();
+ char* orig_str = orig_zone->PrintToString("foo");
+ Thread::ExitIsolate();
+ Isolate::Flags vm_flags;
+ Dart_IsolateFlags api_flags;
+ vm_flags.CopyTo(&api_flags);
+ Isolate* isos[2];
+ // Create and enter a new isolate.
+ isos[0] = Isolate::Init(NULL, api_flags);
+ Zone* zone0 = Thread::Current()->zone();
+ EXPECT(zone0 != orig_zone);
+ isos[0]->Shutdown();
+ Thread::ExitIsolate();
+ // Create and enter yet another isolate.
+ isos[1] = Isolate::Init(NULL, api_flags);
+ {
+ // Create a stack resource this time, and exercise it.
+ StackZone stack_zone(Thread::Current());
+ Zone* zone1 = Thread::Current()->zone();
+ EXPECT(zone1 != zone0);
+ EXPECT(zone1 != orig_zone);
+ }
+ isos[1]->Shutdown();
+ Thread::ExitIsolate();
+ Thread::EnterIsolate(orig);
+ // Original zone should be preserved.
+ EXPECT_EQ(orig_zone, Thread::Current()->zone());
+ EXPECT_STREQ("foo", orig_str);
+ delete isos[0];
+ delete isos[1];
+}
+
} // namespace dart
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index 2fc1440..3d5e179 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -371,7 +371,7 @@
intptr_t pid = OS::ProcessId();
intptr_t len = OS::SNPrint(NULL, 0, format,
directory, pid, isolate->main_port());
- char* filename = isolate->current_zone()->Alloc<char>(len + 1);
+ char* filename = Thread::Current()->zone()->Alloc<char>(len + 1);
OS::SNPrint(filename, len + 1, format,
directory, pid, isolate->main_port());
void* file = (*file_open)(filename, true);
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index 886e14c..88b8cb2 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -452,6 +452,7 @@
'thread_pool.cc',
'thread_pool.h',
'thread_pool_test.cc',
+ 'thread_registry.h',
'thread_test.cc',
'timeline.cc',
'timeline.h',
diff --git a/runtime/vm/weak_code.cc b/runtime/vm/weak_code.cc
index fa11174..3177ba6 100644
--- a/runtime/vm/weak_code.cc
+++ b/runtime/vm/weak_code.cc
@@ -8,6 +8,7 @@
#include "vm/code_generator.h"
#include "vm/code_patcher.h"
+#include "vm/compiler.h"
#include "vm/object.h"
#include "vm/stack_frame.h"
@@ -60,6 +61,7 @@
if (code_objects.IsNull()) {
return;
}
+ ASSERT(Compiler::allow_recompilation());
UpdateArrayTo(Object::null_array());
// Disable all code on stack.
Code& code = Code::Handle();
diff --git a/runtime/vm/zone.cc b/runtime/vm/zone.cc
index b16c030..58fb1d1 100644
--- a/runtime/vm/zone.cc
+++ b/runtime/vm/zone.cc
@@ -215,5 +215,4 @@
return buffer;
}
-
} // namespace dart
diff --git a/runtime/vm/zone.h b/runtime/vm/zone.h
index 0d89c5d..ee0add5 100644
--- a/runtime/vm/zone.h
+++ b/runtime/vm/zone.h
@@ -174,27 +174,21 @@
class StackZone : public StackResource {
public:
- // Create an empty zone and set is at the current zone for the Isolate.
- explicit StackZone(Isolate* isolate)
- : StackResource(isolate),
- zone_() {
-#ifdef DEBUG
- if (FLAG_trace_zones) {
- OS::PrintErr("*** Starting a new Stack zone 0x%" Px "(0x%" Px ")\n",
- reinterpret_cast<intptr_t>(this),
- reinterpret_cast<intptr_t>(&zone_));
- }
-#endif
- BaseIsolate* base_isolate = reinterpret_cast<BaseIsolate*>(isolate);
- zone_.Link(base_isolate->current_zone());
- base_isolate->set_current_zone(&zone_);
+ // Create an empty zone and set is at the current zone for the Thread.
+ explicit StackZone(Thread* thread) : StackResource(thread), zone_() {
+ Initialize();
+ }
+
+ // DEPRECATED: Use Thread-based interface. During migration, this defaults
+ // to using the mutator thread (which must also be the current thread).
+ explicit StackZone(Isolate* isolate) : StackResource(isolate), zone_() {
+ Initialize();
}
// Delete all memory associated with the zone.
~StackZone() {
- BaseIsolate* base_isolate = reinterpret_cast<BaseIsolate*>(isolate());
- ASSERT(base_isolate->current_zone() == &zone_);
- base_isolate->set_current_zone(zone_.previous_);
+ ASSERT(thread()->zone() == &zone_);
+ thread()->set_zone(zone_.previous_);
#ifdef DEBUG
if (FLAG_trace_zones) {
OS::PrintErr("*** Deleting Stack zone 0x%" Px "(0x%" Px ")\n",
@@ -213,6 +207,18 @@
private:
Zone zone_;
+ void Initialize() {
+#ifdef DEBUG
+ if (FLAG_trace_zones) {
+ OS::PrintErr("*** Starting a new Stack zone 0x%" Px "(0x%" Px ")\n",
+ reinterpret_cast<intptr_t>(this),
+ reinterpret_cast<intptr_t>(&zone_));
+ }
+#endif
+ zone_.Link(thread()->zone());
+ thread()->set_zone(&zone_);
+ }
+
template<typename T> friend class GrowableArray;
template<typename T> friend class ZoneGrowableArray;
diff --git a/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart b/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
index 5ce8113..b298e0d 100644
--- a/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
@@ -184,9 +184,9 @@
external RAW_DART_FUNCTION_REF(Function function);
/**
- * Sets the current isolate to [isolate].
+ * Sets the current static state to [staticState].
*/
-external void JS_SET_CURRENT_ISOLATE(isolate);
+external void JS_SET_STATIC_STATE(staticState);
/**
* Returns the interceptor for class [type]. The interceptor is the type's
@@ -197,9 +197,9 @@
external JS_INTERCEPTOR_CONSTANT(Type type);
/**
- * Returns the object corresponding to Namer.CURRENT_ISOLATE.
+ * Returns the object corresponding to Namer.staticStateHolder.
*/
-external JS_CURRENT_ISOLATE();
+external JS_GET_STATIC_STATE();
/// Returns the JS name for [name] from the Namer.
external String JS_GET_NAME(JsGetName name);
diff --git a/sdk/lib/_internal/js_runtime/lib/isolate_helper.dart b/sdk/lib/_internal/js_runtime/lib/isolate_helper.dart
index e3f13bf..5ff44bb 100644
--- a/sdk/lib/_internal/js_runtime/lib/isolate_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/isolate_helper.dart
@@ -31,9 +31,8 @@
import 'dart:_foreign_helper' show DART_CLOSURE_TO_JS,
JS,
JS_CURRENT_ISOLATE_CONTEXT,
- JS_CURRENT_ISOLATE,
JS_EMBEDDED_GLOBAL,
- JS_SET_CURRENT_ISOLATE,
+ JS_SET_STATIC_STATE,
IsolateContext;
import 'dart:_interceptors' show Interceptor,
@@ -482,7 +481,7 @@
}
void _setGlobals() {
- JS_SET_CURRENT_ISOLATE(isolateStatics);
+ JS_SET_STATIC_STATE(isolateStatics);
}
/**
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index 291e178..92ea4ba 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -44,7 +44,7 @@
JS_BUILTIN,
JS_CALL_IN_ISOLATE,
JS_CONST,
- JS_CURRENT_ISOLATE,
+ JS_GET_STATIC_STATEC,
JS_CURRENT_ISOLATE_CONTEXT,
JS_EFFECT,
JS_EMBEDDED_GLOBAL,
diff --git a/sdk/lib/_internal/js_runtime/lib/js_mirrors.dart b/sdk/lib/_internal/js_runtime/lib/js_mirrors.dart
index 5815a32..e5c8495 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_mirrors.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_mirrors.dart
@@ -23,7 +23,7 @@
import 'dart:_foreign_helper' show
JS,
JS_GET_FLAG,
- JS_CURRENT_ISOLATE,
+ JS_GET_STATIC_STATE,
JS_CURRENT_ISOLATE_CONTEXT,
JS_EMBEDDED_GLOBAL,
JS_GET_NAME,
@@ -447,17 +447,17 @@
// TODO(ahe): What about lazily initialized fields? See
// [JsClassMirror.getField].
- // '$' (JS_CURRENT_ISOLATE()) stores state which is read directly, so we
+ // '$' (JS_GET_STATIC_STATE()) stores state which is read directly, so we
// shouldn't use [_globalObject] here.
- assert(JS('bool', '# in #', name, JS_CURRENT_ISOLATE()));
- return JS('', '#[#]', JS_CURRENT_ISOLATE(), name);
+ assert(JS('bool', '# in #', name, JS_GET_STATIC_STATE()));
+ return JS('', '#[#]', JS_GET_STATIC_STATE(), name);
}
void _storeField(String name, Object arg) {
- // '$' (JS_CURRENT_ISOLATE()) stores state which is stored directly, so we
+ // '$' (JS_GET_STATIC_STATE()) stores state which is stored directly, so we
// shouldn't use [_globalObject] here.
- assert(JS('bool', '# in #', name, JS_CURRENT_ISOLATE()));
- JS('void', '#[#] = #', JS_CURRENT_ISOLATE(), name, arg);
+ assert(JS('bool', '# in #', name, JS_GET_STATIC_STATE()));
+ JS('void', '#[#] = #', JS_GET_STATIC_STATE(), name, arg);
}
List<JsMethodMirror> get _functionMirrors {
@@ -1859,13 +1859,13 @@
InstanceMirror setField(Symbol fieldName, Object arg) {
JsVariableMirror mirror = __variables[fieldName];
if (mirror != null && mirror.isStatic && !mirror.isFinal) {
- // '$' (JS_CURRENT_ISOLATE()) stores state which is stored directly, so
+ // '$' (JS_GET_STATIC_STATE()) stores state which is stored directly, so
// we shouldn't use [JsLibraryMirror._globalObject] here.
String jsName = mirror._jsName;
- if (!JS('bool', '# in #', jsName, JS_CURRENT_ISOLATE())) {
+ if (!JS('bool', '# in #', jsName, JS_GET_STATIC_STATE())) {
throw new RuntimeError('Cannot find "$jsName" in current isolate.');
}
- JS('void', '#[#] = #', JS_CURRENT_ISOLATE(), jsName, arg);
+ JS('void', '#[#] = #', JS_GET_STATIC_STATE(), jsName, arg);
return reflect(arg);
}
Symbol setterName = setterSymbol(fieldName);
@@ -1890,17 +1890,17 @@
JsVariableMirror mirror = __variables[fieldName];
if (mirror != null && mirror.isStatic) {
String jsName = mirror._jsName;
- // '$' (JS_CURRENT_ISOLATE()) stores state which is read directly, so
+ // '$' (JS_GET_STATIC_STATE()) stores state which is read directly, so
// we shouldn't use [JsLibraryMirror._globalObject] here.
- if (!JS('bool', '# in #', jsName, JS_CURRENT_ISOLATE())) {
+ if (!JS('bool', '# in #', jsName, JS_GET_STATIC_STATE())) {
throw new RuntimeError('Cannot find "$jsName" in current isolate.');
}
var lazies = JS_EMBEDDED_GLOBAL('', LAZIES);
if (JS('bool', '# in #', jsName, lazies)) {
String getterName = JS('String', '#[#]', lazies, jsName);
- return reflect(JS('', '#[#]()', JS_CURRENT_ISOLATE(), getterName));
+ return reflect(JS('', '#[#]()', JS_GET_STATIC_STATE(), getterName));
} else {
- return reflect(JS('', '#[#]', JS_CURRENT_ISOLATE(), jsName));
+ return reflect(JS('', '#[#]', JS_GET_STATIC_STATE(), jsName));
}
}
JsMethodMirror getter = __getters[fieldName];
@@ -2449,11 +2449,11 @@
positionalArguments.add(parameter.defaultValue.reflectee);
}
}
- // Using JS_CURRENT_ISOLATE() ('$') here is actually correct, although
+ // Using JS_GET_STATIC_STATE() ('$') here is actually correct, although
// _jsFunction may not be a property of '$', most static functions do not
// care who their receiver is. But to lazy getters, it is important that
// 'this' is '$'.
- return JS('', r'#.apply(#, #)', _jsFunction, JS_CURRENT_ISOLATE(),
+ return JS('', r'#.apply(#, #)', _jsFunction, JS_GET_STATIC_STATE(),
new List.from(positionalArguments));
}
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
index fee73b2..5cf49b0 100644
--- a/sdk/lib/core/uri.dart
+++ b/sdk/lib/core/uri.dart
@@ -157,13 +157,12 @@
* to `end` is parsed as a URI.
*
* If the string is not valid as a URI or URI reference,
- * invalid characters will be percent escaped where possible.
- * The resulting `Uri` will represent a valid URI or URI reference.
+ * a [FormatException] is thrown.
*/
static Uri parse(String uri, [int start = 0, int end]) {
- // This parsing will not validate percent-encoding, IPv6, etc. When done
- // it will call `new Uri(...)` which will perform these validations.
- // This is purely splitting up the URI string into components.
+ // This parsing will not validate percent-encoding, IPv6, etc.
+ // When done splitting into parts, it will call, e.g., [_makeFragment]
+ // to do the final parsing.
//
// Important parts of the RFC 3986 used here:
// URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
diff --git a/sdk/lib/developer/developer.dart b/sdk/lib/developer/developer.dart
index 4df565e..03c75c1 100644
--- a/sdk/lib/developer/developer.dart
+++ b/sdk/lib/developer/developer.dart
@@ -2,9 +2,9 @@
// 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.
-/// ## Status: Unstable
+/// Interact with developer tools such as the debugger and inspector.
///
-/// The dart:developer library is unstable and its API might change slightly
+/// The dart:developer library is _unstable_ and its API might change slightly
/// as a result of developer feedback. This library is platform dependent and
/// therefore it has implementations for both dart2js and the Dart VM. Both are
/// under development and may not support all operations yet.
@@ -15,9 +15,12 @@
part 'profiler.dart';
-/// If [when] is true, stop the program as if a breakpoint where hit at the
-/// following statement. Returns the value of [when]. Some debuggers may
+/// If [when] is true, stop the program as if a breakpoint were hit at the
+/// following statement.
+///
+/// Returns the value of [when]. Some debuggers may
/// display [msg].
+///
/// NOTE: When invoked, the isolate will not return until a debugger
/// continues execution. When running in the Dart VM the behaviour is the same
/// regardless of whether or not a debugger is connected. When compiled to
@@ -25,6 +28,7 @@
/// that does.
external bool debugger({bool when: true, String msg});
-/// Send a reference to [object] to any attached debuggers so they may open an
-/// inspector on the object. Returns the argument.
+/// Send a reference to [object] to any attached debuggers.
+///
+/// Debuggers may open an inspector on the object. Returns the argument.
external inspect(object);
diff --git a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
index 5fe0383..ee73b5f 100644
--- a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
+++ b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
@@ -1,3 +1,75 @@
+/**
+ * A client-side key-value store with support for indexes.
+ *
+ * Many browsers support IndexedDB—a web standard for
+ * an indexed database.
+ * By storing data on the client in an IndexedDB,
+ * a web app gets some advantages, such as faster performance and persistence.
+ * To find out which browsers support IndexedDB,
+ * refer to [Can I Use?](http://caniuse.com/#feat=indexeddb)
+ *
+ * In IndexedDB, each record is identified by a unique index or key,
+ * making data retrieval speedy.
+ * You can store structured data,
+ * such as images, arrays, and maps using IndexedDB.
+ * The standard does not specify size limits for individual data items
+ * or for the database itself, but browsers may impose storage limits.
+ *
+ * ## Using indexed_db
+ *
+ * The classes in this library provide an interface
+ * to the browser's IndexedDB, if it has one.
+ * To use this library in your code:
+ *
+ * import 'dart:indexed_db';
+ *
+ * A web app can determine if the browser supports
+ * IndexedDB with [IdbFactory.supported]:
+ *
+ * if (IdbFactory.supported)
+ * // Use indexeddb.
+ * else
+ * // Find an alternative.
+ *
+ * Access to the browser's IndexedDB is provided by the app's top-level
+ * [Window] object, which your code can refer to with `window.indexedDB`.
+ * So, for example,
+ * here's how to use window.indexedDB to open a database:
+ *
+ * Future open() {
+ * return window.indexedDB.open('myIndexedDB',
+ * version: 1,
+ * onUpgradeNeeded: _initializeDatabase)
+ * .then(_loadFromDB);
+ * }
+ * void _initializeDatabase(VersionChangeEvent e) {
+ * ...
+ * }
+ * Future _loadFromDB(Database db) {
+ * ...
+ * }
+ *
+ *
+ * All data in an IndexedDB is stored within an [ObjectStore].
+ * To manipulate the database use [Transaction]s.
+ *
+ * ## Other resources
+ *
+ * Other options for client-side data storage include:
+ *
+ * * [Window.localStorage]—a
+ * basic mechanism that stores data as a [Map],
+ * and where both the keys and the values are strings.
+ *
+ * * [dart:web_sql]—a database that can be queried with SQL.
+ *
+ * For a tutorial about using the indexed_db library with Dart,
+ * check out
+ * [Use IndexedDB](http://www.dartlang.org/docs/tutorials/indexeddb/).
+ *
+ * [IndexedDB reference](http://docs.webplatform.org/wiki/apis/indexeddb)
+ * provides wiki-style docs about indexedDB
+ */
library dart.dom.indexed_db;
import 'dart:async';
diff --git a/sdk/lib/math/math.dart b/sdk/lib/math/math.dart
index 95ed261..d167d80 100644
--- a/sdk/lib/math/math.dart
+++ b/sdk/lib/math/math.dart
@@ -220,13 +220,15 @@
/**
* Converts [x] to a double and returns the arc sine of the value.
+ *
* Returns a value in the range -PI..PI, or NaN if [x] is outside
* the range -1..1.
*/
external double asin(num x);
/**
- * Converts [x] to a dobule and returns the arc tangent of the vlaue.
+ * Converts [x] to a dobule and returns the arc tangent of the value.
+ *
* Returns a value in the range -PI/2..PI/2, or NaN if [x] is NaN.
*/
external double atan(num x);
@@ -241,12 +243,14 @@
/**
* Converts [x] to a double and returns the natural exponent, [E],
* to the power [x].
+ *
* Returns NaN if [x] is NaN.
*/
external double exp(num x);
/**
* Converts [x] to a double and returns the natural logarithm of the value.
+ *
* Returns negative infinity if [x] is equal to zero.
* Returns NaN if [x] is NaN or less than zero.
*/
diff --git a/sdk/lib/typed_data/typed_data.dart b/sdk/lib/typed_data/typed_data.dart
index 628cb2d..b04675c 100644
--- a/sdk/lib/typed_data/typed_data.dart
+++ b/sdk/lib/typed_data/typed_data.dart
@@ -10,6 +10,7 @@
/**
* A sequence of bytes underlying a typed data object.
+ *
* Used to process large quantities of binary or numerical data
* more efficiently using a typed view.
*/
@@ -403,6 +404,7 @@
* A fixed-length, random-access sequence of bytes that also provides random
* and unaligned access to the fixed-width integers and floating point
* numbers represented by those bytes.
+ *
* `ByteData` may be used to pack and unpack data from external sources
* (such as networks or files systems), and to process large quantities
* of numerical data more efficiently than would be possible
@@ -448,7 +450,9 @@
/**
* Returns the (possibly negative) integer represented by the byte at the
* specified [byteOffset] in this object, in two's complement binary
- * representation. The return value will be between -128 and 127, inclusive.
+ * representation.
+ *
+ * The return value will be between -128 and 127, inclusive.
*
* Throws [RangeError] if [byteOffset] is negative, or
* greater than or equal to the length of this object.
@@ -458,8 +462,9 @@
/**
* Sets the byte at the specified [byteOffset] in this object to the
* two's complement binary representation of the specified [value], which
- * must fit in a single byte. In other words, [value] must be between
- * -128 and 127, inclusive.
+ * must fit in a single byte.
+ *
+ * In other words, [value] must be between -128 and 127, inclusive.
*
* Throws [RangeError] if [byteOffset] is negative, or
* greater than or equal to the length of this object.
@@ -468,8 +473,9 @@
/**
* Returns the positive integer represented by the byte at the specified
- * [byteOffset] in this object, in unsigned binary form. The
- * return value will be between 0 and 255, inclusive.
+ * [byteOffset] in this object, in unsigned binary form.
+ *
+ * The return value will be between 0 and 255, inclusive.
*
* Throws [RangeError] if [byteOffset] is negative, or
* greater than or equal to the length of this object.
@@ -479,8 +485,9 @@
/**
* Sets the byte at the specified [byteOffset] in this object to the
* unsigned binary representation of the specified [value], which must fit
- * in a single byte. in other words, [value] must be between 0 and 255,
- * inclusive.
+ * in a single byte.
+ *
+ * In other words, [value] must be between 0 and 255, inclusive.
*
* Throws [RangeError] if [byteOffset] is negative,
* or greater than or equal to the length of this object.
@@ -491,6 +498,7 @@
* Returns the (possibly negative) integer represented by the two bytes at
* the specified [byteOffset] in this object, in two's complement binary
* form.
+ *
* The return value will be between 2<sup>15</sup> and 2<sup>15</sup> - 1,
* inclusive.
*
@@ -502,7 +510,9 @@
/**
* Sets the two bytes starting at the specified [byteOffset] in this
* object to the two's complement binary representation of the specified
- * [value], which must fit in two bytes. In other words, [value] must lie
+ * [value], which must fit in two bytes.
+ *
+ * In other words, [value] must lie
* between 2<sup>15</sup> and 2<sup>15</sup> - 1, inclusive.
*
* Throws [RangeError] if [byteOffset] is negative, or
@@ -516,6 +526,7 @@
* Returns the positive integer represented by the two bytes starting
* at the specified [byteOffset] in this object, in unsigned binary
* form.
+ *
* The return value will be between 0 and 2<sup>16</sup> - 1, inclusive.
*
* Throws [RangeError] if [byteOffset] is negative, or
@@ -526,7 +537,9 @@
/**
* Sets the two bytes starting at the specified [byteOffset] in this object
* to the unsigned binary representation of the specified [value],
- * which must fit in two bytes. in other words, [value] must be between
+ * which must fit in two bytes.
+ *
+ * In other words, [value] must be between
* 0 and 2<sup>16</sup> - 1, inclusive.
*
* Throws [RangeError] if [byteOffset] is negative, or
@@ -540,6 +553,7 @@
* Returns the (possibly negative) integer represented by the four bytes at
* the specified [byteOffset] in this object, in two's complement binary
* form.
+ *
* The return value will be between 2<sup>31</sup> and 2<sup>31</sup> - 1,
* inclusive.
*
@@ -551,7 +565,9 @@
/**
* Sets the four bytes starting at the specified [byteOffset] in this
* object to the two's complement binary representation of the specified
- * [value], which must fit in four bytes. In other words, [value] must lie
+ * [value], which must fit in four bytes.
+ *
+ * In other words, [value] must lie
* between 2<sup>31</sup> and 2<sup>31</sup> - 1, inclusive.
*
* Throws [RangeError] if [byteOffset] is negative, or
@@ -565,6 +581,7 @@
* Returns the positive integer represented by the four bytes starting
* at the specified [byteOffset] in this object, in unsigned binary
* form.
+ *
* The return value will be between 0 and 2<sup>32</sup> - 1, inclusive.
*
* Throws [RangeError] if [byteOffset] is negative, or
@@ -575,7 +592,9 @@
/**
* Sets the four bytes starting at the specified [byteOffset] in this object
* to the unsigned binary representation of the specified [value],
- * which must fit in four bytes. in other words, [value] must be between
+ * which must fit in four bytes.
+ *
+ * In other words, [value] must be between
* 0 and 2<sup>32</sup> - 1, inclusive.
*
* Throws [RangeError] if [byteOffset] is negative, or
@@ -589,6 +608,7 @@
* Returns the (possibly negative) integer represented by the eight bytes at
* the specified [byteOffset] in this object, in two's complement binary
* form.
+ *
* The return value will be between 2<sup>63</sup> and 2<sup>63</sup> - 1,
* inclusive.
*
@@ -600,7 +620,9 @@
/**
* Sets the eight bytes starting at the specified [byteOffset] in this
* object to the two's complement binary representation of the specified
- * [value], which must fit in eight bytes. In other words, [value] must lie
+ * [value], which must fit in eight bytes.
+ *
+ * In other words, [value] must lie
* between 2<sup>63</sup> and 2<sup>63</sup> - 1, inclusive.
*
* Throws [RangeError] if [byteOffset] is negative, or
@@ -614,6 +636,7 @@
* Returns the positive integer represented by the eight bytes starting
* at the specified [byteOffset] in this object, in unsigned binary
* form.
+ *
* The return value will be between 0 and 2<sup>64</sup> - 1, inclusive.
*
* Throws [RangeError] if [byteOffset] is negative, or
@@ -624,7 +647,9 @@
/**
* Sets the eight bytes starting at the specified [byteOffset] in this object
* to the unsigned binary representation of the specified [value],
- * which must fit in eight bytes. in other words, [value] must be between
+ * which must fit in eight bytes.
+ *
+ * In other words, [value] must be between
* 0 and 2<sup>64</sup> - 1, inclusive.
*
* Throws [RangeError] if [byteOffset] is negative, or
@@ -693,6 +718,7 @@
/**
* A fixed-length list of 8-bit signed integers.
+ *
* For long lists, this implementation can be considerably
* more space- and time-efficient than the default [List] implementation.
*/
@@ -734,6 +760,7 @@
/**
* A fixed-length list of 8-bit unsigned integers.
+ *
* For long lists, this implementation can be considerably
* more space- and time-efficient than the default [List] implementation.
*/
@@ -775,6 +802,7 @@
/**
* A fixed-length list of 8-bit unsigned integers.
+ *
* For long lists, this implementation can be considerably
* more space- and time-efficient than the default [List] implementation.
* Indexed store clamps the value to range 0..0xFF.
@@ -818,7 +846,9 @@
/**
* A fixed-length list of 16-bit signed integers that is viewable as a
- * [TypedData]. For long lists, this implementation can be considerably
+ * [TypedData].
+ *
+ * For long lists, this implementation can be considerably
* more space- and time-efficient than the default [List] implementation.
*/
abstract class Int16List implements List<int>, TypedData {
@@ -862,7 +892,9 @@
/**
* A fixed-length list of 16-bit unsigned integers that is viewable as a
- * [TypedData]. For long lists, this implementation can be considerably
+ * [TypedData].
+ *
+ * For long lists, this implementation can be considerably
* more space- and time-efficient than the default [List] implementation.
*/
abstract class Uint16List implements List<int>, TypedData {
@@ -907,7 +939,9 @@
/**
* A fixed-length list of 32-bit signed integers that is viewable as a
- * [TypedData]. For long lists, this implementation can be considerably
+ * [TypedData].
+ *
+ * For long lists, this implementation can be considerably
* more space- and time-efficient than the default [List] implementation.
*/
abstract class Int32List implements List<int>, TypedData {
@@ -951,7 +985,9 @@
/**
* A fixed-length list of 32-bit unsigned integers that is viewable as a
- * [TypedData]. For long lists, this implementation can be considerably
+ * [TypedData].
+ *
+ * For long lists, this implementation can be considerably
* more space- and time-efficient than the default [List] implementation.
*/
abstract class Uint32List implements List<int>, TypedData {
@@ -996,7 +1032,9 @@
/**
* A fixed-length list of 64-bit signed integers that is viewable as a
- * [TypedData]. For long lists, this implementation can be considerably
+ * [TypedData].
+ *
+ * For long lists, this implementation can be considerably
* more space- and time-efficient than the default [List] implementation.
*/
abstract class Int64List implements List<int>, TypedData {
@@ -1040,7 +1078,9 @@
/**
* A fixed-length list of 64-bit unsigned integers that is viewable as a
- * [TypedData]. For long lists, this implementation can be considerably
+ * [TypedData].
+ *
+ * For long lists, this implementation can be considerably
* more space- and time-efficient than the default [List] implementation.
*/
abstract class Uint64List implements List<int>, TypedData {
@@ -1085,7 +1125,9 @@
/**
* A fixed-length list of IEEE 754 single-precision binary floating-point
- * numbers that is viewable as a [TypedData]. For long lists, this
+ * numbers that is viewable as a [TypedData].
+ *
+ * For long lists, this
* implementation can be considerably more space- and time-efficient than
* the default [List] implementation.
*/
@@ -1130,7 +1172,9 @@
/**
* A fixed-length list of IEEE 754 double-precision binary floating-point
- * numbers that is viewable as a [TypedData]. For long lists, this
+ * numbers that is viewable as a [TypedData].
+ *
+ * For long lists, this
* implementation can be considerably more space- and time-efficient than
* the default [List] implementation.
*/
@@ -1175,7 +1219,9 @@
/**
* A fixed-length list of Float32x4 numbers that is viewable as a
- * [TypedData]. For long lists, this implementation will be considerably more
+ * [TypedData].
+ *
+ * For long lists, this implementation will be considerably more
* space- and time-efficient than the default [List] implementation.
*/
abstract class Float32x4List implements List<Float32x4>, TypedData {
@@ -1219,7 +1265,9 @@
/**
* A fixed-length list of Int32x4 numbers that is viewable as a
- * [TypedData]. For long lists, this implementation will be considerably more
+ * [TypedData].
+ *
+ * For long lists, this implementation will be considerably more
* space- and time-efficient than the default [List] implementation.
*/
abstract class Int32x4List implements List<Int32x4>, TypedData {
@@ -1263,7 +1311,9 @@
/**
* A fixed-length list of Float64x2 numbers that is viewable as a
- * [TypedData]. For long lists, this implementation will be considerably more
+ * [TypedData].
+ *
+ * For long lists, this implementation will be considerably more
* space- and time-efficient than the default [List] implementation.
*/
abstract class Float64x2List implements List<Float64x2>, TypedData {
@@ -1307,6 +1357,7 @@
/**
* Float32x4 immutable value type and operations.
+ *
* Float32x4 stores 4 32-bit floating point values in "lanes".
* The lanes are "x", "y", "z", and "w" respectively.
*/
@@ -1661,6 +1712,7 @@
/**
* Int32x4 and operations.
+ *
* Int32x4 stores 4 32-bit bit-masks in "lanes".
* The lanes are "x", "y", "z", and "w" respectively.
*/
@@ -1997,6 +2049,7 @@
/**
* Float64x2 immutable value type and operations.
+ *
* Float64x2 stores 2 64-bit floating point values in "lanes".
* The lanes are "x" and "y" respectively.
*/
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 97a467e..922066a 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -46,8 +46,6 @@
Language/13_Statements/04_Local_Function_Declaration_A04_t01: MissingCompileTimeError # Issue 21050
Language/13_Statements/04_Local_Function_Declaration_A04_t03: MissingCompileTimeError # Issue 21050
Language/14_Libraries_and_Scripts/1_Imports_A03_t08: fail # Issue 21171
-Language/14_Libraries_and_Scripts/1_Imports_A03_t09: fail # Issue 21171
-Language/14_Libraries_and_Scripts/1_Imports_A03_t10: fail # Issue 21171
Language/14_Libraries_and_Scripts/1_Imports_A03_t28: fail # Issue 21171
Language/15_Types/4_Interface_Types_A11_t01: crash # Issue 21174
Language/15_Types/4_Interface_Types_A11_t02: crash # Issue 21174
@@ -9606,296 +9604,299 @@
Language/12_Expressions/13_Property_Extraction_A03_t01: RuntimeError # Cannot read property 'call' of undefined
Language/12_Expressions/13_Property_Extraction_A03_t02: RuntimeError # Cannot read property 'call' of undefined
Language/12_Expressions/13_Property_Extraction_A03_t03: RuntimeError # Cannot read property 'call' of undefined
-Language/12_Expressions/13_Spawning_an_Isolate_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+Language/12_Expressions/13_Spawning_an_Isolate_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
Language/12_Expressions/15_Method_Invocation/4_Super_Invocation_A01_t01: RuntimeError # Cannot read property 'call' of undefined
Language/12_Expressions/30_Identifier_Reference_A09_t03: Crash # (i=0): For-loop variable captured in loop header
Language/13_Statements/06_For_A01_t07: Crash # unsupported operation on erroneous element
Language/13_Statements/12_Labels_A03_t04: Crash # (switch (i){L:case 0:flag=true;break;case 2:continue L;}): continue to a labeled switch case
Language/13_Statements/14_Continue_A02_t12: Crash # (switch (2){L:case 1:flag=true;break;case 2:continue L;}): continue to a labeled switch case
Language/13_Statements/14_Continue_A02_t13: Crash # (switch (2){case 2:continue L;L:case 1:flag=true;}): continue to a labeled switch case
-Language/14_Libraries_and_Scripts/4_Scripts_A03_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Completer/Completer.sync_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Completer/completeError_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Completer/completeError_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Completer/completeError_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Completer/completeError_A01_t04: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Completer/completeError_A03_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Completer/completeError_A03_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Completer/complete_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Completer/complete_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Completer/complete_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Completer/complete_A01_t04: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Completer/complete_A01_t05: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Completer/complete_A01_t06: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Completer/complete_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Completer/complete_A02_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Completer/isCompleted_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/DeferredLibrary/DeferredLibrary_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/Future.delayed_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/Future.delayed_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/Future.delayed_A03_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/Future.error_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/Future.microtask_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/Future.microtask_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/Future.microtask_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/Future.microtask_A01_t04: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/Future.sync_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/Future.sync_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/Future.sync_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/Future.sync_A01_t04: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/Future.value_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/Future.value_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/Future_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/Future_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/Future_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/Future_A01_t04: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/asStream_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/asStream_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/asStream_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/asStream_A02_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/catchError_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/catchError_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/catchError_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/catchError_A03_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/catchError_A03_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/catchError_A03_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/catchError_A03_t04: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/catchError_A03_t05: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/forEach_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/forEach_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/forEach_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/then_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/then_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/then_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/then_A01_t04: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/then_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/then_A03_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/then_A03_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/then_A04_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/then_A05_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/then_A05_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/then_A05_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/wait_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/wait_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/wait_A01_t04: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/wait_A01_t05: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/wait_A01_t06: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/wait_A01_t07: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/wait_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/wait_A02_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/whenComplete_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/whenComplete_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/whenComplete_A03_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/whenComplete_A04_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/whenComplete_A04_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/Stream.eventTransformed_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/Stream.eventTransformed_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/Stream.fromFuture_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/Stream.fromFuture_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/Stream.fromFuture_A02_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/Stream.fromIterable_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/Stream.fromIterable_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/Stream.fromIterable_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/Stream.periodic_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/Stream.periodic_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/Stream.periodic_A03_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/Stream_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/any_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/any_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/any_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/asBroadcastStream_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/asBroadcastStream_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/asBroadcastStream_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/asBroadcastStream_A01_t04: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/asBroadcastStream_A03_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/asBroadcastStream_A03_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/asBroadcastStream_A03_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/asBroadcastStream_A04_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/asBroadcastStream_A04_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/asBroadcastStream_A04_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/contains_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/contains_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/contains_A03_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/distinct_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/distinct_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/drain_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/drain_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/drain_A02_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/elementAt_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/elementAt_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/elementAt_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/elementAt_A03_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/every_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/every_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/expand_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/firstWhere_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/firstWhere_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/firstWhere_A03_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/firstWhere_A03_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/first_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/first_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/first_A02_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/first_A03_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/fold_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/fold_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/forEach_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/forEach_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/forEach_A02_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/handleError_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/handleError_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/handleError_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/handleError_A04_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/handleError_A04_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/handleError_A04_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/isBroadcast_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/isBroadcast_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/isEmpty_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/join_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/join_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/join_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/join_A02_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/lastWhere_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/lastWhere_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/lastWhere_A03_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/lastWhere_A04_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/last_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/last_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/last_A03_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/length_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/listen_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/listen_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/listen_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/listen_A04_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/listen_A05_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/listen_A05_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/listen_A05_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/listen_A06_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/map_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/pipe_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/reduce_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/reduce_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/reduce_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/singleWhere_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/singleWhere_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/single_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/single_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/skipWhile_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/skip_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/takeWhile_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/take_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/take_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/take_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/toList_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/toSet_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/transform_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/transform_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/where_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/where_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/StreamController.broadcast_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/StreamController.broadcast_A03_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/StreamController.broadcast_A04_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/StreamController.broadcast_A05_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/StreamController.broadcast_A06_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/StreamController.broadcast_A07_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/StreamController.broadcast_A07_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/StreamController.broadcast_A08_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/StreamController_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/StreamController_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/StreamController_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/StreamController_A04_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/StreamController_A05_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/StreamController_A06_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/StreamController_A06_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/addError_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/addError_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/addStream_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/addStream_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/addStream_A02_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/addStream_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/addStream_A03_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/add_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/close_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/close_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/done_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/done_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/done_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/hasListener_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/hasListener_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/isClosed_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/isClosed_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/isPaused_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/isPaused_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/isPaused_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/sink_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamController/stream_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamIterator/StreamIterator_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamIterator/cancel_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamIterator/current_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamIterator/moveNext_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamIterator/moveNext_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamSink/addError_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamSink/addStream_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamSink/addStream_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamSink/addStream_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamSink/addStream_A01_t04: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamSink/addStream_A01_t05: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamSink/add_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamSink/close_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamSink/done_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamTransformer/StreamTransformer.fromHandlers_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamTransformer/StreamTransformer.fromHandlers_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamTransformer/StreamTransformer.fromHandlers_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamTransformer/StreamTransformer.fromHandlers_A01_t04: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamTransformer/StreamTransformer_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamTransformer/StreamTransformer_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamTransformer/StreamTransformer_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamTransformer/StreamTransformer_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamTransformer/StreamTransformer_A02_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamTransformer/StreamTransformer_A03_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/StreamTransformer/StreamTransformer_A03_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamTransformer/bind_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Timer/Timer.periodic_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Timer/Timer.periodic_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Timer/Timer_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Timer/Timer_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Timer/cancel_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Timer/isActive_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Timer/isActive_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Timer/run_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Timer/run_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/bindBinaryCallback_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/bindBinaryCallback_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/bindCallback_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/bindCallback_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/bindUnaryCallback_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/bindUnaryCallback_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/createPeriodicTimer_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/createTimer_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/current_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/current_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/fork_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/handleUncaughtError_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/handleUncaughtError_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/handleUncaughtError_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Zone/handleUncaughtError_A01_t04: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/inSameErrorZone_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/inSameErrorZone_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/inSameErrorZone_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/inSameErrorZone_A01_t04: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/inSameErrorZone_A01_t05: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/operator_subscript_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Zone/parent_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/registerBinaryCallback_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/registerCallback_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/registerUnaryCallback_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/runBinaryGuarded_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/runBinary_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/runGuarded_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/runUnaryGuarded_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/runUnary_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/run_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/scheduleMicrotask_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/scheduleMicrotask_A01_t02: RuntimeError # receiver.get$_nums is not a function
+Language/14_Libraries_and_Scripts/13_Libraries_and_Scripts_A05_t04: Crash # The null object does not have a getter 'name'.
+Language/14_Libraries_and_Scripts/4_Scripts_A03_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LayoutTests/fast/canvas/webgl/framebuffer-object-attachment_t01: Crash # The null object does not have a getter 'name'.
+LayoutTests/fast/canvas/webgl/webgl-specific_t01: Crash # The null object does not have a getter 'name'.
+LibTest/async/Completer/Completer.sync_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Completer/completeError_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Completer/completeError_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Completer/completeError_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Completer/completeError_A01_t04: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Completer/completeError_A03_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Completer/completeError_A03_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Completer/complete_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Completer/complete_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Completer/complete_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Completer/complete_A01_t04: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Completer/complete_A01_t05: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Completer/complete_A01_t06: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Completer/complete_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Completer/complete_A02_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Completer/isCompleted_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/DeferredLibrary/DeferredLibrary_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/Future.delayed_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/Future.delayed_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/Future.delayed_A03_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/Future.error_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/Future.microtask_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/Future.microtask_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/Future.microtask_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/Future.microtask_A01_t04: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/Future.sync_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/Future.sync_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/Future.sync_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/Future.sync_A01_t04: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/Future.value_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/Future.value_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/Future_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/Future_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/Future_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/Future_A01_t04: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/asStream_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/asStream_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/asStream_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/asStream_A02_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/catchError_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/catchError_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/catchError_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/catchError_A03_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/catchError_A03_t02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Future/catchError_A03_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/catchError_A03_t04: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/catchError_A03_t05: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/forEach_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/forEach_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/forEach_A03_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Future/then_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/then_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/then_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/then_A01_t04: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/then_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/then_A03_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/then_A03_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/then_A04_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/then_A05_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/then_A05_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/then_A05_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/wait_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Future/wait_A01_t03: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Future/wait_A01_t04: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Future/wait_A01_t05: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Future/wait_A01_t06: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Future/wait_A01_t07: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Future/wait_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/wait_A02_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/whenComplete_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/whenComplete_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/whenComplete_A03_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/whenComplete_A04_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Future/whenComplete_A04_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/Stream.eventTransformed_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Stream/Stream.eventTransformed_A01_t02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Stream/Stream.fromFuture_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/Stream.fromFuture_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/Stream.fromFuture_A02_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/Stream.fromIterable_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/Stream.fromIterable_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/Stream.fromIterable_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/Stream.periodic_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/Stream.periodic_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/Stream.periodic_A03_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/Stream_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/any_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/any_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/any_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/asBroadcastStream_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Stream/asBroadcastStream_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/asBroadcastStream_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/asBroadcastStream_A01_t04: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/asBroadcastStream_A03_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/asBroadcastStream_A03_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/asBroadcastStream_A03_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/asBroadcastStream_A04_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/asBroadcastStream_A04_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/asBroadcastStream_A04_t03: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Stream/contains_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/contains_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/contains_A03_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/distinct_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/distinct_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/drain_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/drain_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/drain_A02_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/elementAt_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/elementAt_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/elementAt_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/elementAt_A03_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/every_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/every_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/expand_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Stream/firstWhere_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/firstWhere_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/firstWhere_A03_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/firstWhere_A03_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/first_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/first_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/first_A02_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/first_A03_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/fold_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/fold_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/forEach_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Stream/forEach_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/forEach_A02_t02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Stream/handleError_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Stream/handleError_A02_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Stream/handleError_A03_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Stream/handleError_A04_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/handleError_A04_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/handleError_A04_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/isBroadcast_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/isBroadcast_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/isEmpty_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/join_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/join_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/join_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/join_A02_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/lastWhere_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/lastWhere_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/lastWhere_A03_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/lastWhere_A04_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/last_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/last_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/last_A03_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/length_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/listen_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Stream/listen_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/listen_A03_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Stream/listen_A04_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/listen_A05_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/listen_A05_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/listen_A05_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/listen_A06_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/map_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Stream/pipe_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Stream/reduce_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/reduce_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/reduce_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/singleWhere_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/singleWhere_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/single_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/single_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/skipWhile_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/skip_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/takeWhile_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/take_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/take_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/take_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/toList_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Stream/toSet_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/transform_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Stream/transform_A01_t02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Stream/where_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Stream/where_A01_t02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/StreamController/StreamController.broadcast_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/StreamController/StreamController.broadcast_A03_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/StreamController.broadcast_A04_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/StreamController.broadcast_A05_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/StreamController.broadcast_A06_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/StreamController.broadcast_A07_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/StreamController.broadcast_A07_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/StreamController.broadcast_A08_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/StreamController_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/StreamController_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/StreamController_A03_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/StreamController/StreamController_A04_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/StreamController_A05_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/StreamController_A06_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/StreamController_A06_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/addError_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/addError_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/addStream_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/StreamController/addStream_A02_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/StreamController/addStream_A02_t02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/StreamController/addStream_A03_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/StreamController/addStream_A03_t02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/StreamController/add_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/close_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/close_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/done_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/done_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/done_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/hasListener_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/hasListener_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/isClosed_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/isClosed_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/isPaused_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/isPaused_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/isPaused_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/sink_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamController/stream_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamIterator/StreamIterator_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamIterator/cancel_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/StreamIterator/current_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamIterator/moveNext_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamIterator/moveNext_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamSink/addError_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamSink/addStream_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/StreamSink/addStream_A01_t02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/StreamSink/addStream_A01_t03: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/StreamSink/addStream_A01_t04: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamSink/addStream_A01_t05: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/StreamSink/add_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/StreamSink/close_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/StreamSink/done_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/StreamTransformer/StreamTransformer.fromHandlers_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamTransformer/StreamTransformer.fromHandlers_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamTransformer/StreamTransformer.fromHandlers_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamTransformer/StreamTransformer.fromHandlers_A01_t04: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/StreamTransformer/StreamTransformer_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamTransformer/StreamTransformer_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamTransformer/StreamTransformer_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamTransformer/StreamTransformer_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamTransformer/StreamTransformer_A02_t02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/StreamTransformer/StreamTransformer_A03_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/StreamTransformer/StreamTransformer_A03_t02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/StreamTransformer/bind_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Timer/Timer.periodic_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Timer/Timer.periodic_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Timer/Timer_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Timer/Timer_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Timer/cancel_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Timer/isActive_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Timer/isActive_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Timer/run_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Timer/run_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/bindBinaryCallback_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/bindBinaryCallback_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/bindCallback_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/bindCallback_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/bindUnaryCallback_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/bindUnaryCallback_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/createPeriodicTimer_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/createTimer_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/current_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/current_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/fork_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/handleUncaughtError_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/handleUncaughtError_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/handleUncaughtError_A01_t03: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Zone/handleUncaughtError_A01_t04: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/inSameErrorZone_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/inSameErrorZone_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/inSameErrorZone_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/inSameErrorZone_A01_t04: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/inSameErrorZone_A01_t05: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/operator_subscript_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/async/Zone/parent_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/registerBinaryCallback_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/registerCallback_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/registerUnaryCallback_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/runBinaryGuarded_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/runBinary_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/runGuarded_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/runUnaryGuarded_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/runUnary_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/run_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/scheduleMicrotask_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/async/Zone/scheduleMicrotask_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
LibTest/collection/ListBase/ListBase_class_A01_t02: Crash # Stack Overflow
LibTest/collection/ListMixin/ListMixin_class_A01_t02: Crash # Stack Overflow
LibTest/core/Invocation/isAccessor_A01_t01: Crash # Class 'PartialMethodElement' has no instance getter 'initializer'.
@@ -9908,108 +9909,108 @@
LibTest/core/Invocation/namedArguments_A01_t01: RuntimeError # Please triage this failure.
LibTest/core/Invocation/positionalArguments_A01_t01: RuntimeError # Please triage this failure.
LibTest/core/List/List_class_A01_t02: Crash # Stack Overflow
-LibTest/core/Stopwatch/elapsedInMs_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/core/Stopwatch/elapsedInUs_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/core/Stopwatch/elapsedTicks_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/core/Stopwatch/elapsedTicks_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/core/Stopwatch/elapsedTicks_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/core/Stopwatch/elapsed_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/core/Stopwatch/elapsed_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/core/Stopwatch/elapsed_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/core/Stopwatch/start_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/core/Stopwatch/start_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/core/Stopwatch/start_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/core/Stopwatch/stop_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/core/Stopwatch/elapsedInMs_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/core/Stopwatch/elapsedInUs_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/core/Stopwatch/elapsedTicks_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/core/Stopwatch/elapsedTicks_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/core/Stopwatch/elapsedTicks_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/core/Stopwatch/elapsed_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/core/Stopwatch/elapsed_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/core/Stopwatch/elapsed_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/core/Stopwatch/start_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/core/Stopwatch/start_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/core/Stopwatch/start_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/core/Stopwatch/stop_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
LibTest/core/Symbol/Symbol_A01_t03: RuntimeError # Please triage this failure.
LibTest/core/Symbol/Symbol_A01_t05: RuntimeError # Please triage this failure.
LibTest/core/double/INFINITY_A01_t04: Pass # Please triage this failure.
LibTest/core/double/NEGATIVE_INFINITY_A01_t04: Pass # Please triage this failure.
-LibTest/isolate/Isolate/spawnUri_A02_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/Isolate/spawnUri_A02_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/Isolate/spawnUri_A02_t04: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/Isolate/spawn_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/Isolate/spawn_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/Isolate/spawn_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/Isolate/spawn_A01_t04: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/Isolate/spawn_A01_t05: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/Isolate/spawn_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/RawReceivePort/RawReceivePort_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/RawReceivePort/RawReceivePort_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/RawReceivePort/close_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/RawReceivePort/handler_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/RawReceivePort/sendPort_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/ReceivePort.fromRawReceivePort_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/ReceivePort.fromRawReceivePort_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/ReceivePort_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/any_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/any_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/asBroadcastStream_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/asBroadcastStream_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/asBroadcastStream_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/asBroadcastStream_A01_t04: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/asBroadcastStream_A03_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/asBroadcastStream_A03_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/asBroadcastStream_A03_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/asBroadcastStream_A04_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/asBroadcastStream_A04_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/asBroadcastStream_A04_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/close_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/close_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/contains_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/distinct_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/distinct_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/drain_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/drain_A02_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/elementAt_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/elementAt_A03_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/every_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/expand_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/firstWhere_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/firstWhere_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/firstWhere_A03_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/first_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/first_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/first_A02_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/fold_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/fold_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/forEach_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/isBroadcast_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/isBroadcast_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/isEmpty_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/join_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/join_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/lastWhere_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/lastWhere_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/lastWhere_A04_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/last_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/last_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/length_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/listen_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/map_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/pipe_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/reduce_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/reduce_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/reduce_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/singleWhere_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/singleWhere_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/single_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/single_A02_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/skipWhile_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/skip_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/takeWhile_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/take_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/take_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/take_A01_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/toList_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/toSet_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/transform_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/transform_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/where_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/where_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/SendPort/hashCode_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/SendPort/operator_equality_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/SendPort/send_A01_t04: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/SendPort/send_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/isolate/Isolate/spawnUri_A02_t02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/Isolate/spawnUri_A02_t03: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/Isolate/spawnUri_A02_t04: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/Isolate/spawn_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/Isolate/spawn_A01_t02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/Isolate/spawn_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/Isolate/spawn_A01_t04: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/Isolate/spawn_A01_t05: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/Isolate/spawn_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/RawReceivePort/RawReceivePort_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/RawReceivePort/RawReceivePort_A01_t02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/RawReceivePort/close_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/RawReceivePort/handler_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/RawReceivePort/sendPort_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/ReceivePort.fromRawReceivePort_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/ReceivePort.fromRawReceivePort_A02_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/ReceivePort_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/any_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/any_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/asBroadcastStream_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/asBroadcastStream_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/asBroadcastStream_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/asBroadcastStream_A01_t04: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/asBroadcastStream_A03_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/asBroadcastStream_A03_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/asBroadcastStream_A03_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/asBroadcastStream_A04_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/asBroadcastStream_A04_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/asBroadcastStream_A04_t03: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/close_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/close_A02_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/contains_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/distinct_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/distinct_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/drain_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/drain_A02_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/elementAt_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/elementAt_A03_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/every_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/expand_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/firstWhere_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/firstWhere_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/firstWhere_A03_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/first_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/first_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/first_A02_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/fold_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/fold_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/forEach_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/isBroadcast_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/isBroadcast_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/isEmpty_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/join_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/join_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/lastWhere_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/lastWhere_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/lastWhere_A04_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/last_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/last_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/length_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/listen_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/map_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/pipe_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/reduce_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/reduce_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/reduce_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/singleWhere_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/singleWhere_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/single_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/single_A02_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/skipWhile_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/skip_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/takeWhile_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/take_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/take_A01_t02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/take_A01_t03: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/toList_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/toSet_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/transform_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/transform_A01_t02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/where_A01_t01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+LibTest/isolate/ReceivePort/where_A01_t02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/SendPort/hashCode_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/SendPort/operator_equality_A01_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/SendPort/send_A01_t04: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+LibTest/isolate/SendPort/send_A02_t01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
LibTest/typed_data/Float32List/setAll_A01_t01: RuntimeError # this.get$length is not a function
LibTest/typed_data/Float32List/setRange_A01_t01: RuntimeError # this.get$length is not a function
LibTest/typed_data/Float32List/setRange_A02_t01: RuntimeError # this.get$length is not a function
diff --git a/tests/compiler/dart2js/backend_dart/sexpr_unstringifier.dart b/tests/compiler/dart2js/backend_dart/sexpr_unstringifier.dart
index 809aa99..8b7b7cd 100644
--- a/tests/compiler/dart2js/backend_dart/sexpr_unstringifier.dart
+++ b/tests/compiler/dart2js/backend_dart/sexpr_unstringifier.dart
@@ -150,6 +150,9 @@
static const String GET_STATIC = "GetStatic";
static const String TYPE_TEST = "TypeTest";
static const String APPLY_BUILTIN_OPERATOR = "ApplyBuiltinOperator";
+ static const String GET_LENGTH = "GetLength";
+ static const String GET_INDEX = "GetIndex";
+ static const String SET_INDEX = "SetIndex";
// Other
static const String FUNCTION_DEFINITION = "FunctionDefinition";
@@ -610,6 +613,33 @@
return new ApplyBuiltinOperator(operator, arguments);
}
+ /// (GetLength object)
+ GetLength parseGetLength() {
+ tokens.consumeStart(GET_LENGTH);
+ Primitive object = name2variable[tokens.read()];
+ tokens.consumeEnd();
+ return new GetLength(object);
+ }
+
+ /// (GetIndex object index)
+ GetIndex parseGetIndex() {
+ tokens.consumeStart(GET_INDEX);
+ Primitive object = name2variable[tokens.read()];
+ Primitive index = name2variable[tokens.read()];
+ tokens.consumeEnd();
+ return new GetIndex(object, index);
+ }
+
+ /// (SetIndex object index value)
+ SetIndex parseSetIndex() {
+ tokens.consumeStart(SET_INDEX);
+ Primitive object = name2variable[tokens.read()];
+ Primitive index = name2variable[tokens.read()];
+ Primitive value = name2variable[tokens.read()];
+ tokens.consumeEnd();
+ return new SetIndex(object, index, value);
+ }
+
/// (SetStatic field value body)
SetStatic parseSetStatic() {
tokens.consumeStart(SET_STATIC);
@@ -684,6 +714,12 @@
return parseTypeTest();
case APPLY_BUILTIN_OPERATOR:
return parseApplyBuiltinOperator();
+ case GET_LENGTH:
+ return parseGetLength();
+ case GET_INDEX:
+ return parseGetIndex();
+ case SET_INDEX:
+ return parseSetIndex();
default:
assert(false);
}
diff --git a/tests/compiler/dart2js/dart2js.status b/tests/compiler/dart2js/dart2js.status
index 82511ce..096a7bc 100644
--- a/tests/compiler/dart2js/dart2js.status
+++ b/tests/compiler/dart2js/dart2js.status
@@ -45,6 +45,7 @@
# These tests run the compiler multiple times.
js_backend_cps_ir_basic_test: Pass, Slow
js_backend_cps_ir_closures_test: Pass, Slow
+js_backend_cps_ir_constructor_test: Pass, Slow
[ $unchecked ]
exit_code_test: Skip # This tests requires checked mode.
diff --git a/tests/compiler/dart2js/deferred_load_graph_segmentation_test.dart b/tests/compiler/dart2js/deferred_load_graph_segmentation_test.dart
index 1927db0..a3624f0 100644
--- a/tests/compiler/dart2js/deferred_load_graph_segmentation_test.dart
+++ b/tests/compiler/dart2js/deferred_load_graph_segmentation_test.dart
@@ -61,7 +61,6 @@
var lib4 = lookupLibrary("memory:lib4.dart");
var bar1 = lib4.find("bar1");
var bar2 = lib4.find("bar2");
- var outputClassLists = backend.emitter.outputClassLists;
OutputUnit ou_lib1 = outputUnitForElement(foo1);
OutputUnit ou_lib2 = outputUnitForElement(foo2);
diff --git a/tests/compiler/dart2js/deferred_not_in_main_test.dart b/tests/compiler/dart2js/deferred_not_in_main_test.dart
index 9999881..a4b8435 100644
--- a/tests/compiler/dart2js/deferred_not_in_main_test.dart
+++ b/tests/compiler/dart2js/deferred_not_in_main_test.dart
@@ -51,8 +51,6 @@
var foo1 = lib1.find("foo1");
var foo2 = lib2.find("foo2");
- var outputClassLists = backend.emitter.outputClassLists;
-
Expect.notEquals(mainOutputUnit, outputUnitForElement(foo2));
}));
}
diff --git a/tests/compiler/dart2js/diagnose_ambiguous_test.dart b/tests/compiler/dart2js/diagnose_ambiguous_test.dart
index c6b3061..d70c8e4 100644
--- a/tests/compiler/dart2js/diagnose_ambiguous_test.dart
+++ b/tests/compiler/dart2js/diagnose_ambiguous_test.dart
@@ -29,7 +29,7 @@
diagnosticHandler,
libraryRoot,
packageRoot,
- ['--analyze-only'],
+ ['--analyze-all'],
{});
asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
diagnostics.sort();
@@ -38,10 +38,10 @@
"memory:library.dart:41:45:'hest' is defined here.:info",
"memory:main.dart:0:22:'hest' is imported here.:info",
"memory:main.dart:23:46:'hest' is imported here.:info",
- "memory:main.dart:86:92:Duplicate import of 'hest'.:error"
+ "memory:main.dart:86:92:Duplicate import of 'hest'.:warning",
];
Expect.listEquals(expected, diagnostics);
- Expect.isTrue(compiler.compilationFailed);
+ Expect.isFalse(compiler.compilationFailed);
}));
}
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_control_flow_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_control_flow_test.dart
index b16a1a8..adf8db7 100644
--- a/tests/compiler/dart2js/js_backend_cps_ir_control_flow_test.dart
+++ b/tests/compiler/dart2js/js_backend_cps_ir_control_flow_test.dart
@@ -57,13 +57,12 @@
}""", """
function() {
var i = 0;
- L2:
- while (P.identical(V.foo(true), true)) {
- P.print(1);
- if (P.identical(V.foo(false), true))
- break L2;
- i = V.foo(i);
- }
+ while (P.identical(V.foo(true), true)) {
+ P.print(1);
+ if (P.identical(V.foo(false), true))
+ break;
+ i = V.foo(i);
+ }
P.print(2);
}"""),
const TestEntry("""
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_interceptors_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_interceptors_test.dart
index 60f9717..374b751 100644
--- a/tests/compiler/dart2js/js_backend_cps_ir_interceptors_test.dart
+++ b/tests/compiler/dart2js/js_backend_cps_ir_interceptors_test.dart
@@ -34,9 +34,11 @@
r"""
function() {
var l = ["hest", ["h", "e", "s", "t"]], i = 0, x, j;
- P.print(J.getInterceptor$as(l).get$length(l));
- while (i < J.getInterceptor$as(l).get$length(l)) {
- x = J.getInterceptor$as(l).$index(l, i);
+ P.print(l.length);
+ while (i < l.length) {
+ if (i < 0 || i >= l.length)
+ H.ioore(l, i);
+ x = l[i];
j = 0;
while (j < J.getInterceptor$as(x).get$length(x)) {
P.print(J.getInterceptor$as(x).$index(x, j));
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_operators_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_operators_test.dart
index 577dca0..138e684 100644
--- a/tests/compiler/dart2js/js_backend_cps_ir_operators_test.dart
+++ b/tests/compiler/dart2js/js_backend_cps_ir_operators_test.dart
@@ -14,17 +14,16 @@
foo() => foo();
main() {
print(foo() ? "hello world" : "bad bad");
-}""",
-"""function() {
- V.foo();
- P.print("bad bad");
+}""","""
+function() {
+ P.print(V.foo() ? "hello world" : "bad bad");
}"""),
const TestEntry("""
foo() => null;
main() {
print(foo() ? "hello world" : "bad bad");
-}""",
-"""function() {
+}""","""
+function() {
V.foo();
P.print("bad bad");
}"""),
@@ -32,25 +31,23 @@
get foo => foo;
main() {
print(foo ? "hello world" : "bad bad");
-}""",
-"""function() {
- V.foo();
- P.print("bad bad");
+}""","""
+function() {
+ P.print(V.foo() ? "hello world" : "bad bad");
}"""),
const TestEntry("""
get foo => foo;
-main() { print(foo && foo); }""",
-"""function() {
- V.foo();
- P.print(false);
+main() { print(foo && foo); }
+""", """
+function() {
+ P.print(V.foo() ? !!P.identical(V.foo(), true) : false);
}"""),
const TestEntry("""
get foo => foo;
-main() { print(foo || foo); }""",
-"""function() {
- V.foo();
- V.foo();
- P.print(false);
+main() { print(foo || foo); }
+""","""
+function() {
+ P.print(V.foo() ? true : !!P.identical(V.foo(), true));
}"""),
// Needs interceptor calling convention
@@ -76,8 +73,10 @@
print(list);
}""", r"""
function() {
- var list = [1, 2, 3];
- J.getInterceptor$a(list).$indexSet(list, 1, 6);
+ var list = [1, 2, 3], v0 = 1;
+ if (v0 < 0 || v0 >= list.length)
+ H.ioore(list, v0);
+ list[v0] = 6;
P.print(list);
}"""),
];
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_supercall_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_supercall_test.dart
index 332af73..7d9283e 100644
--- a/tests/compiler/dart2js/js_backend_cps_ir_supercall_test.dart
+++ b/tests/compiler/dart2js/js_backend_cps_ir_supercall_test.dart
@@ -53,7 +53,7 @@
const TestEntry.forMethod('function(Sub#m)', """
class Base {
- var field;
+ var field = 123;
}
class Sub extends Base {
m(x) => x + super.field;
@@ -63,7 +63,7 @@
}""",
r"""
function(x) {
- return J.getInterceptor$ns(x).$add(x, this.field);
+ return x + this.field;
}"""),
diff --git a/tests/compiler/dart2js/mirrors_used_test.dart b/tests/compiler/dart2js/mirrors_used_test.dart
index 3b2bb39..e79df96 100644
--- a/tests/compiler/dart2js/mirrors_used_test.dart
+++ b/tests/compiler/dart2js/mirrors_used_test.dart
@@ -26,6 +26,9 @@
import 'package:compiler/src/js_backend/js_backend.dart' show
JavaScriptBackend;
+import 'package:compiler/src/js_emitter/full_emitter/emitter.dart'
+ as full show Emitter;
+
void expectOnlyVerboseInfo(Uri uri, int begin, int end, String message, kind) {
if (kind.name == 'verbose info') {
print(message);
@@ -89,10 +92,13 @@
expectedNames = expectedNames.map(backend.namer.asName).toList();
expectedNames.addAll(nativeNames);
+ // Mirrors only work in the full emitter. We can thus be certain that the
+ // emitter is the full emitter.
+ full.Emitter fullEmitter = backend.emitter.emitter;
Set recordedNames = new Set()
- ..addAll(backend.emitter.oldEmitter.recordedMangledNames)
- ..addAll(backend.emitter.oldEmitter.mangledFieldNames.keys)
- ..addAll(backend.emitter.oldEmitter.mangledGlobalFieldNames.keys);
+ ..addAll(fullEmitter.recordedMangledNames)
+ ..addAll(fullEmitter.mangledFieldNames.keys)
+ ..addAll(fullEmitter.mangledGlobalFieldNames.keys);
Expect.setEquals(new Set.from(expectedNames), recordedNames);
for (var library in compiler.libraryLoader.libraries) {
diff --git a/tests/compiler/dart2js/parser_helper.dart b/tests/compiler/dart2js/parser_helper.dart
index acd2c030..ad7550c 100644
--- a/tests/compiler/dart2js/parser_helper.dart
+++ b/tests/compiler/dart2js/parser_helper.dart
@@ -65,7 +65,7 @@
}
Token scan(String text) =>
- new StringScanner.fromString(text, enableNullAwareOperators: true)
+ new StringScanner.fromString(text)
.tokenize();
Node parseBodyCode(String text, Function parseMethod,
diff --git a/tests/compiler/dart2js/semantic_visitor_test_send_data.dart b/tests/compiler/dart2js/semantic_visitor_test_send_data.dart
index 514aa2a..7ffca23 100644
--- a/tests/compiler/dart2js/semantic_visitor_test_send_data.dart
+++ b/tests/compiler/dart2js/semantic_visitor_test_send_data.dart
@@ -749,7 +749,6 @@
''',
const Visit(VisitKind.VISIT_TOP_LEVEL_GETTER_GET,
element: 'getter(o)')),
- // TODO(johnniwinther): Expect [VISIT_TOP_LEVEL_SETTER_GET] instead.
const Test(
'''
set o(_) {}
@@ -764,8 +763,8 @@
'''
m() => p.o;
''',
- const Visit(VisitKind.VISIT_UNRESOLVED_GET,
- name: 'o')),
+ const Visit(VisitKind.VISIT_TOP_LEVEL_SETTER_GET,
+ element: 'setter(o)')),
// TODO(johnniwinther): Expect [VISIT_TOP_LEVEL_GETTER_SET] instead.
const Test(
'''
@@ -815,7 +814,6 @@
const Visit(VisitKind.VISIT_TOP_LEVEL_GETTER_INVOKE,
element: 'getter(o)',
arguments: '(null,42)')),
- // TODO(johnniwinther): Expected [VISIT_TOP_LEVEL_SETTER_INVOKE] instead.
const Test(
'''
set o(_) {}
@@ -829,8 +827,8 @@
set o(_) {}
''',
'm() { p.o(null, 42); }',
- const Visit(VisitKind.VISIT_UNRESOLVED_INVOKE,
- name: 'o',
+ const Visit(VisitKind.VISIT_TOP_LEVEL_SETTER_INVOKE,
+ element: 'setter(o)',
arguments: '(null,42)')),
],
'Top level functions': const [
diff --git a/tests/compiler/dart2js/source_mapping_test.dart b/tests/compiler/dart2js/source_mapping_test.dart
index a54caac..9c350f6 100644
--- a/tests/compiler/dart2js/source_mapping_test.dart
+++ b/tests/compiler/dart2js/source_mapping_test.dart
@@ -10,6 +10,9 @@
import 'package:compiler/src/io/source_information.dart';
import "mock_compiler.dart";
import 'package:compiler/src/js_backend/js_backend.dart';
+import 'package:compiler/src/js_emitter/js_emitter.dart';
+import 'package:compiler/src/js_emitter/full_emitter/emitter.dart'
+ as full show Emitter;
Future<CodeBuffer> compileAll(SourceFile sourceFile) {
MockCompiler compiler = new MockCompiler.internal();
@@ -17,7 +20,10 @@
compiler.sourceFiles[uri.toString()] = sourceFile;
JavaScriptBackend backend = compiler.backend;
return compiler.runCompiler(uri).then((_) {
- return backend.emitter.oldEmitter
+ // TODO(floitsch): the outputBuffers are only accessible in the full
+ // emitter.
+ full.Emitter fullEmitter = backend.emitter.emitter;
+ return fullEmitter
.outputBuffers[compiler.deferredLoadTask.mainOutputUnit];
});
}
diff --git a/tests/compiler/dart2js/sourcemaps/invokes_test_file.dart b/tests/compiler/dart2js/sourcemaps/invokes_test_file.dart
index 9c06550..83a5ef3 100644
--- a/tests/compiler/dart2js/sourcemaps/invokes_test_file.dart
+++ b/tests/compiler/dart2js/sourcemaps/invokes_test_file.dart
@@ -36,6 +36,7 @@
parameter();
localVariable();
localFunction();
+ (parameter)();
parameter.dynamicInvoke();
new C(parameter).instanceInvokes();
diff --git a/tests/compiler/dart2js/sourcemaps/source_mapping_test.dart b/tests/compiler/dart2js/sourcemaps/source_mapping_test.dart
index 831299f..551bf40 100644
--- a/tests/compiler/dart2js/sourcemaps/source_mapping_test.dart
+++ b/tests/compiler/dart2js/sourcemaps/source_mapping_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'dart:async';
import 'package:async_helper/async_helper.dart';
import 'package:expect/expect.dart';
import 'sourcemap_helper.dart';
@@ -10,42 +11,134 @@
main(List<String> arguments) {
bool showAll = false;
+ bool measure = false;
Uri outputUri;
- if (arguments.isNotEmpty) {
- outputUri = Uri.base.resolve(nativeToUriPath(arguments.last));
- showAll = arguments.contains('-a');
+ Set<String> configurations = new Set<String>();
+ for (String argument in arguments) {
+ if (argument.startsWith('-')) {
+ if (argument == '-a') {
+ /// Generate visualization for all user methods.
+ showAll = true;
+ } else if (argument == '-m') {
+ /// Measure instead of reporting the number of missing code points.
+ measure = true;
+ } else if (argument.startsWith('--out=')) {
+ /// Generate visualization for the first configuration.
+ outputUri = Uri.base.resolve(
+ nativeToUriPath(argument.substring('--out='.length)));
+ } else if (argument.startsWith('-o')) {
+ /// Generate visualization for the first configuration.
+ outputUri = Uri.base.resolve(
+ nativeToUriPath(argument.substring('-o'.length)));
+ } else {
+ print("Unknown option '$argument'.");
+ return;
+ }
+ } else {
+ if (TEST_CONFIGURATIONS.containsKey(argument)) {
+ configurations.add(argument);
+ } else {
+ print("Unknown configuration '$argument'. "
+ "Must be one of '${TEST_CONFIGURATIONS.keys.join("', '")}'");
+ return;
+ }
+ }
}
+
+ if (configurations.isEmpty) {
+ configurations.addAll(TEST_CONFIGURATIONS.keys);
+ }
+ String outputConfig = configurations.first;
+
asyncTest(() async {
- String filename =
- 'tests/compiler/dart2js/sourcemaps/invokes_test_file.dart';
- SourceMapProcessor processor = new SourceMapProcessor(filename);
- List<SourceMapInfo> infoList = await processor.process(
- ['--use-new-source-info', '--csp', '--disable-inlining']);
- List<SourceMapInfo> userInfoList = <SourceMapInfo>[];
- List<SourceMapInfo> failureList = <SourceMapInfo>[];
- for (SourceMapInfo info in infoList) {
- if (info.element.library.isPlatformLibrary) continue;
- userInfoList.add(info);
- Iterable<CodePoint> missingCodePoints =
- info.codePoints.where((c) => c.isMissing);
+ List<Measurement> measurements = <Measurement>[];
+ for (String config in configurations) {
+ List<String> options = TEST_CONFIGURATIONS[config];
+ Measurement measurement = await runTests(
+ config,
+ options,
+ showAll: showAll,
+ measure: measure,
+ outputUri: outputConfig == config ? outputUri : null);
+ if (measurement != null) {
+ measurements.add(measurement);
+ }
+ }
+ for (Measurement measurement in measurements) {
+ print(measurement);
+ }
+ });
+}
+
+const Map<String, List<String>> TEST_CONFIGURATIONS = const {
+ 'old': const [],
+ 'ssa': const ['--use-new-source-info', ],
+ 'cps': const ['--use-new-source-info', '--use-cps-ir'],
+};
+
+Future<Measurement> runTests(
+ String config,
+ List<String> options,
+ {bool showAll: false,
+ Uri outputUri,
+ bool measure: false}) async {
+ if (config == 'old' && !measure) return null;
+
+ String filename =
+ 'tests/compiler/dart2js/sourcemaps/invokes_test_file.dart';
+ SourceMapProcessor processor = new SourceMapProcessor(filename);
+ List<SourceMapInfo> infoList = await processor.process(
+ ['--csp', '--disable-inlining']
+ ..addAll(options),
+ verbose: !measure);
+ List<SourceMapInfo> userInfoList = <SourceMapInfo>[];
+ List<SourceMapInfo> failureList = <SourceMapInfo>[];
+ Measurement measurement = new Measurement(config);
+ for (SourceMapInfo info in infoList) {
+ if (info.element.library.isPlatformLibrary) continue;
+ userInfoList.add(info);
+ Iterable<CodePoint> missingCodePoints =
+ info.codePoints.where((c) => c.isMissing);
+ measurement.missing += missingCodePoints.length;
+ measurement.count += info.codePoints.length;
+ if (!measure) {
if (!missingCodePoints.isEmpty) {
- print('Missing code points ${missingCodePoints} for '
- '${info.element} in $filename');
+ print("Missing code points for ${info.element} in '$filename':");
+ for (CodePoint codePoint in missingCodePoints) {
+ print(" $codePoint");
+ }
failureList.add(info);
}
}
- if (failureList.isNotEmpty) {
- if (outputUri == null) {
+ }
+ if (failureList.isNotEmpty) {
+ if (outputUri == null) {
+ if (!measure) {
Expect.fail(
"Missing code points found. "
- "Run the test with a URI option, `source_mapping_test <uri>`, to "
+ "Run the test with a URI option, "
+ "`source_mapping_test --out=<uri> $config`, to "
"create a html visualization of the missing code points.");
- } else {
- createTraceSourceMapHtml(outputUri, processor,
- showAll ? userInfoList : failureList);
}
- } else if (outputUri != null) {
- createTraceSourceMapHtml(outputUri, processor, userInfoList);
+ } else {
+ createTraceSourceMapHtml(outputUri, processor,
+ showAll ? userInfoList : failureList);
}
- });
+ } else if (outputUri != null) {
+ createTraceSourceMapHtml(outputUri, processor, userInfoList);
+ }
+ return measurement;
+}
+
+class Measurement {
+ final String config;
+ int missing = 0;
+ int count = 0;
+
+ Measurement(this.config);
+
+ String toString() {
+ double percentage = 100 * missing / count;
+ return "Config '${config}': $missing of $count ($percentage%) missing";
+ }
}
diff --git a/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart b/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart
index d7aa763..b0dfb21 100644
--- a/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart
+++ b/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart
@@ -7,7 +7,8 @@
import 'dart:async';
import 'package:compiler/src/apiimpl.dart' as api;
import 'package:compiler/src/dart2jslib.dart' show NullSink;
-import "package:compiler/src/elements/elements.dart";
+import 'package:compiler/src/elements/elements.dart';
+import 'package:compiler/src/helpers/helpers.dart';
import 'package:compiler/src/filenames.dart';
import 'package:compiler/src/io/source_file.dart';
import 'package:compiler/src/io/source_information.dart';
@@ -106,20 +107,23 @@
}
/// Computes the [SourceMapInfo] for the compiled elements.
- Future<List<SourceMapInfo>> process(List<String> options) async {
+ Future<List<SourceMapInfo>> process(
+ List<String> options,
+ {bool verbose: true}) async {
OutputProvider outputProvider = outputToFile
? new OutputProvider()
: new CloningOutputProvider(targetUri, sourceMapFileUri);
if (options.contains('--use-new-source-info')) {
- print('Using the new source information system.');
+ if (verbose) print('Using the new source information system.');
useNewSourceInfo = true;
}
api.Compiler compiler = await compilerFor({},
outputProvider: outputProvider,
+ // TODO(johnniwinther): Use [verbose] to avoid showing diagnostics.
options: ['--out=$targetUri', '--source-map=$sourceMapFileUri']
..addAll(options));
if (options.contains('--disable-inlining')) {
- print('Inlining disabled');
+ if (verbose) print('Inlining disabled');
compiler.disableInlining = true;
}
diff --git a/tests/compiler/dart2js/world_test.dart b/tests/compiler/dart2js/world_test.dart
new file mode 100644
index 0000000..436b3d7
--- /dev/null
+++ b/tests/compiler/dart2js/world_test.dart
@@ -0,0 +1,130 @@
+// 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.
+
+library world_test;
+
+import 'package:expect/expect.dart';
+import 'package:async_helper/async_helper.dart';
+import 'type_test_helper.dart';
+import 'package:compiler/src/elements/elements.dart'
+ show Element, ClassElement;
+import 'package:compiler/src/dart2jslib.dart';
+
+void main() {
+ asyncTest(() => TypeEnvironment.create(r"""
+ class A {}
+ class B {}
+ class C extends A {}
+ class D implements A {}
+ class E extends B implements A {}
+ class F extends Object with A implements B {}
+ class G extends Object with A, B {}
+ """,
+ mainSource: r"""
+ main() {
+ new A();
+ new B();
+ new C();
+ new D();
+ new E();
+ new F();
+ new G();
+ }
+ """,
+ useMockCompiler: false).then((env) {
+ ClassWorld classWorld = env.compiler.world;
+
+ ClassElement Object_ = env.getElement("Object");
+ ClassElement A = env.getElement("A");
+ ClassElement B = env.getElement("B");
+ ClassElement C = env.getElement("C");
+ ClassElement D = env.getElement("D");
+ ClassElement E = env.getElement("E");
+ ClassElement F = env.getElement("F");
+ ClassElement G = env.getElement("G");
+
+ void check(
+ String property,
+ ClassElement cls,
+ Iterable<ClassElement> foundClasses,
+ List<ClassElement> expectedClasses,
+ {bool exact: true}) {
+ for (ClassElement expectedClass in expectedClasses) {
+ Expect.isTrue(foundClasses.contains(expectedClass),
+ "Expect $expectedClass in '$property' on $cls. "
+ "Found:\n ${foundClasses.join('\n ')}");
+ }
+ if (exact) {
+ Expect.equals(expectedClasses.length, foundClasses.length,
+ "Unexpected classes "
+ "${foundClasses.where((c) => !expectedClasses.contains(c))} "
+ "in '$property' on $cls.");
+ }
+ }
+
+ void testStrictSubclasses(
+ ClassElement cls,
+ List<ClassElement> expectedClasses,
+ {bool exact: true}) {
+ check(
+ 'strictSubclassesOf',
+ cls,
+ classWorld.strictSubclassesOf(cls),
+ expectedClasses,
+ exact: exact);
+ }
+
+ void testStrictSubtypes(
+ ClassElement cls,
+ List<ClassElement> expectedClasses,
+ {bool exact: true}) {
+ check(
+ 'strictSubtypesOf',
+ cls,
+ classWorld.strictSubtypesOf(cls),
+ expectedClasses,
+ exact: exact);
+ }
+
+ void testMixinUses(
+ ClassElement cls,
+ List<ClassElement> expectedClasses,
+ {bool exact: true}) {
+ check(
+ 'mixinUsesOf',
+ cls,
+ classWorld.mixinUsesOf(cls),
+ expectedClasses,
+ exact: exact);
+ }
+
+ testStrictSubclasses(Object_, [A, B, C, D, E, F, G], exact: false);
+ testStrictSubclasses(A, [C]);
+ testStrictSubclasses(B, [E]);
+ testStrictSubclasses(C, []);
+ testStrictSubclasses(D, []);
+ testStrictSubclasses(E, []);
+ testStrictSubclasses(F, []);
+ testStrictSubclasses(G, []);
+
+ testStrictSubtypes(Object_, [A, B, C, D, E, F, G], exact: false);
+ testStrictSubtypes(A, [C, D, E, F, G]);
+ testStrictSubtypes(B, [E, F, G]);
+ testStrictSubtypes(C, []);
+ testStrictSubtypes(D, []);
+ testStrictSubtypes(E, []);
+ testStrictSubtypes(F, []);
+ testStrictSubtypes(G, []);
+
+ testMixinUses(Object_, []);
+ testMixinUses(A, [F.superclass, G.superclass.superclass]);
+ testMixinUses(B, [G.superclass]);
+ testMixinUses(C, []);
+ testMixinUses(D, []);
+ testMixinUses(E, []);
+ testMixinUses(F, []);
+ testMixinUses(G, []);
+
+ }));
+}
diff --git a/tests/compiler/dart2js_extra/23486_test.dart b/tests/compiler/dart2js_extra/23486_test.dart
index 1d8eb39..41fcf2d 100644
--- a/tests/compiler/dart2js_extra/23486_test.dart
+++ b/tests/compiler/dart2js_extra/23486_test.dart
@@ -33,6 +33,6 @@
main() {
Expect.throws(new A().m); /// 01: continued
Expect.throws(() => new D.name()); /// 02: continued
- Expect.throws(() => (p).x); /// 03: static type warning
+ Expect.throws(() => (p).x); /// 03: compile-time error
}
diff --git a/tests/compiler/dart2js_extra/23804_test.dart b/tests/compiler/dart2js_extra/23804_test.dart
new file mode 100644
index 0000000..2fad1d5
--- /dev/null
+++ b/tests/compiler/dart2js_extra/23804_test.dart
@@ -0,0 +1,15 @@
+// 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.
+
+// Regression test for http://dartbug.com/23804/
+// Inference incorrectly assumed that `any` and `every` didn't escape the values
+// in the collections.
+
+import 'package:expect/expect.dart';
+
+test(n) => n == 1;
+run(f) => f(1);
+main() {
+ Expect.equals([test].any(run), true);
+}
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index d3968e2..5c61219 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -71,21 +71,20 @@
async_stacktrace_test/asyncStar: Crash # (runTests()async{awa... cannot handle async/sync*/async* functions
async_stacktrace_test/none: Crash # (runTests()async{awa... cannot handle async/sync*/async* functions
closure_capture5_test: Crash # (i=0): For-loop variable captured in loop header
-conditional_send_test: RuntimeError # receiver.get$_nums is not a function
-deferred/deferred_class_test: RuntimeError # receiver.get$_nums is not a function
-deferred/deferred_constant2_test: RuntimeError # receiver.get$_nums is not a function
-deferred/deferred_constant3_test: RuntimeError # receiver.get$_nums is not a function
-deferred/deferred_constant4_test: RuntimeError # receiver.get$_nums is not a function
-deferred/deferred_function_test: RuntimeError # receiver.get$_nums is not a function
-deferred/deferred_mirrors1_test: RuntimeError # receiver.get$_nums is not a function
-deferred/deferred_mirrors2_test: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred/deferred_overlapping_test: RuntimeError # receiver.get$_nums is not a function
-if_null_test: RuntimeError # receiver.get$_nums is not a function
-mirror_printer_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirror_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors_used_warning2_test: RuntimeError # receiver.get$_nums is not a function
-mirrors_used_warning_test/minif: RuntimeError # receiver.get$_nums is not a function
-mirrors_used_warning_test/none: RuntimeError # receiver.get$_nums is not a function
-reflect_native_types_test: Crash # (=_EmptyStream<T>;): Unhandled node
+conditional_send_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred/deferred_class_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred/deferred_constant2_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred/deferred_constant3_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred/deferred_constant4_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred/deferred_function_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred/deferred_mirrors1_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred/deferred_mirrors2_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+deferred/deferred_overlapping_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+if_null_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirror_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors_used_warning2_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirrors_used_warning_test/minif: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirrors_used_warning_test/none: RuntimeError # receiver._addHashTableEntry$2 is not a function
+reflect_native_types_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
switch_test/none: Crash # (switch (val){foo:ba... continue to a labeled switch case
-timer_test: RuntimeError # receiver.get$_nums is not a function
+timer_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
diff --git a/tests/compiler/dart2js_extra/interceptor_named_arguments_test.dart b/tests/compiler/dart2js_extra/interceptor_named_arguments_test.dart
new file mode 100644
index 0000000..6911a96
--- /dev/null
+++ b/tests/compiler/dart2js_extra/interceptor_named_arguments_test.dart
@@ -0,0 +1,56 @@
+// 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 proper one-shot interceptor is used for different
+// combinations of named arguments.
+import "package:expect/expect.dart";
+
+// Use dart:html to get interceptors into play.
+import "dart:html";
+
+// [createFragment] has the same signature as in [Element].
+class Other {
+ createFragment(html, {validator, treeSanitizer}) {
+ int result = 0;
+ result += validator == null ? 0 : 2;
+ result += treeSanitizer == null ? 0 : 1;
+ return result;
+ }
+}
+
+@NoInline()
+bool wontTell(bool x) => x;
+
+
+// Ensure that we use the interceptor only once per context so that we
+// actually get a one-shot interceptor. This is a little brittle...
+@NoInline()
+testA(thing) {
+ Expect.equals(0, thing.createFragment(null));
+}
+
+@NoInline()
+testB(thing) {
+ Expect.equals(2, thing.createFragment(null, validator: 1));
+}
+
+@NoInline()
+testC(thing) {
+ Expect.equals(1, thing.createFragment(null, treeSanitizer: 1));
+}
+
+@NoInline()
+testD(thing) {
+ Expect.equals(3, thing.createFragment(null, validator: 1, treeSanitizer: 1));
+}
+
+main () {
+ // Ensure we get interceptors into play.
+ var thing = wontTell(true) ? new Other() : new DivElement();
+ testA(thing);
+ testB(thing);
+ testC(thing);
+ testD(thing);
+}
diff --git a/tests/compiler/dart2js_native/dart2js_native.status b/tests/compiler/dart2js_native/dart2js_native.status
index 2b3774c..bacc7ed 100644
--- a/tests/compiler/dart2js_native/dart2js_native.status
+++ b/tests/compiler/dart2js_native/dart2js_native.status
@@ -21,14 +21,14 @@
compute_this_script_test: Skip # Issue 17458
[ $compiler == dart2js && $cps_ir ]
-compute_this_script_test: RuntimeError # receiver.get$_nums is not a function
-event_loop_test: RuntimeError # receiver.get$_nums is not a function
-internal_library_test: RuntimeError # receiver.get$_nums is not a function
-mirror_intercepted_field_test: Crash # (=_EmptyStream<T>;): Unhandled node
+compute_this_script_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+event_loop_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+internal_library_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirror_intercepted_field_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
native_closure_identity_frog_test: RuntimeError # invoke is not a function
native_exception_test: RuntimeError # J.getInterceptor(...).toString$0 is not a function
native_method_inlining_test: RuntimeError # Please triage this failure.
-native_mirror_test: Crash # (=_EmptyStream<T>;): Unhandled node
+native_mirror_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
native_no_such_method_exception3_frog_test: RuntimeError # Please triage this failure.
native_wrapping_function3_frog_test: RuntimeError # invoke is not a function
native_wrapping_function_frog_test: RuntimeError # invoke is not a function
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 4f9274e..2061caf 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -221,13 +221,13 @@
iterable_to_set_test: RuntimeError # Please triage this failure.
list_test/01: RuntimeError # this.get$length is not a function
list_test/none: RuntimeError # this.get$length is not a function
-main_test: RuntimeError # receiver.get$_nums is not a function
+main_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
map_values2_test: RuntimeError # Please triage this failure.
map_values3_test: RuntimeError # Please triage this failure.
map_values4_test: RuntimeError # Please triage this failure.
regexp/pcre_test: Crash # Stack Overflow
shuffle_test: RuntimeError # this.get$length is not a function
-stacktrace_fromstring_test: RuntimeError # receiver.get$_nums is not a function
+stacktrace_fromstring_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
string_fromcharcodes_test: RuntimeError # this.get$length is not a function
symbol_operator_test/03: RuntimeError # Please triage this failure.
symbol_reserved_word_test/03: Pass # Please triage this failure.
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 2472eb6..ca463e5 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -126,55 +126,55 @@
package_root_test: SkipByDesign # Uses dart:io.
[ $compiler == dart2js && $cps_ir ]
-bool_from_environment_default_value_test: RuntimeError # receiver.get$_collection$_nums is not a function
-capability_test: RuntimeError # receiver.get$_collection$_nums is not a function
-compile_time_error_test/none: RuntimeError # receiver.get$_collection$_nums is not a function
-count_test: RuntimeError # receiver.get$_nums is not a function
-cross_isolate_message_test: RuntimeError # receiver.get$_nums is not a function
-deferred_in_isolate2_test: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_in_isolate_test: RuntimeError # receiver.get$_collection$_nums is not a function
-function_send_test: RuntimeError # receiver.get$_nums is not a function
-handle_error2_test: RuntimeError # receiver.get$_collection$_nums is not a function
-handle_error3_test: RuntimeError # receiver.get$_collection$_nums is not a function
-handle_error_test: RuntimeError # receiver.get$_collection$_nums is not a function
-illegal_msg_function_test: RuntimeError # receiver.get$_nums is not a function
-illegal_msg_mirror_test: RuntimeError # receiver.get$_nums is not a function
-int_from_environment_default_value_test: RuntimeError # receiver.get$_collection$_nums is not a function
-isolate_complex_messages_test: RuntimeError # receiver.get$_nums is not a function
-isolate_current_test: RuntimeError # receiver.get$_nums is not a function
-isolate_import_test/none: RuntimeError # receiver.get$_collection$_nums is not a function
-issue_22778_test: RuntimeError # receiver.get$_collection$_nums is not a function
-kill2_test: RuntimeError # receiver.get$_collection$_nums is not a function
-kill_self_test: RuntimeError # receiver.get$_collection$_nums is not a function
-kill_test: RuntimeError # receiver.get$_collection$_nums is not a function
-mandel_isolate_test: RuntimeError # receiver.get$_collection$_nums is not a function
-message2_test: RuntimeError # receiver.get$_nums is not a function
-message3_test/byteBuffer: RuntimeError # receiver.get$_collection$_nums is not a function
-message3_test/fun: RuntimeError # receiver.get$_collection$_nums is not a function
-message3_test/int32x4: RuntimeError # receiver.get$_collection$_nums is not a function
-message3_test/none: RuntimeError # receiver.get$_collection$_nums is not a function
-message_enum_test: RuntimeError # receiver.get$_collection$_nums is not a function
-message_test: RuntimeError # receiver.get$_nums is not a function
-mint_maker_test: RuntimeError # receiver.get$_nums is not a function
-nested_spawn2_test: RuntimeError # receiver.get$_nums is not a function
-nested_spawn_test: RuntimeError # receiver.get$_nums is not a function
-object_leak_test: RuntimeError # receiver.get$_collection$_nums is not a function
-ondone_test: RuntimeError # receiver.get$_nums is not a function
-pause_test: RuntimeError # receiver.get$_nums is not a function
-ping_pause_test: RuntimeError # receiver.get$_collection$_nums is not a function
-ping_test: RuntimeError # receiver.get$_collection$_nums is not a function
-port_test: RuntimeError # receiver.get$_collection$_nums is not a function
-raw_port_test: RuntimeError # receiver.get$_nums is not a function
-request_reply_test: RuntimeError # receiver.get$_nums is not a function
-simple_message_test/none: RuntimeError # receiver.get$_collection$_nums is not a function
-spawn_function_custom_class_test: RuntimeError # receiver.get$_nums is not a function
-spawn_function_test: RuntimeError # receiver.get$_nums is not a function
-spawn_uri_missing_from_isolate_test: RuntimeError # receiver.get$_collection$_nums is not a function
-spawn_uri_missing_test: RuntimeError # receiver.get$_collection$_nums is not a function
-stacktrace_message_test: RuntimeError # receiver.get$_nums is not a function
-start_paused_test: RuntimeError # receiver.get$_nums is not a function
-static_function_test: RuntimeError # receiver.get$_nums is not a function
-string_from_environment_default_value_test: RuntimeError # receiver.get$_collection$_nums is not a function
-timer_isolate_test: RuntimeError # receiver.get$_collection$_nums is not a function
-typed_message_test: RuntimeError # receiver.get$_nums is not a function
-unresolved_ports_test: RuntimeError # receiver.get$_nums is not a function
+bool_from_environment_default_value_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+capability_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+compile_time_error_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+count_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+cross_isolate_message_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_in_isolate2_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+deferred_in_isolate_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+function_send_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+handle_error2_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+handle_error3_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+handle_error_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+illegal_msg_function_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+illegal_msg_mirror_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+int_from_environment_default_value_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+isolate_complex_messages_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+isolate_current_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+isolate_import_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+issue_22778_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+kill2_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+kill_self_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+kill_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mandel_isolate_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+message2_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+message3_test/byteBuffer: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+message3_test/fun: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+message3_test/int32x4: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+message3_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+message_enum_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+message_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mint_maker_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+nested_spawn2_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+nested_spawn_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+object_leak_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+ondone_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+pause_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+ping_pause_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+ping_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+port_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+raw_port_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+request_reply_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+simple_message_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+spawn_function_custom_class_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+spawn_function_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+spawn_uri_missing_from_isolate_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+spawn_uri_missing_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+stacktrace_message_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+start_paused_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+static_function_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+string_from_environment_default_value_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+timer_isolate_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+typed_message_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+unresolved_ports_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
diff --git a/tests/language/deferred_static_seperate_test.dart b/tests/language/deferred_static_seperate_test.dart
index f5e59f0..080c753 100644
--- a/tests/language/deferred_static_seperate_test.dart
+++ b/tests/language/deferred_static_seperate_test.dart
@@ -14,6 +14,7 @@
void main() {
asyncStart();
+ Expect.throws(() => new lib1.C());
lib1.loadLibrary().then((_) {
lib2.loadLibrary().then((_) {
print("HERE");
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index f728a01..0a9e2cf 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -33,10 +33,6 @@
stacktrace_rethrow_nonerror_test: Pass, RuntimeError # Issue 12698
stacktrace_rethrow_error_test: Pass, RuntimeError # Issue 12698
instantiate_type_variable_test/01: CompileTimeError # Issue 13631
-library_ambiguous_test/00: CompileTimeError # Issue 13632
-library_ambiguous_test/01: CompileTimeError # Issue 13632
-library_ambiguous_test/02: CompileTimeError # Issue 13632
-library_ambiguous_test/03: CompileTimeError # Issue 13632
type_variable_conflict_test/01: Fail # Issue 13702
type_variable_conflict_test/02: Fail # Issue 13702
type_variable_conflict_test/03: Fail # Issue 13702
@@ -64,21 +60,12 @@
if_null_assignment_behavior_test/14: Crash # Issue 23491
nullaware_opt_test: Fail # Fails at e?.f ??= 200;
-conditional_method_invocation_test/11: MissingCompileTimeError # Issue 23611
-conditional_property_access_test/09: MissingCompileTimeError # Issue 23611
-conditional_property_assignment_test/20: MissingCompileTimeError # Issue 23611
-conditional_property_assignment_test/21: MissingCompileTimeError # Issue 23611
-conditional_property_assignment_test/22: MissingCompileTimeError # Issue 23611
if_null_assignment_behavior_test/29: Crash # Issue 23611
if_null_assignment_behavior_test/30: Crash # Issue 23611
prefix_assignment_test/01: Crash # Issue 23611
prefix_assignment_test/02: Crash # Issue 23611
-prefix_identifier_reference_test/01: MissingCompileTimeError # Issue 23611
-prefix_identifier_reference_test/02: MissingCompileTimeError # Issue 23611
-prefix_identifier_reference_test/03: MissingCompileTimeError # Issue 23611
prefix_identifier_reference_test/04: Crash # Issue 23611
prefix_identifier_reference_test/05: Crash # Issue 23611
-prefix_unqualified_invocation_test/01: RuntimeError # Issue 23611
const_error_multiply_initialized_test/02: CompileTimeError # Issue 23618
const_error_multiply_initialized_test/04: CompileTimeError # Issue 23618
@@ -206,10 +193,6 @@
bit_operations_test: RuntimeError, OK # Issue 1533
expect_test: RuntimeError, OK # Issue 13080
-illegal_invocation_test/01: MissingCompileTimeError # Issue 23611
-prefix_unqualified_invocation_test/01: MissingCompileTimeError # Issue 23611
-prefix_unqualified_invocation_test/02: MissingCompileTimeError # Issue 23611
-
[ $compiler == dart2js && $runtime == none ]
*: Fail, Pass # TODO(ahe): Triage these tests.
@@ -360,55 +343,56 @@
await_postfix_expr_test: Crash # (test()async{Expect.... cannot handle async/sync*/async* functions
await_regression_test: Crash # (main()async{testNes... cannot handle async/sync*/async* functions
await_test: Crash # (others()async{var a... cannot handle async/sync*/async* functions
-cha_deopt1_test: RuntimeError # receiver.get$_nums is not a function
-cha_deopt2_test: RuntimeError # receiver.get$_nums is not a function
-cha_deopt3_test: RuntimeError # receiver.get$_nums is not a function
-closure_cycles_test: RuntimeError # receiver.get$_nums is not a function
+cha_deopt1_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+cha_deopt2_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+cha_deopt3_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+closure_cycles_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
closure_in_constructor_test: Crash # Invalid argument(s)
closure_type_variables_test: Crash # Invalid argument(s)
-const_evaluation_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+const_evaluation_test/01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
constructor12_test: RuntimeError # Please triage this failure.
crash_6725_test/01: Crash # The null object does not have a getter '_element'.
custom_await_stack_trace_test: Crash # (main()async{try {va... cannot handle async/sync*/async* functions
-deferred_closurize_load_library_test: RuntimeError # receiver.get$_nums is not a function
-deferred_constant_list_test: RuntimeError # receiver.get$_nums is not a function
-deferred_constraints_constants_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-deferred_constraints_constants_test/reference_after_load: Crash # (=_EmptyStream<T>;): Unhandled node
-deferred_constraints_type_annotation_test/as_operation: RuntimeError # receiver.get$_nums is not a function
+deferred_closurize_load_library_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_constant_list_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_constraints_constants_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+deferred_constraints_constants_test/reference_after_load: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+deferred_constraints_type_annotation_test/as_operation: RuntimeError # receiver._addHashTableEntry$2 is not a function
deferred_constraints_type_annotation_test/catch_check: Crash # The null object does not have a getter '_element'.
-deferred_constraints_type_annotation_test/is_check: RuntimeError # receiver.get$_nums is not a function
-deferred_constraints_type_annotation_test/new: RuntimeError # receiver.get$_nums is not a function
-deferred_constraints_type_annotation_test/new_before_load: RuntimeError # receiver.get$_nums is not a function
-deferred_constraints_type_annotation_test/new_generic1: RuntimeError # receiver.get$_nums is not a function
-deferred_constraints_type_annotation_test/new_generic2: RuntimeError # receiver.get$_nums is not a function
-deferred_constraints_type_annotation_test/new_generic3: RuntimeError # receiver.get$_nums is not a function
-deferred_constraints_type_annotation_test/none: RuntimeError # receiver.get$_nums is not a function
-deferred_constraints_type_annotation_test/static_method: RuntimeError # receiver.get$_nums is not a function
-deferred_constraints_type_annotation_test/type_annotation1: RuntimeError # receiver.get$_nums is not a function
-deferred_constraints_type_annotation_test/type_annotation_generic1: RuntimeError # receiver.get$_nums is not a function
-deferred_constraints_type_annotation_test/type_annotation_generic2: RuntimeError # receiver.get$_nums is not a function
-deferred_constraints_type_annotation_test/type_annotation_generic3: RuntimeError # receiver.get$_nums is not a function
-deferred_constraints_type_annotation_test/type_annotation_generic4: RuntimeError # receiver.get$_nums is not a function
-deferred_constraints_type_annotation_test/type_annotation_non_deferred: RuntimeError # receiver.get$_nums is not a function
-deferred_constraints_type_annotation_test/type_annotation_null: RuntimeError # receiver.get$_nums is not a function
-deferred_constraints_type_annotation_test/type_annotation_top_level: RuntimeError # receiver.get$_nums is not a function
-deferred_function_type_test: RuntimeError # receiver.get$_nums is not a function
-deferred_global_test: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_inlined_test: RuntimeError # receiver.get$_nums is not a function
-deferred_load_constants_test/none: RuntimeError # receiver.get$_nums is not a function
-deferred_load_inval_code_test: RuntimeError # receiver.get$_nums is not a function
-deferred_load_library_wrong_args_test/none: RuntimeError # receiver.get$_nums is not a function
-deferred_mixin_test: RuntimeError # receiver.get$_nums is not a function
-deferred_no_such_method_test: RuntimeError # receiver.get$_nums is not a function
+deferred_constraints_type_annotation_test/is_check: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_constraints_type_annotation_test/new: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_constraints_type_annotation_test/new_before_load: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_constraints_type_annotation_test/new_generic1: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_constraints_type_annotation_test/new_generic2: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_constraints_type_annotation_test/new_generic3: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_constraints_type_annotation_test/none: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_constraints_type_annotation_test/static_method: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_constraints_type_annotation_test/type_annotation1: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_constraints_type_annotation_test/type_annotation_generic1: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_constraints_type_annotation_test/type_annotation_generic2: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_constraints_type_annotation_test/type_annotation_generic3: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_constraints_type_annotation_test/type_annotation_generic4: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_constraints_type_annotation_test/type_annotation_non_deferred: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_constraints_type_annotation_test/type_annotation_null: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_constraints_type_annotation_test/type_annotation_top_level: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_function_type_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_global_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_inlined_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_load_constants_test/none: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_load_inval_code_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_load_library_wrong_args_test/none: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_mixin_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_no_such_method_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
deferred_not_loaded_check_test: RuntimeError # Please triage this failure.
-deferred_only_constant_test: RuntimeError # receiver.get$_nums is not a function
-deferred_optimized_test: RuntimeError # receiver.get$_nums is not a function
+deferred_only_constant_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_optimized_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
deferred_redirecting_factory_test: Crash # (test()async{await t... cannot handle async/sync*/async* functions
-deferred_regression_22995_test: RuntimeError # receiver.get$_nums is not a function
-deferred_shadow_load_library_test: RuntimeError # receiver.get$_nums is not a function
-deferred_shared_and_unshared_classes_test: RuntimeError # receiver.get$_nums is not a function
-deferred_static_seperate_test: RuntimeError # receiver.get$_collection$_nums is not a function
-enum_mirror_test: Crash # (=_EmptyStream<T>;): Unhandled node
+deferred_regression_22995_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_shadow_load_library_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_shared_and_unshared_classes_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+deferred_static_seperate_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+dynamic_prefix_core_test/01: Crash # The null object does not have a getter 'name'.
+enum_mirror_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
final_super_field_set_test/01: RuntimeError # Please triage this failure.
flatten_test/01: Crash # (test()async{int x=await new Derived<int>();}): cannot handle async/sync*/async* functions
flatten_test/02: Crash # (test()async{Future<int> f()async=>new Derived<int>();}): cannot handle async/sync*/async* functions
@@ -426,34 +410,41 @@
for2_test: Crash # The null object does not have a getter 'field'.
for_variable_capture_test: Crash # (i=0): For-loop variable captured in loop header
generic_field_mixin3_test: RuntimeError # Please triage this failure.
+if_null_assignment_behavior_test/12: RuntimeError # Please triage this failure.
+if_null_assignment_behavior_test/28: RuntimeError # Please triage this failure.
if_null_assignment_static_test/01: RuntimeError # v0.get$a is not a function
if_null_assignment_static_test/03: RuntimeError # v0.get$a is not a function
if_null_assignment_static_test/04: RuntimeError # v0.get$b is not a function
if_null_assignment_static_test/05: RuntimeError # v0.get$a is not a function
+if_null_assignment_static_test/29: RuntimeError # v0.get$a is not a function
+if_null_assignment_static_test/31: RuntimeError # v0.get$a is not a function
+if_null_assignment_static_test/32: RuntimeError # v0.get$b is not a function
+if_null_assignment_static_test/33: RuntimeError # v0.get$a is not a function
if_null_assignment_static_test/36: RuntimeError # v0.get$a is not a function
if_null_assignment_static_test/38: RuntimeError # v0.get$a is not a function
if_null_assignment_static_test/39: RuntimeError # v0.get$b is not a function
if_null_assignment_static_test/40: RuntimeError # v0.get$a is not a function
+import_self_test/01: Crash # The null object does not have a getter 'name'.
infinite_switch_label_test: Crash # (switch (target){l0:... continue to a labeled switch case
-instance_creation_in_function_annotation_test: Crash # (=_EmptyStream<T>;): Unhandled node
+instance_creation_in_function_annotation_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
instanceof4_test/01: RuntimeError # Please triage this failure.
invocation_mirror_invoke_on_test: RuntimeError # Please triage this failure.
invocation_mirror_test: Crash # (super[37]=42): visitUnresolvedSuperIndexSet
-issue_1751477_test: RuntimeError # receiver.get$_nums is not a function
+issue_1751477_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
large_class_declaration_test: Crash # Stack Overflow
list_test: RuntimeError # Please triage this failure.
-main_test/01: RuntimeError # receiver.get$_nums is not a function
-main_test/02: RuntimeError # receiver.get$_nums is not a function
-main_test/04: RuntimeError # receiver.get$_nums is not a function
-main_test/05: RuntimeError # receiver.get$_nums is not a function
-main_test/20: RuntimeError # receiver.get$_nums is not a function
-main_test/21: RuntimeError # receiver.get$_nums is not a function
-main_test/22: RuntimeError # receiver.get$_nums is not a function
-main_test/41: RuntimeError # receiver.get$_nums is not a function
-main_test/42: RuntimeError # receiver.get$_nums is not a function
-main_test/43: RuntimeError # receiver.get$_nums is not a function
-main_test/44: RuntimeError # receiver.get$_nums is not a function
-main_test/45: RuntimeError # receiver.get$_nums is not a function
+main_test/01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+main_test/02: RuntimeError # receiver._addHashTableEntry$2 is not a function
+main_test/04: RuntimeError # receiver._addHashTableEntry$2 is not a function
+main_test/05: RuntimeError # receiver._addHashTableEntry$2 is not a function
+main_test/20: RuntimeError # receiver._addHashTableEntry$2 is not a function
+main_test/21: RuntimeError # receiver._addHashTableEntry$2 is not a function
+main_test/22: RuntimeError # receiver._addHashTableEntry$2 is not a function
+main_test/41: RuntimeError # receiver._addHashTableEntry$2 is not a function
+main_test/42: RuntimeError # receiver._addHashTableEntry$2 is not a function
+main_test/43: RuntimeError # receiver._addHashTableEntry$2 is not a function
+main_test/44: RuntimeError # receiver._addHashTableEntry$2 is not a function
+main_test/45: RuntimeError # receiver._addHashTableEntry$2 is not a function
many_overridden_no_such_method_test: RuntimeError # Please triage this failure.
mixin_type_parameters_mixin_extends_test: Crash # The null object does not have a getter '_element'.
mixin_type_parameters_mixin_test: Crash # The null object does not have a getter '_element'.
@@ -461,18 +452,22 @@
mixin_type_parameters_super_test: Crash # The null object does not have a getter '_element'.
nested_switch_label_test: Crash # (switch (target){out... continue to a labeled switch case
no_such_method_test: RuntimeError # Please triage this failure.
-null_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+null_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
overridden_no_such_method_test: RuntimeError # Please triage this failure.
-regress_18535_test: Crash # (=_EmptyStream<T>;): Unhandled node
+prefix12_negative_test: Crash # The null object does not have a getter 'name'.
+prefix2_negative_test: Crash # The null object does not have a getter 'name'.
+private_access_test/02: Crash # The null object does not have a getter 'name'.
+redirecting_factory_reflection_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+regress_18535_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
regress_22438_test: Crash # (main()async{var err... cannot handle async/sync*/async* functions
-regress_22443_test: RuntimeError # receiver.get$_nums is not a function
+regress_22443_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
regress_22445_test: Crash # (main()async{var err... cannot handle async/sync*/async* functions
regress_22579_test: Crash # (main()async{var err... cannot handle async/sync*/async* functions
regress_22728_test: Crash # (main()async{bool fa... cannot handle async/sync*/async* functions
regress_22777_test: Crash # (test()async{try {te... cannot handle async/sync*/async* functions
regress_22936_test/01: Crash # The null object does not have a getter '_element'.
regress_22936_test/none: Crash # The null object does not have a getter '_element'.
-regress_23408_test: RuntimeError # receiver.get$_nums is not a function
+regress_23408_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
regress_23498_test: Crash # (main()async{var err... cannot handle async/sync*/async* functions
regress_23500_test/01: Crash # (main()async{var err... cannot handle async/sync*/async* functions
regress_23500_test/02: Crash # (main()async{var err... cannot handle async/sync*/async* functions
diff --git a/tests/language/nullaware_opt_test.dart b/tests/language/nullaware_opt_test.dart
index aafb7ac..625ccc9 100644
--- a/tests/language/nullaware_opt_test.dart
+++ b/tests/language/nullaware_opt_test.dart
@@ -36,7 +36,7 @@
Expect.equals(d, d ?? bomb());
var e;
- // The assginment to e is not executed since d != null.
+ // The assignment to e is not executed since d != null.
d ??= e ??= new C(100);
Expect.equals(null, e);
e ??= new C(100);
diff --git a/tests/language/redirecting_factory_reflection_test.dart b/tests/language/redirecting_factory_reflection_test.dart
new file mode 100644
index 0000000..af39373
--- /dev/null
+++ b/tests/language/redirecting_factory_reflection_test.dart
@@ -0,0 +1,22 @@
+// 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:mirrors';
+import 'package:expect/expect.dart';
+
+abstract class A<T> {
+ get t;
+ factory A() = B<T, A<T>>;
+}
+
+class B<X, Y> implements A<X> {
+ final t;
+ B() : t = Y;
+}
+
+main() {
+ ClassMirror m = reflectClass(A);
+ var i = m.newInstance(const Symbol(''), []).reflectee;
+ Expect.equals(i.t.toString(), 'A');
+}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index e63fadf..02a9e192 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -327,380 +327,297 @@
convert/streamed_conversion_json_utf8_decode_test: Skip # Timeout.
[ $compiler == dart2js && $cps_ir ]
-async/catch_errors11_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors12_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors13_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors14_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors15_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors16_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors17_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors18_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors19_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors20_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors21_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors22_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors23_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors24_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors25_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors26_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors27_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors28_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors2_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors3_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors4_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors5_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors6_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors7_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors8_test: RuntimeError # receiver.get$_nums is not a function
-async/catch_errors_test: RuntimeError # receiver.get$_nums is not a function
-async/first_regression_test: RuntimeError # receiver.get$_nums is not a function
-async/future_constructor_test: RuntimeError # receiver.get$_nums is not a function
-async/future_delayed_error_test: RuntimeError # receiver.get$_nums is not a function
-async/future_microtask_test: RuntimeError # receiver.get$_nums is not a function
+async/catch_errors11_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors12_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors13_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors14_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors15_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors16_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors17_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors18_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors19_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors20_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors21_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors22_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors23_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors24_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors25_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors26_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors27_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors28_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors2_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors3_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors4_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors5_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors6_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors7_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors8_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/catch_errors_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/first_regression_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/future_constructor_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/future_delayed_error_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/future_microtask_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
async/future_test/01: Crash # (()async=>new Future.value(value)): cannot handle async/sync*/async* functions
-async/future_test/none: RuntimeError # receiver.get$_nums is not a function
-async/future_timeout_test: RuntimeError # receiver.get$_nums is not a function
-async/future_value_chain2_test: RuntimeError # receiver.get$_nums is not a function
-async/future_value_chain3_test: RuntimeError # receiver.get$_nums is not a function
-async/future_value_chain4_test: RuntimeError # receiver.get$_nums is not a function
-async/future_value_chain_test: RuntimeError # receiver.get$_nums is not a function
-async/futures_test: RuntimeError # receiver.get$_nums is not a function
-async/intercept_print1_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/intercept_schedule_microtask1_test: RuntimeError # receiver.get$_nums is not a function
-async/intercept_schedule_microtask2_test: RuntimeError # receiver.get$_nums is not a function
-async/intercept_schedule_microtask3_test: RuntimeError # receiver.get$_nums is not a function
-async/intercept_schedule_microtask4_test: RuntimeError # receiver.get$_nums is not a function
-async/intercept_schedule_microtask5_test: RuntimeError # receiver.get$_nums is not a function
-async/intercept_schedule_microtask6_test: RuntimeError # receiver.get$_nums is not a function
-async/multiple_timer_test: RuntimeError # receiver.get$_nums is not a function
-async/print_test/none: RuntimeError # receiver.get$_nums is not a function
-async/run_zoned1_test: RuntimeError # receiver.get$_nums is not a function
-async/run_zoned4_test: RuntimeError # receiver.get$_nums is not a function
-async/run_zoned5_test: RuntimeError # receiver.get$_nums is not a function
-async/run_zoned6_test/none: RuntimeError # receiver.get$_nums is not a function
-async/run_zoned7_test: RuntimeError # receiver.get$_nums is not a function
-async/run_zoned8_test: RuntimeError # receiver.get$_nums is not a function
-async/run_zoned9_test/none: RuntimeError # receiver.get$_nums is not a function
-async/schedule_microtask2_test: RuntimeError # receiver.get$_nums is not a function
-async/schedule_microtask3_test: RuntimeError # receiver.get$_nums is not a function
-async/schedule_microtask5_test: RuntimeError # receiver.get$_nums is not a function
-async/schedule_microtask_test: RuntimeError # receiver.get$_nums is not a function
-async/slow_consumer2_test: RuntimeError # receiver.get$_nums is not a function
-async/slow_consumer3_test: RuntimeError # receiver.get$_nums is not a function
-async/slow_consumer_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace01_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace02_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace03_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace04_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace05_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace06_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace07_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace08_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace09_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace10_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace11_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace12_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace13_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace14_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace15_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace16_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace17_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace18_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace19_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace20_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace21_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace22_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace23_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace24_test: RuntimeError # receiver.get$_nums is not a function
-async/stack_trace25_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_controller_async_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_controller_test: RuntimeError # receiver.get$_nums is not a function
+async/future_test/none: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/future_timeout_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/future_value_chain2_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/future_value_chain3_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/future_value_chain4_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/future_value_chain_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/futures_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/intercept_print1_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+async/intercept_schedule_microtask1_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/intercept_schedule_microtask2_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/intercept_schedule_microtask3_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/intercept_schedule_microtask4_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/intercept_schedule_microtask5_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/intercept_schedule_microtask6_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/multiple_timer_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/print_test/none: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/run_zoned1_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/run_zoned4_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/run_zoned5_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/run_zoned6_test/none: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/run_zoned7_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/run_zoned8_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/run_zoned9_test/none: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/schedule_microtask2_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/schedule_microtask3_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/schedule_microtask5_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/schedule_microtask_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/slow_consumer2_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/slow_consumer3_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/slow_consumer_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace01_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace02_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace03_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace04_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace05_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace06_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace07_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace08_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace09_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace10_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace11_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace12_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace13_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace14_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace15_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace16_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace17_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace18_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace19_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace20_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace21_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace22_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace23_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace24_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stack_trace25_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_controller_async_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_controller_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
async/stream_empty_test: Crash # (Future runTest()asy... cannot handle async/sync*/async* functions
-async/stream_event_transformed_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_first_where_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_from_iterable_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_iterator_double_cancel_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_event_transformed_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_first_where_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_from_iterable_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_iterator_double_cancel_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
async/stream_iterator_test: Crash # (()async{var stream=... cannot handle async/sync*/async* functions
-async/stream_join_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_last_where_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_listen_zone_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_periodic2_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_periodic3_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_periodic4_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_periodic5_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_periodic_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_single_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_single_to_multi_subscriber_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_state_nonzero_timer_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_state_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_subscription_as_future_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_subscription_cancel_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_timeout_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_transform_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_transformation_broadcast_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_transformer_from_handlers_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_transformer_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_zones_test: RuntimeError # receiver.get$_nums is not a function
-async/timer_cancel1_test: RuntimeError # receiver.get$_nums is not a function
-async/timer_cancel2_test: RuntimeError # receiver.get$_nums is not a function
-async/timer_cancel_test: RuntimeError # receiver.get$_nums is not a function
-async/timer_isActive_test: RuntimeError # receiver.get$_nums is not a function
-async/timer_regress22626_test: RuntimeError # receiver.get$_nums is not a function
-async/timer_repeat_test: RuntimeError # receiver.get$_nums is not a function
-async/timer_test: RuntimeError # receiver.get$_nums is not a function
-async/zone_bind_callback_test: RuntimeError # receiver.get$_nums is not a function
-async/zone_bind_callback_unary_test: RuntimeError # receiver.get$_nums is not a function
-async/zone_bind_test: RuntimeError # receiver.get$_nums is not a function
-async/zone_create_periodic_timer_test: RuntimeError # receiver.get$_nums is not a function
-async/zone_create_timer2_test: RuntimeError # receiver.get$_nums is not a function
-async/zone_create_timer_test: RuntimeError # receiver.get$_nums is not a function
-async/zone_debug_test: RuntimeError # receiver.get$_nums is not a function
-async/zone_empty_description2_test: RuntimeError # receiver.get$_nums is not a function
-async/zone_empty_description_test: RuntimeError # receiver.get$_nums is not a function
-async/zone_error_callback_test: RuntimeError # receiver.get$_nums is not a function
-async/zone_fork_test: RuntimeError # receiver.get$_nums is not a function
-async/zone_future_schedule_microtask_test: RuntimeError # receiver.get$_nums is not a function
-async/zone_register_callback_test: RuntimeError # receiver.get$_nums is not a function
-async/zone_register_callback_unary_test: RuntimeError # receiver.get$_nums is not a function
-async/zone_root_bind_test: RuntimeError # receiver.get$_nums is not a function
-async/zone_run_guarded_test: RuntimeError # receiver.get$_nums is not a function
-async/zone_run_test: RuntimeError # receiver.get$_nums is not a function
-async/zone_run_unary_test: RuntimeError # receiver.get$_nums is not a function
-async/zone_value_test: RuntimeError # receiver.get$_collection$_nums is not a function
+async/stream_join_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_last_where_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_listen_zone_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_periodic2_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_periodic3_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_periodic4_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_periodic5_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_periodic_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_single_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_single_to_multi_subscriber_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_state_nonzero_timer_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_state_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_subscription_as_future_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_subscription_cancel_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_timeout_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_transform_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_transformation_broadcast_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_transformer_from_handlers_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_transformer_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/stream_zones_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/timer_cancel1_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/timer_cancel2_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/timer_cancel_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/timer_isActive_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/timer_regress22626_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/timer_repeat_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/timer_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/zone_bind_callback_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/zone_bind_callback_unary_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/zone_bind_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/zone_create_periodic_timer_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/zone_create_timer2_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/zone_create_timer_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/zone_debug_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/zone_empty_description2_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/zone_empty_description_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/zone_error_callback_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/zone_fork_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/zone_future_schedule_microtask_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/zone_register_callback_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/zone_register_callback_unary_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/zone_root_bind_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/zone_run_guarded_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/zone_run_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/zone_run_unary_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+async/zone_value_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
convert/ascii_test: RuntimeError # this.get$length is not a function
-convert/encoding_test: RuntimeError # receiver.get$_nums is not a function
-convert/html_escape_test: RuntimeError # receiver.get$_nums is not a function
-convert/json_lib_test: RuntimeError # receiver.get$_nums is not a function
+convert/encoding_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+convert/html_escape_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+convert/json_lib_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
convert/latin1_test: RuntimeError # this.get$length is not a function
-convert/line_splitter_test: RuntimeError # receiver.get$_nums is not a function
-convert/streamed_conversion_json_decode1_test: RuntimeError # receiver.get$_collection$_nums is not a function
-convert/streamed_conversion_json_encode1_test: RuntimeError # receiver.get$_collection$_nums is not a function
-convert/streamed_conversion_json_utf8_decode_test: RuntimeError # receiver.get$_collection$_nums is not a function
-convert/streamed_conversion_json_utf8_encode_test: RuntimeError # receiver.get$_collection$_nums is not a function
-convert/streamed_conversion_utf8_decode_test: RuntimeError # receiver.get$_nums is not a function
-convert/streamed_conversion_utf8_encode_test: RuntimeError # receiver.get$_nums is not a function
-math/pi_test: RuntimeError # receiver.get$_nums is not a function
-math/point_test: RuntimeError # receiver.get$_nums is not a function
-math/rectangle_test: RuntimeError # receiver.get$_nums is not a function
-mirrors/abstract_class_test/00: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/abstract_class_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/abstract_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/accessor_cache_overflow_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/array_tracing2_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/array_tracing_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/basic_types_in_dart_core_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/circular_factory_redirection_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/class_declarations_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/class_declarations_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/class_mirror_location_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/class_mirror_type_variables_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/closures_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/closurization_equivalence_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/constructor_kinds_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/constructor_kinds_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/constructors_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/dart2js_mirrors_test: Crash # (=Class.faktory;): Unhandled node
-mirrors/declarations_type_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/deferred_mirrors_metadata_test: RuntimeError # receiver.get$_collection$_nums is not a function
-mirrors/deferred_mirrors_metatarget_test: RuntimeError # receiver.get$_collection$_nums is not a function
-mirrors/deferred_mirrors_update_test: RuntimeError # receiver.get$_collection$_nums is not a function
-mirrors/deferred_type_test: Crash # (=_EmptyStream<T>;): Unhandled node
+convert/line_splitter_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+convert/streamed_conversion_json_decode1_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+convert/streamed_conversion_json_encode1_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+convert/streamed_conversion_json_utf8_decode_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+convert/streamed_conversion_json_utf8_encode_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+convert/streamed_conversion_utf8_decode_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+convert/streamed_conversion_utf8_encode_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+math/pi_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+math/point_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+math/rectangle_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirrors/abstract_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/accessor_cache_overflow_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/array_tracing2_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/array_tracing_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/basic_types_in_dart_core_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/circular_factory_redirection_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/class_declarations_test/01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirrors/class_mirror_type_variables_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/closures_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/constructors_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/dart2js_mirrors_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirrors/declarations_type_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/deferred_mirrors_metadata_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/deferred_mirrors_metatarget_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/deferred_mirrors_update_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
mirrors/delegate_call_through_getter_test: RuntimeError # Please triage this failure.
mirrors/delegate_test: RuntimeError # Please triage this failure.
-mirrors/disable_tree_shaking_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/empty_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/enum_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/equality_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/fake_function_with_call_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/fake_function_without_call_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/field_type_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/function_type_mirror_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_bounded_by_type_parameter_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_bounded_by_type_parameter_test/02: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_bounded_by_type_parameter_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_bounded_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_bounded_test/02: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_bounded_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_class_declaration_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_f_bounded_mixin_application_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_f_bounded_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_f_bounded_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_function_typedef_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_interface_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_interface_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_list_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_local_function_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_mixin_applications_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_mixin_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_superclass_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_superclass_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generic_type_mirror_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generics_double_substitution_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generics_double_substitution_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generics_dynamic_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generics_special_types_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generics_substitution_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generics_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/generics_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/globalized_closures2_test/00: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/globalized_closures2_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/globalized_closures_test/00: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/globalized_closures_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/hierarchy_invariants_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/immutable_collections_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/inherit_field_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/initializing_formals_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/initializing_formals_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/instance_members_easier_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/instance_members_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/instance_members_unimplemented_interface_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/instance_members_with_override_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/instantiate_abstract_class_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/intercepted_cache_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/intercepted_class_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/intercepted_object_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/intercepted_superclass_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invocation_fuzz_test/emptyarray: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invocation_fuzz_test/false: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invocation_fuzz_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invocation_fuzz_test/smi: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invocation_fuzz_test/string: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invoke_call_on_closure_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invoke_call_through_getter_previously_accessed_test/named: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invoke_call_through_getter_previously_accessed_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invoke_call_through_getter_test/named: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invoke_call_through_getter_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invoke_call_through_implicit_getter_previously_accessed_test/named: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invoke_call_through_implicit_getter_previously_accessed_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invoke_call_through_implicit_getter_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invoke_closurization2_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invoke_closurization_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invoke_import_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invoke_named_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invoke_named_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invoke_natives_malicious_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invoke_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/invoke_throws_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/is_odd_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/lazy_static_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/libraries_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/library_declarations_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/library_declarations_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/library_enumeration_deferred_loading_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/library_exports_hidden_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/library_exports_shown_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/library_import_deferred_loading_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/library_imports_bad_metadata_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/library_imports_deferred_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/library_imports_hidden_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/library_imports_metadata_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/library_imports_prefixed_show_hide_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/library_imports_prefixed_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/library_imports_shown_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/library_metadata2_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/library_metadata_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/library_uri_package_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/list_constructor_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/list_constructor_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/load_library_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/local_function_is_static_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/local_isolate_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/metadata_allowed_values_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/metadata_allowed_values_test/05: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/metadata_allowed_values_test/10: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/metadata_allowed_values_test/11: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/metadata_allowed_values_test/13: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/metadata_allowed_values_test/14: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/metadata_allowed_values_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/metadata_class_mirror_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/metadata_constructed_constant_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/metadata_constructor_arguments_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/metadata_nested_constructor_call_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/metadata_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/method_mirror_location_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/method_mirror_name_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/method_mirror_properties_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/method_mirror_returntype_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/method_mirror_source_line_ending_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/method_mirror_source_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/mirror_in_static_init_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/mirrors_nsm_mismatch_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/mirrors_nsm_test/dart2js: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/mirrors_nsm_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/mirrors_reader_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/mirrors_resolve_fields_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/mirrors_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/mixin_application_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/mixin_members_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/mixin_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/native_class_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/new_instance_with_type_arguments_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/no_metadata_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/null2_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/null_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/operator_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/parameter_is_const_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/parameter_metadata_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/parameter_of_mixin_app_constructor_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/private_symbol_mangling_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/private_types_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/proxy_type_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/raw_type_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/raw_type_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/redirecting_factory_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/redirecting_factory_test/02: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/redirecting_factory_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/reflect_class_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/reflect_class_test/02: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/reflect_class_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/reflect_model_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/reflect_runtime_type_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/reflect_uninstantiated_class_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/reflected_type_classes_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/reflected_type_classes_test/02: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/reflected_type_classes_test/03: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/reflected_type_classes_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/reflected_type_function_type_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/reflected_type_special_types_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/reflected_type_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/reflected_type_test/02: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/reflected_type_test/03: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/reflected_type_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/reflected_type_typedefs_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/reflected_type_typevars_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/reflectively_instantiate_uninstantiated_class_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/regress_14304_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/regress_16321_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/regress_16321_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/regress_19731_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/relation_assignable_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/relation_subclass_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/relation_subtype_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/removed_api_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/repeated_private_anon_mixin_app_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/set_field_with_final_inheritance_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/set_field_with_final_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/spawn_function_root_library_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/static_members_easier_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/static_members_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/static_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/superclass2_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/superclass_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/symbol_validation_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/disable_tree_shaking_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/equality_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/field_type_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/generic_bounded_by_type_parameter_test/01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/generic_bounded_by_type_parameter_test/02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/generic_bounded_by_type_parameter_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/generic_bounded_test/01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/generic_bounded_test/02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/generic_bounded_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/generic_class_declaration_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirrors/generic_f_bounded_test/01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/generic_f_bounded_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/generic_list_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/generic_superclass_test/01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/generic_superclass_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/generic_type_mirror_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/generics_double_substitution_test/01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/generics_double_substitution_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/generics_dynamic_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/generics_special_types_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/generics_substitution_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/generics_test/01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/generics_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/globalized_closures2_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/globalized_closures_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/inherit_field_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/initializing_formals_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/instance_members_easier_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirrors/instance_members_unimplemented_interface_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirrors/instance_members_with_override_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirrors/intercepted_cache_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/intercepted_class_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/intercepted_object_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/intercepted_superclass_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/invocation_fuzz_test/emptyarray: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirrors/invocation_fuzz_test/false: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirrors/invocation_fuzz_test/none: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirrors/invocation_fuzz_test/smi: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirrors/invocation_fuzz_test/string: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirrors/invoke_call_through_getter_previously_accessed_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/invoke_call_through_getter_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/invoke_call_through_implicit_getter_previously_accessed_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/invoke_closurization2_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/invoke_closurization_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/invoke_import_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/invoke_named_test/01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/invoke_natives_malicious_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/invoke_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/invoke_throws_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/is_odd_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/lazy_static_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/libraries_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/library_declarations_test/01: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirrors/library_enumeration_deferred_loading_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/library_metadata2_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/library_metadata_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/library_uri_package_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirrors/list_constructor_test/01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/list_constructor_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/local_isolate_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/metadata_allowed_values_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/metadata_class_mirror_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/metadata_constructed_constant_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/metadata_constructor_arguments_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/metadata_nested_constructor_call_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/metadata_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/method_mirror_returntype_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/mirror_in_static_init_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/mirrors_nsm_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/mirrors_resolve_fields_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/mixin_members_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/new_instance_with_type_arguments_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/no_metadata_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/null2_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/null_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/operator_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/parameter_is_const_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/parameter_metadata_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/private_symbol_mangling_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/proxy_type_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/raw_type_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/redirecting_factory_test/01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/reflect_class_test/01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/reflect_class_test/02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/reflect_class_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/reflect_model_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/reflect_runtime_type_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/reflect_uninstantiated_class_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/reflected_type_classes_test/01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/reflected_type_classes_test/02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/reflected_type_classes_test/03: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/reflected_type_classes_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/reflected_type_test/01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/reflected_type_test/02: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/reflected_type_test/03: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/reflected_type_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/reflectively_instantiate_uninstantiated_class_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/regress_14304_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/regress_16321_test/01: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/regress_16321_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/regress_19731_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirrors/relation_subclass_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/removed_api_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/set_field_with_final_inheritance_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/set_field_with_final_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/spawn_function_root_library_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/static_members_easier_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+mirrors/static_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/superclass2_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/superclass_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
mirrors/symbol_validation_test/none: RuntimeError # Please triage this failure.
-mirrors/syntax_error_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/synthetic_accessor_properties_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/to_string_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/top_level_accessors_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/type_argument_is_type_variable_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/type_variable_is_static_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/type_variable_owner_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/type_variable_owner_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/typearguments_mirror_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/typedef_deferred_library_test: RuntimeError # receiver.get$_collection$_nums is not a function
-mirrors/typedef_metadata_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/typedef_reflected_type_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/typedef_reflected_type_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/unnamed_library_test: Crash # (=_EmptyStream<T>;): Unhandled node
-mirrors/variable_is_const_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/syntax_error_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/synthetic_accessor_properties_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/to_string_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/top_level_accessors_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/type_argument_is_type_variable_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/type_variable_owner_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/typearguments_mirror_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/typedef_deferred_library_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/typedef_reflected_type_test/none: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
+mirrors/unnamed_library_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
typed_data/typed_data_list_test: RuntimeError # this.get$length is not a function
diff --git a/tests/lib/mirrors/static_const_field_test.dart b/tests/lib/mirrors/static_const_field_test.dart
new file mode 100644
index 0000000..f6fd959
--- /dev/null
+++ b/tests/lib/mirrors/static_const_field_test.dart
@@ -0,0 +1,18 @@
+// 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.
+
+// Test that static const fields are accessible by reflection.
+// Regression test for http://dartbug.com/23811.
+
+@MirrorsUsed(targets: const [A])
+import "dart:mirrors";
+import "package:expect/expect.dart";
+
+class A {
+ static const ONE = 1;
+}
+
+main() {
+ Expect.equals(1, reflectClass(A).getField(#ONE).reflectee);
+}
diff --git a/tests/standalone/io/stdio_nonblocking_test.dart b/tests/standalone/io/stdio_nonblocking_test.dart
index 0740dbe..05f5fde 100644
--- a/tests/standalone/io/stdio_nonblocking_test.dart
+++ b/tests/standalone/io/stdio_nonblocking_test.dart
@@ -17,12 +17,7 @@
print(result.stdout);
print(result.stderr);
Expect.equals(1, result.exitCode);
- if (Platform.isWindows) {
- Expect.equals('stdout\r\n\r\ntuodts\r\nABCDEFGHIJKLM\r\n', result.stdout);
- Expect.equals('stderr\r\n\r\nrredts\r\nABCDEFGHIJKLM\r\n', result.stderr);
- } else {
- Expect.equals('stdout\n\ntuodts\nABCDEFGHIJKLM\n', result.stdout);
- Expect.equals('stderr\n\nrredts\nABCDEFGHIJKLM\n', result.stderr);
- }
+ Expect.equals('stdout\n\ntuodts\nABCDEFGHIJKLM\n', result.stdout);
+ Expect.equals('stderr\n\nrredts\nABCDEFGHIJKLM\n', result.stderr);
});
}
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 3dd8e64..e095467 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -173,12 +173,11 @@
io/file_test: Crash # (static testWriteFro... cannot handle async/sync*/async* functions
io/file_write_only_test: Crash # (main()async{asyncSt... cannot handle async/sync*/async* functions
io/http_bind_test: Crash # (testBindShared(Stri... cannot handle async/sync*/async* functions
-io/http_parser_test: RuntimeError # receiver.get$_nums is not a function
+io/http_parser_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
io/https_bad_certificate_test: Crash # (main()async{var cli... cannot handle async/sync*/async* functions
io/issue_22636_test: Crash # (test()async{server=... cannot handle async/sync*/async* functions
io/issue_22637_test: Crash # (test()async{server=... cannot handle async/sync*/async* functions
-io/observatory_test: Crash # (=_ByteCallbackSink;): Unhandled node
io/socket_bind_test: Crash # (testListenCloseList... cannot handle async/sync*/async* functions
io/socket_source_address_test: Crash # (Future testConnect(... cannot handle async/sync*/async* functions
-priority_queue_stress_test: RuntimeError # receiver.get$_nums is not a function
-typed_array_test: RuntimeError # receiver.get$_collection$_nums is not a function
+priority_queue_stress_test: RuntimeError # receiver._addHashTableEntry$2 is not a function
+typed_array_test: RuntimeError # receiver._collection$_addHashTableEntry$2 is not a function
diff --git a/tests/utils/utils.status b/tests/utils/utils.status
index d690ff9..c438459 100644
--- a/tests/utils/utils.status
+++ b/tests/utils/utils.status
@@ -31,4 +31,4 @@
[ $compiler == dart2js && $cps_ir ]
dummy_compiler_test: Crash # The null object does not have a getter '_element'.
recursive_import_test: Crash # The null object does not have a getter '_element'.
-source_mirrors_test: Crash # (Future<bool> run(Ur... cannot handle async/sync*/async* functions
+source_mirrors_test: Crash # The null object does not have a getter '_element'.
diff --git a/tools/VERSION b/tools/VERSION
index 3572a33..6cd4df1 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 1
MINOR 12
PATCH 0
-PRERELEASE 2
-PRERELEASE_PATCH 2
+PRERELEASE 3
+PRERELEASE_PATCH 0
diff --git a/tools/bots/bot_utils.py b/tools/bots/bot_utils.py
index 3646724..8262462 100644
--- a/tools/bots/bot_utils.py
+++ b/tools/bots/bot_utils.py
@@ -208,8 +208,7 @@
def dartdocs_dirpath(self, revision):
assert len('%s' % revision) > 0
- return '%s/channels/%s/gen-dartdocs/%s' % (self.bucket,
- self.channel, revision)
+ return '%s/gen-dartdocs/%s' % (self.bucket, revision)
def docs_latestpath(self, revision):
assert len('%s' % revision) > 0
diff --git a/tools/dom/templates/html/dartium/indexed_db_dartium.darttemplate b/tools/dom/templates/html/dartium/indexed_db_dartium.darttemplate
index 0ac7e6f..256a12a 100644
--- a/tools/dom/templates/html/dartium/indexed_db_dartium.darttemplate
+++ b/tools/dom/templates/html/dartium/indexed_db_dartium.darttemplate
@@ -5,6 +5,78 @@
// DO NOT EDIT
// Auto-generated dart:indexed_db library.
+/**
+ * A client-side key-value store with support for indexes.
+ *
+ * Many browsers support IndexedDB—a web standard for
+ * an indexed database.
+ * By storing data on the client in an IndexedDB,
+ * a web app gets some advantages, such as faster performance and persistence.
+ * To find out which browsers support IndexedDB,
+ * refer to [Can I Use?](http://caniuse.com/#feat=indexeddb)
+ *
+ * In IndexedDB, each record is identified by a unique index or key,
+ * making data retrieval speedy.
+ * You can store structured data,
+ * such as images, arrays, and maps using IndexedDB.
+ * The standard does not specify size limits for individual data items
+ * or for the database itself, but browsers may impose storage limits.
+ *
+ * ## Using indexed_db
+ *
+ * The classes in this library provide an interface
+ * to the browser's IndexedDB, if it has one.
+ * To use this library in your code:
+ *
+ * import 'dart:indexed_db';
+ *
+ * A web app can determine if the browser supports
+ * IndexedDB with [IdbFactory.supported]:
+ *
+ * if (IdbFactory.supported)
+ * // Use indexeddb.
+ * else
+ * // Find an alternative.
+ *
+ * Access to the browser's IndexedDB is provided by the app's top-level
+ * [Window] object, which your code can refer to with `window.indexedDB`.
+ * So, for example,
+ * here's how to use window.indexedDB to open a database:
+ *
+ * Future open() {
+ * return window.indexedDB.open('myIndexedDB',
+ * version: 1,
+ * onUpgradeNeeded: _initializeDatabase)
+ * .then(_loadFromDB);
+ * }
+ * void _initializeDatabase(VersionChangeEvent e) {
+ * ...
+ * }
+ * Future _loadFromDB(Database db) {
+ * ...
+ * }
+ *
+ *
+ * All data in an IndexedDB is stored within an [ObjectStore].
+ * To manipulate the database use [Transaction]s.
+ *
+ * ## Other resources
+ *
+ * Other options for client-side data storage include:
+ *
+ * * [Window.localStorage]—a
+ * basic mechanism that stores data as a [Map],
+ * and where both the keys and the values are strings.
+ *
+ * * [dart:web_sql]—a database that can be queried with SQL.
+ *
+ * For a tutorial about using the indexed_db library with Dart,
+ * check out
+ * [Use IndexedDB](http://www.dartlang.org/docs/tutorials/indexeddb/).
+ *
+ * [IndexedDB reference](http://docs.webplatform.org/wiki/apis/indexeddb)
+ * provides wiki-style docs about indexedDB
+ */
library dart.dom.indexed_db;
import 'dart:async';